This is a demo for Wroclowe.rb featuring a small SerpApi-powered application for tracking keywords and Kamal configuration for simple VPS deployment.
First, create a VPS server on Digital Ocean with the cloud-init configuration from config/cloud-init.sh. Then update config/deploy.yml and create .env with your environment.
To deploy the application with Kamal, run kamal setup:
kamal setupSomething wrong with the accessory? Reboot it:
kamal lock release
kamal accessory boot [ACCESSORY]
kamal deployCheck snapshots are being written in logs and in S3 bucket:
kamal accessory logs litestream
kamal accessory exec litestream generations /rails/storage/production.sqlite3Here's how to restore the database. Start the maintainance mode and stop Litestream before continuing.
kamal accessory exec litestream snapshots /rails/storage/production.sqlite3
kamal app maintenance
kamal accessory stop litestreamNow let's delete the database so we can put the restore:
kamal shell
> rm storage/production.sqlite3*(Or delete the files directly from /var/lib/docker/volumes/serptrail_storage/_data if the app container is not available.)
Restore the db files, restart litestream, and restart the application:
kamal app stop
kamal accessory exec litestream restore /rails/storage/production.sqlite3
kamal accessory start litestream
kamal app boot
kamal app liveTo restore with point-in-time, add -timestamp TIMESTAMP to restore like this:
kamal accessory exec litestream "restore -timestamp 2026-04-13T14:50:24Z /rails/storage/production.sqlite3"If you want to run a copy of the app on a new server with the latest backup, you might need to restore from Litestream before Rails creates an empty database.
kamal server bootstrap
kamal accessory boot litestream
# Update permissions for /rails/storage
kamal server exec "docker run --rm -v serptrail_storage:/rails/storage alpine chown -R 1000:1000 /rails/storage"
kamal accessory exec litestream restore /rails/storage/production.sqlite3
kamal setupSee Kamal audit on each host:
kamal auditSee fail2ban audit:
kamal server exec sudo cat /var/log/fail2ban.log
kamal server exec sudo cat /var/log/auth.logSee system log for a service:
sudo journalctl _SYSTEMD_UNIT=docker.service -n 1000