This post is a collection of tips and tricks I’ve gathered over the years, while running my own Rails apps on a VPS with Dokku.
I will be avoiding things you can already find in Dokku’s documentation, which I highly recommend reading through if you haven’t already.
This post is a work-in-progress, I will be updating it as I go. It should only serve as a quick reference.
Performance
Enable YJIT
YJIT is a just-in-time compiler by Shopify that can significantly boost your app’s performance.
dokku config:set rails-app RUBYOPT="--enable-yjit"
Use jemalloc
jemalloc is an efficient memory allocator that can greatly reduce your app’s memory usage.
Add the jemalloc buildpack to your .buildpack
file:
https://github.com/gaffneyc/heroku-buildpack-jemalloc.git
https://github.com/heroku/heroku-buildpack-ruby.git
Or set buildpacks via command line:
dokku buildpacks:add rails-app https://github.com/gaffneyc/heroku-buildpack-jemalloc.git
Then enable the environment variable:
dokku config:set app JEMALLOC_ENABLED=true
Reliability
Auto-restore
Automatically start/restore your Dokku containers on reboot to reduce downtime. Using systemd
, we can create a simple service that runs dokku ps:restore
on startup.
Create the systemd service file:
sudo nano /etc/systemd/system/dokku-restore.service
Paste the following into the file:
[Unit]
Description=Restore Dokku Containers at Boot
After=docker.service
Requires=docker.service
[Service]
Type=oneshot
ExecStart=/usr/bin/dokku ps:restore
RemainAfterExit=true
[Install]
WantedBy=multi-user.target
Reload systemd and enable the service:
sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl enable dokku-restore.service
Optionally, start it now to test:
sudo systemctl start dokku-restore.service
This runs dokku ps:restore
once at boot, after Docker is ready.
Cache cleanup
Frequent deployments with Dokku can lead to Docker’s cache becoming full, potentially exhausting system disk space. Schedule a daily Docker build-cache cleanup with cron.
Open crontab:
sudo crontab -e
The first time you run this you may be asked which editor to use. Pick your favorite (nano
is fine).
Insert this single line, then save and exit:
# Purge Docker build cache every day at 04:05 server time
5 4 * * * /usr/bin/docker builder prune -f 2>&1 | /usr/bin/logger -t docker-prune
5 4 * * *
schedules the task to run at minute 5 of hour 4 every day. The output is piped to logger
which writes to journald, and you can view the logs later with journalctl -t docker-prune
.
Verify it’s registered:
sudo crontab -l
You should see the line you just added.
Enable Swap
Deployments can consume significant system resources, particularly RAM, during resource-intensive builds. If the system exhausts its memory, it may hang or crash, potentially bringing down your application.
Swap space is a designated portion of your system’s disk that acts as an extension of RAM. It is particularly beneficial for handling long-running or resource-demanding builds.
Enabling Swap
sudo fallocate -l 2G /swapfile && \
sudo chmod 600 /swapfile && \
sudo mkswap /swapfile && \
sudo swapon /swapfile && \
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
Verify
free -h # swap row ≈ 2.0G
swapon --show # lists /swapfile size 2G
Rollback (just in case)
sudo swapoff /swapfile
sudo rm /swapfile
sudo sed -i '/\/swapfile none swap/d' /etc/fstab
If you’re still timing out, you’re probably CPU-bound. Build in CI and dokku tags:deploy
or upgrade your VPS.
Security
Configure Firewall
Configure your firewall to allow only HTTPS traffic from Cloudflare. See the guide from Hetzner for more details:
https://community.hetzner.com/tutorials/cloudflare-website-protect