Replication & backup with Litestream
SQLite is a single file — back it up by copying it. But for production,
you want continuous replication: every WAL frame streamed to object
storage so you can restore to any point in time, with zero downtime.
Litestream does exactly this, and it works
seamlessly with Dulak’s WAL-mode bun:sqlite database.
How it works
Section titled “How it works”Dulak (Bun) → app.sqlite (WAL mode) ↓ Litestream daemon ↓ S3 / R2 / MinIOLitestream runs as a sidecar process alongside Dulak. It tails the WAL file and streams changes to your replica — no app code changes, no downtime, no locks. If the server dies, you restore from the replica and restart.
Install
Section titled “Install”# Linux (amd64)curl -L https://github.com/litestream/litestream/releases/latest/download/litestream-linux-amd64 -o /usr/local/bin/litestreamchmod +x /usr/local/bin/litestreamOr with Homebrew on macOS for local testing:
brew install litestreamConfigure
Section titled “Configure”Create /etc/litestream.yml:
dbs: - path: /opt/dulak/data/app.sqlite replicas: - url: s3://your-bucket/dulak # S3-compatible endpoints work too: Cloudflare R2, MinIO, Backblaze B2 # For R2: s3://your-bucket@dulak-backup.<account-id>.r2.cloudflarestorage.com/dulak # For B2: s3://your-bucket@s3.us-west-000.backblazeb2.com/dulak sync-interval: 1sCredentials go in environment variables, not the config file:
export LITESTREAM_ACCESS_KEY_ID=...export LITESTREAM_SECRET_ACCESS_KEY=...Or put them in /opt/dulak/.env.litestream and source it from the
systemd unit.
Run as a systemd service
Section titled “Run as a systemd service”/etc/systemd/system/litestream.service:
[Unit]Description=Litestream replicationAfter=network.target
[Service]Type=simpleEnvironmentFile=/opt/dulak/.env.litestreamExecStart=/usr/local/bin/litestream replicate -config /etc/litestream.ymlRestart=alwaysRestartSec=3
[Install]WantedBy=multi-user.targetsudo systemctl enable --now litestreamsudo systemctl status litestreamLitestream starts after Dulak and tails the WAL file. If Dulak restarts, Litestream picks up where it left off — no coordination needed.
Run with Docker
Section titled “Run with Docker”If you deploy Dulak with Docker, run Litestream as a sidecar in
docker-compose.yml:
services: app: build: . ports: - "127.0.0.1:4000:4000" env_file: .env volumes: - ./data:/app/data restart: unless-stopped
litestream: image: litestream/litestream:latest command: replicate -config /etc/litestream.yml environment: LITESTREAM_ACCESS_KEY_ID: ${LITESTREAM_ACCESS_KEY_ID} LITESTREAM_SECRET_ACCESS_KEY: ${LITESTREAM_SECRET_ACCESS_KEY} volumes: - ./data:/data:ro # read-only access to the SQLite file - ./litestream.yml:/etc/litestream.yml:ro restart: unless-stopped depends_on: - appUpdate the path in litestream.yml to /data/app.sqlite (the volume
mount path inside the Litestream container).
Restore
Section titled “Restore”If your server dies or the database file corrupts:
# Stop Dulak firstsudo systemctl stop dulak
# Restore from the replicalitestream restore -o /opt/dulak/data/app.sqlite s3://your-bucket/dulak
# Start Dulaksudo systemctl start dulakYou can also restore to a specific point in time:
litestream restore -o /opt/dulak/data/app.sqlite \ -timestamp 2026-08-08T10:30:00Z \ s3://your-bucket/dulakWhat Litestream does NOT do
Section titled “What Litestream does NOT do”Litestream is replication, not high availability. It protects against data loss — not against downtime. If the server dies, you restore to a new server and restart. For zero-downtime failover, you need multiple Dulak instances behind a load balancer with a shared database (Postgres, MySQL) — that is the swap point where SQLite is no longer the right tool.
Litestream is free, open-source, and self-hosted. You pay only for object storage:
- Cloudflare R2: $0.015/GB/month, no egress fees — cheapest option
- AWS S3: $0.023/GB/month + egress
- Backblaze B2: $0.006/GB/month — cheapest storage, egress is free up to 3× storage cost
A Dulak database with 10K users and uploads metadata is likely under 100MB — that is less than $0.01/month on any provider.