litestream Ruby gem. The
Litestream binary runs as a Puma plugin inside the app container and streams the
WAL to S3-compatible object storage in near real time.
What is replicated
Litestream config lives inconfig/litestream.yml. Two databases are replicated:
Deliberately not replicated:
cache (Solid Cache — fully regenerable) and
cable (Solid Cable — transient Action Cable messages). Both would be pure noise.
storage/ is a persisted Kamal volume (voteringsapp_storage:/rails/storage in
production, /volume1/docker/votering:/rails/storage on staging), so Litestream’s
generation/temp files survive container restarts.
Enabling backups (operator, one-time per environment)
Litestream is ENV-gated and inert until a replica bucket is configured — the Puma plugin (config/puma.rb) only loads when LITESTREAM_REPLICA_BUCKET is set,
mirroring the Sentry DSN-gating philosophy. Un-provisioned deploys, dev, and test
are completely unaffected.
To turn backups on, set these secrets in Doppler (project votering) and redeploy:
stg config for staging.
How it is wired
- The Puma plugin (
plugin :litestreaminconfig/puma.rb) runs the Litestream binary inside the app container, once, from the Puma master. config/litestream.ymlis read raw by the Go binary, so it must not use ERB; it relies on Litestream’s own environment expansion (${RAILS_ENV},$LITESTREAM_*).config/initializers/litestream.rbfeeds theLITESTREAM_*variables into the gem’s config.- The secrets reach the container through Kamal’s
env.secretand Doppler (prd/stg)..kamal/secrets*read them with|| echo ""fallbacks, so a deploy succeeds before the bucket is provisioned.
Checking backup status
Automated freshness monitoring
LitestreamVerificationJob runs daily at 04:00 UTC — 06:00 Oslo time in summer,
05:00 in winter; the schedule names UTC, so the app zone does not move it
(config/recurring.yml) — and
calls Litestream.verify! against each replicated database. On failure or
staleness it reports to Sentry (Sentry.capture_exception) and the Rails
log (Rails.logger.error), so a broken/stale backup is observable. The job
no-ops when Litestream isn’t configured.
Restore runbook
Restoring rebuilds a database file from its replica. Do this on the server (the config + credentials live there).-timestamp on the restore command; see
the Litestream restore reference.