English | 中文
Back up your memos SQLite database to S3/B2 with Litestream. A redesigned version of memos-on-fly-build.
For Fly.io deployment, see Fly.io setup below. The Docker image works locally and on Fly.io.
Built on usememos/memos and litestream.
- Docker
- A BackBlaze B2 or S3-compatible account
- Create a bucket and note the bucket-name and endpoint-url
- Create an app key and get the access-key-id and secret-access-key
- (Optional) A Telegram Bot Token if using Memogram. See usememos/telegram-integration.
This image ships Litestream v0.5.15 (upgraded from v0.3.x). The upgrade is transparent:
- v0.3.x backups are still restorable. Litestream v0.5.8+ can restore databases created by v0.3.x without any migration step.
- Environment variables updated. This image now uses the standard
AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEYnames. The oldLITESTREAM_ACCESS_KEY_ID/LITESTREAM_SECRET_ACCESS_KEYare still supported as fallbacks but no longer documented. - Snapshot by default. The config now creates a snapshot every 24 hours and keeps them for 7 days. This speeds up recovery for long-running databases.
- The config format changed. If you maintain your own
litestream.yml, the oldreplicasarray format is still parsed but the newreplicasingle-object format is recommended. See the upstream migration guide for details.
If you're upgrading from an older version of this image, your existing S3 backups require no conversion. Just pull the new image and restart.
The image supports linux/amd64 and linux/arm64.
Tags:
stable,stable-memogram.stabletracks the latest memos release.stable-memogramadds the Telegram bot integration.
Available feature combinations:
| Scheme | Memos | Litestream | Memogram |
|---|---|---|---|
| 1 | ✓ | ✓ | ✕ |
| 2 | ✓ | ✓ | ✓ |
| 3 | ✓ | ✕ | ✓ |
| 4 | ✓ | ✕ | ✕ |
docker run -d \
--name memos \
-p 5230:5230 \
-v ~/.memos/:/var/opt/memos \
-e LITESTREAM_REPLICA_PATH=memos_prod.db \
-e LITESTREAM_REPLICA_BUCKET=your-bucket-name \
-e LITESTREAM_REPLICA_ENDPOINT=s3.us-west-000.backblazeb2.com \
-e AWS_ACCESS_KEY_ID=000000001a2b3c40000000001 \
-e AWS_SECRET_ACCESS_KEY=K000ABCDEFGHiJkLmNoPqRsTuVwXyZ0 \
ghcr.io/hu3rror/memos-litestream:stabledocker run -d \
--name memos \
-p 5230:5230 \
-v ~/.memos/:/var/opt/memos \
-e LITESTREAM_REPLICA_PATH=memos_prod.db \
-e LITESTREAM_REPLICA_BUCKET=your-bucket-name \
-e LITESTREAM_REPLICA_ENDPOINT=s3.us-west-000.backblazeb2.com \
-e AWS_ACCESS_KEY_ID=000000001a2b3c40000000001 \
-e AWS_SECRET_ACCESS_KEY=K000ABCDEFGHiJkLmNoPqRsTuVwXyZ0 \
-e BOT_TOKEN=your-bot-token \
ghcr.io/hu3rror/memos-litestream:stable-memogramdocker run -d \
--name memos \
-p 5230:5230 \
-v ~/.memos/:/var/opt/memos \
-e BOT_TOKEN=your-bot-token \
ghcr.io/hu3rror/memos-litestream:stable-memogramdocker run -d \
--name memos \
-p 5230:5230 \
-v ~/.memos/:/var/opt/memos \
ghcr.io/hu3rror/memos-litestream:stableOr use the official image neosmemo/memos:stable.
| Variable | Required | Default | Description |
|---|---|---|---|
LITESTREAM_REPLICA_BUCKET |
For Litestream | — | S3/B2 bucket name |
LITESTREAM_REPLICA_ENDPOINT |
For Litestream | — | S3/B2 endpoint URL |
AWS_ACCESS_KEY_ID |
For Litestream | — | S3/B2 access key ID |
AWS_SECRET_ACCESS_KEY |
For Litestream | — | S3/B2 access key secret |
LITESTREAM_REPLICA_PATH |
No | memos_prod.db |
Database file name in the bucket |
BOT_TOKEN |
For Memogram | — | Telegram bot token. Only for stable-memogram image |
MEMOS_TOKEN |
For Memogram | — | Memos API token. If not set, Memogram tries the first admin user's token |
TG_ID |
For Memogram | — | Telegram user ID allowed to use the bot |
ALLOWED_USERNAMES |
No | — | Comma-separated Telegram usernames allowed to use the bot. Omit or leave empty to allow all users. Usernames without @ |
See litestream.io for more about Litestream configuration.
Data lives in ~/.memos by default. Mount it as a volume to keep data across restarts.
Automatic restore:
- If no local database (
memos_prod.db) exists at startup, the entrypoint attempts to restore from S3/B2. - If a local database exists, the restore is skipped. This prevents accidental overwrites.
- To force a restore from S3/B2, delete the local database file before starting the container. This will overwrite your local data. Back up first.
Note: This project does not back up local resource files (e.g., photos). Use memos' built-in external storage instead.
All processes run in one container via the entrypoint script. Same as local Docker. fly deploy works normally.
# 1. Create the app
fly launch --no-deploy --region ord
# 2. Set Litestream credentials
fly secrets set \
LITESTREAM_REPLICA_BUCKET=your-bucket \
LITESTREAM_REPLICA_ENDPOINT=s3.us-west-000.backblazeb2.com \
AWS_ACCESS_KEY_ID=your-key-id \
AWS_SECRET_ACCESS_KEY=your-secret-key \
LITESTREAM_REPLICA_PATH=memos_prod.db
# 3. Optional: Telegram bot
fly secrets set BOT_TOKEN=your-bot-token
# 4. Deploy (with Telegram bot support)
fly deploy --build-arg USE_MEMOGRAM=1The entrypoint handles database restore, memos startup, and memogram (if BOT_TOKEN is set).
Note: The default
stableimage does not include memogram. Pass--build-arg USE_MEMOGRAM=1tofly deploy, or set[build.args]infly.tomlto make it permanent.
Note: Memogram needs the Machine to stay awake. The
fly.tomlthatfly launchgenerates setsauto_stop_machines = 'stop', so an idle Machine stops and the bot stops answering. Change it toauto_stop_machines = 'off'under[http_service]before deploying.
Memos, litestream, and memogram each run in their own container, sharing the same Machine. Uses cli-config.json.
# 1. Create the app
fly launch --no-deploy --region ord --dockerfile ./Dockerfile
# 2. Set secrets (same as Approach A)
fly secrets set \
LITESTREAM_REPLICA_BUCKET=your-bucket \
LITESTREAM_REPLICA_ENDPOINT=s3.us-west-000.backblazeb2.com \
AWS_ACCESS_KEY_ID=your-key-id \
AWS_SECRET_ACCESS_KEY=your-secret-key \
LITESTREAM_REPLICA_PATH=memos_prod.db
# 3. Optional: Telegram bot
fly secrets set BOT_TOKEN=your-bot-token
# 4. Deploy with multi-container config
fly machine run --machine-config cli-config.json \
--port 5230:5230/tcp:httpNote: fly deploy is not used here. fly machine run creates a Machine with 3 containers. To update the image later, use fly machine update for each container or rebuild and re-run fly machine run.
| Approach A | Approach B | |
|---|---|---|
| Complexity | Low | Higher |
fly deploy works |
✅ | ❌ (use fly machine run) |
| Memos + Litestream | ✅ | ✅ |
| Memogram | ✅ | ✅ |
| Independent updates | ❌ | ✅ (each container can be updated separately) |
| Recommended for | All users | Users who want to isolate litestream/memogram processes |
fly.toml— app and service config (works with Approach A)cli-config.json— multi-container definitions (for Approach B)
git clone https://github.com/hu3rror/memos-litestream.git
cd memos-litestream
docker buildx build ./ --file ./Dockerfile --tag your-tagTo build with Memogram support:
docker buildx build ./ --file ./Dockerfile --build-arg USE_MEMOGRAM=1 --tag your-tag:memogramThe container runs a single entrypoint script (entrypoint.sh) that handles:
- Database restore — if Litestream (v0.5.15) is configured and no local database exists, restores from S3/B2
- Memogram startup — if
BOT_TOKENis set, starts Memogram in the background once the memos port is ready - Memos launch — runs memos through Litestream replication (if configured) or directly
No process manager (supervisor) is needed. The entrypoint uses exec to hand off to Litestream or memos directly.
Fly.io's Depot builder sometimes fails to start, especially during peak hours. Try:
# Skip Depot, use legacy remote builder
fly deploy --depot=false
# Or build locally and upload
fly deploy --local-onlyIf the problem persists, reset the builder in your Fly.io organization dashboard: Settings → App Builders → Reset. Or switch to a different builder region.
See Fly.io troubleshooting docs for more.
The version tag format is wrong. Run fly deploy without custom tags, or check the build-and-push.yml if using GitHub Actions.
If you're upgrading the Litestream binary inside this image from v0.3.x to v0.5.x, here's what changed and what you need to know:
| Change | v0.3.x | v0.5.x | Impact |
|---|---|---|---|
| SQLite driver | mattn/go-sqlite3 (cgo) | modernc.org/sqlite (no cgo) | No action needed — the binary is self-contained |
| Cloud SDK | AWS SDK v1, Azure SDK v1 | AWS SDK v2, Azure SDK v2 | Transparent, no config change |
| Config format | replicas: [...] array |
replica: single object |
Old format still works, new format recommended |
| Snapshot config | Not available | snapshot.interval + snapshot.retention |
Added automatically in this image |
| Command rename | litestream wal |
litestream ltx |
Only affects manual CLI usage, not the entrypoint |
| Age encryption | Supported | Removed | Not used by this project |
| v0.3.x restore | — | Supported (v0.5.8+) | Your existing backups are recoverable |
Litestream v0.5.x uses the standard AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY. The old LITESTREAM_ACCESS_KEY_ID / LITESTREAM_SECRET_ACCESS_KEY are still supported as fallbacks but no longer documented.
In etc/litestream.yml, the old format:
dbs:
- path: $DB_PATH
replicas:
- type: s3
bucket: $LITESTREAM_REPLICA_BUCKET
path: $LITESTREAM_REPLICA_PATH
endpoint: $LITESTREAM_REPLICA_ENDPOINT
force-path-style: trueHas been replaced with:
snapshot:
interval: 24h
retention: 168h
dbs:
- path: $DB_PATH
replica:
url: s3://$LITESTREAM_REPLICA_BUCKET/$LITESTREAM_REPLICA_PATH
endpoint: $LITESTREAM_REPLICA_ENDPOINT
force-path-style: trueThe snapshot section creates a compact snapshot every 24 hours and keeps them for 7 days. This avoids replaying months of WAL to restore a database — the latest snapshot is used instead.
- Pull the latest image:
docker pull ghcr.io/hu3rror/memos-litestream:stable - Stop your container:
docker stop memos && docker rm memos - Start it again with the same volume and env vars
That's it. Litestream v0.5.x will read your existing S3 backups in the old format and continue replicating normally.
⚠️ Basic maintenance only, as-is.
- This project is provided as-is with minimal maintenance. Use at your own risk.
- If the upstream memos project undergoes major changes, I will not push compatibility updates.
- You are responsible for your own data safety and backups.
- If you need the latest memos features or long-term support, migrate back to the official image.
If you no longer need Litestream or Memogram, switch to the official image (ghcr.io/usememos/memos).
- Stop and remove the container:
docker stop memos && docker rm memos - Back up your data:
cp -r ~/.memos ~/.memos_backup
- Run the official image:
docker run -d \ --name memos \ --restart unless-stopped \ -p 5230:5230 \ -v ~/.memos:/var/opt/memos \ ghcr.io/usememos/memos:latest - Open
http://localhost:5230to verify your data.
Note: The official image does not include Memogram. If you rely on the Telegram bot, host it separately.