Production deployment
Grove is intentionally designed for one application process with local SQLite and filesystem storage.
Deployment shape
public client
|
| HTTPS
v
reverse proxy
|
| private HTTP
v
Grove (one worker) -> persistent /data
Keep the container port on loopback when the reverse proxy runs on the same host. If the proxy runs on another private machine, bind only to the required private interface and enforce the path with a firewall or VPN policy.
Start and update
docker compose build --pull
docker compose up -d
docker compose ps
docker compose logs --tail=100 grove
After changing the source or configuration:
docker compose build --pull
docker compose up -d --force-recreate
Stop the service without deleting its persistent data:
docker compose down
Nginx example
server {
listen 443 ssl http2;
server_name blobs.example.com;
client_max_body_size 100m;
location / {
proxy_pass http://127.0.0.1:8200;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_request_buffering off;
}
}
Set the proxy body limit consistently with GROVE_MAX_BLOB_SIZE. Disabling
request buffering preserves Grove's streaming-upload behavior.
Health and observability
Docker probes GET /health every 30 seconds. External monitoring can use the
same endpoint:
curl --fail https://blobs.example.com/health
The health check confirms that the process answers HTTP. It does not currently perform a write/read probe against SQLite and the blob filesystem.
Backup and recovery
/data is the complete persistent state: SQLite metadata plus blob bytes. The
simplest consistent backup is taken while Grove is stopped:
docker compose stop grove
rsync -a --delete /mnt/bitcoin/blossom/ /backup/grove/
docker compose start grove
Test restoration periodically. A backup of only grove.db or only blobs/ is
incomplete. For uninterrupted production backups, use SQLite's online backup
mechanism and coordinate it with a filesystem snapshot of blob data.
One worker means one worker
Do not add Uvicorn workers or run multiple Grove containers against the same SQLite database and filesystem. Horizontal operation requires a coordinated metadata database and storage adapter that Grove does not yet provide.