How to Deploy Litestream Using Docker Compose Behind Caddy
Litestream is a powerful, standalone streaming replication tool for SQLite. Learn how to deploy it alongside your web applications using Docker Compose and a Caddy reverse proxy.

Litestream is a standalone streaming replication tool for SQLite. It runs as a background process and continuously streams changes from your SQLite databases to external storage like AWS S3, Cloudflare R2, or MinIO. It provides robust disaster recovery for single-node architectures without the overhead of a traditional database server.
Welcome back to another infrastructure guide! As single-node deployments and SQLite gain immense popularity, ensuring your data is safely backed up is more critical than ever.
Today, I will walk you through deploying a web application backed by SQLite, replicated by Litestream, and served securely behind a Caddy reverse proxy—all orchestrated with Docker Compose.
Prerequisites
Ensure you fulfill the following requirements before proceeding with the deployment:
- Ubuntu Server (or your preferred Linux distribution).
- Docker and Docker Compose installed on your server.
- An S3-compatible storage bucket (AWS S3, DigitalOcean Spaces, Cloudflare R2, etc.) and its associated access keys.
Introduction to Litestream
Litestream bridges the gap between the simplicity of SQLite and the durability of traditional client-server databases like PostgreSQL. By operating at the WAL (Write-Ahead Log) level, it replicates database changes in real-time.
While Litestream itself doesn’t serve HTTP traffic, it runs directly alongside your web application. Caddy acts as the front door, terminating SSL and routing traffic to your app, while Litestream works invisibly in the background to ensure your application’s SQLite database is never lost.
Litestream Core Features
Continuous Streaming
- Replicates SQLite WAL frames to your storage bucket every second, ensuring near-zero data loss.
Point-in-Time Restore
- Allows you to restore your database to any specific second in the past, protecting against accidental deletions or bad migrations.
Extremely Low Overhead
- Consumes minimal CPU and memory, making it perfect for running on small VPS instances.
S3 Compatibility
- Natively supports AWS S3, Google Cloud Storage, Azure Blob Storage, SFTP, and any S3-compatible API like MinIO or Cloudflare R2.
Prepare the Server Environment
Create a dedicated directory under /opt on your host to persist your application data and configurations:
cd /opt
sudo mkdir -p myapp/data
cd myapp
Litestream Configuration
Litestream requires a simple YAML file to map your local database to its remote storage destination.
Save the following configuration inside /opt/myapp/litestream.yml:
dbs:
- path: /data/database.sqlite
replicas:
- url: s3://[my-litestream-bucket.us-east-1.amazonaws.com/myapp-db](https://my-litestream-bucket.us-east-1.amazonaws.com/myapp-db)
access_key_id: ${LITESTREAM_ACCESS_KEY_ID}
secret_access_key: ${LITESTREAM_SECRET_ACCESS_KEY}
${...}) for the credentials. This ensures your secrets stay out of your configuration files and are passed securely via Docker Compose.Caddy Configuration (Caddyfile)
Create your Caddyfile inside /opt/myapp:
sudo touch Caddyfile
sudo nano Caddyfile
Paste the configuration below:
{
email your-email@example.com
cert_issuer acme
servers {
protocol h1 h2c h3
strict_sni_host on
}
}
app.example.com {
log {
output file /var/log/caddy/app.log
format console
}
# Route traffic to your actual web application
reverse_proxy app:8080 {
transport http {
keepalive 300s
}
}
}
Docker Compose Configuration
To run Litestream effectively in Docker, the “sidecar” pattern is highly recommended. The application and Litestream run as separate containers but share a Docker volume containing the SQLite database.
Create /opt/myapp/docker-compose.yml:
sudo touch docker-compose.yml
sudo nano docker-compose.yml
Add the following stack definition:
networks:
caddy_net:
driver: bridge
volumes:
caddy_data:
caddy_config:
app_data: # Shared volume for the SQLite database
services:
caddy:
image: rajaseg/caddy:latest
container_name: caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
networks:
- caddy_net
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
# Your Web Application
app:
image: your-web-app-image:latest # Replace with your actual app image
container_name: app
restart: unless-stopped
networks:
- caddy_net
volumes:
- app_data:/data # Mounts the shared volume to /data
environment:
- DATABASE_URL=sqlite:///data/database.sqlite
# Litestream Sidecar
litestream:
image: litestream/litestream:latest
container_name: litestream
restart: unless-stopped
depends_on:
- app
volumes:
- ./litestream.yml:/etc/litestream.yml:ro
- app_data:/data # Shares the EXACT same volume as the app
environment:
- LITESTREAM_ACCESS_KEY_ID=your_aws_or_r2_access_key
- LITESTREAM_SECRET_ACCESS_KEY=your_aws_or_r2_secret_key
command: replicate -config /etc/litestream.yml
Key configuration details used:
- Shared Volume (
app_data): Both theappandlitestreamcontainers mount the exact same volume. This allows Litestream to read the SQLite WAL files generated by your application in real-time. - Sidecar Pattern: By keeping Litestream in its own container, you don’t need to modify your application’s Dockerfile or use complex startup scripts.
Deploy the Stack
With your configuration files in place, deploy the stack in detached mode:
docker compose up -d
Litestream will automatically detect the database.sqlite file created by your application in the shared app_data volume and immediately begin replicating the WAL frames to your S3 bucket.
Restoring Your Database
If disaster strikes and you need to restore your database, you can use the Litestream container to pull the latest state from your bucket before starting your application.
Run these commands to safely restore the database from S3 into your shared Docker volume:
# 1. Stop the application container to prevent database locks
docker compose stop app
# 2. Run the restore command via the Litestream container
docker compose run --rm litestream restore -v -config /etc/litestream.yml /data/database.sqlite
# 3. Restart the application
docker compose start app
Conclusion
By running Litestream as a sidecar to your main application container, you decouple your disaster recovery process from your application logic. Caddy handles the secure routing, your app serves the business logic, and Litestream quietly ensures your SQLite data is immortalized in the cloud.
Feel free to leave a comment below if you have any questions or encounter issues setting this up.
Continue reading

How to Self-Host Maddy Mail Server Using Docker Compose Behind Caddy
Maddy is a modern, all-in-one open-source mail server written in Go. Learn how to deploy Maddy with Docker Compose, leverage Caddy for automatic SSL certificates, and configure DKIM, SPF, and DMARC.

How to Deploy Authelia Using Docker Compose Behind Caddy
Authelia is an open-source authentication and authorization server providing two-factor authentication and single sign-on (SSO) for applications via a web portal.

How to Self-Host Stalwart Mail Server Using Docker Compose Behind Caddy v2.8.4
Stalwart is an open-source mail server solution with JMAP, IMAP4, POP3 & SMTP support. It is written in Rust and aims to be secure, fast, robust, and scalable.