OpenRun Bakes Litestream Into Its Platform, Making SQLite Replication Ops-Free
OpenRun, a self-hosted GitOps platform, now ships built-in Litestream support: SQLite databases are continuously replicated to S3-compatible storage, with automatic restore on empty volumes. No app changes, no sidecar config, no restore logic.

OpenRun, an open-source, self-hosted GitOps platform for deploying web apps and internal tools on Docker, Podman, or Kubernetes, has added built-in Litestream support. SQLite databases are now continuously replicated to AWS S3 or S3-compatible object storage (Cloudflare R2, MinIO, SeaweedFS), and restore is automatic: when OpenRun detects an empty or recreated app volume, it restores the database from the replica before starting the app. The same setup works on a single node with Docker/Podman and on Kubernetes.
The pitch: application developers use SQLite normally without having to install Litestream, configure object storage, modify their container image, or implement restore logic. That operational burden moves into the platform.
How It Works
Litestream settings are defined once in the OpenRun server configuration. A SQLite service references that config, and apps bind to the service. The app gets a persistent volume mounted at /data and finds its database via injected environment variables (SQLITE_DB_PATH, SQLITE_DIR). Every *.db file the app creates in that directory is replicated, including files created at runtime. Changes typically replicate within about a second by default (sync_interval is configurable).
On Docker and Podman, OpenRun runs Litestream in a per-app companion container that shares the app's data volume. Before the app container starts on an empty volume, restore containers pull any replicated databases back. When the app scales to zero on idle, the Litestream container performs a final sync and stops.
On Kubernetes, the binding's volume becomes a PersistentVolumeClaim, and OpenRun adds a restore init container plus a native Litestream sidecar (Kubernetes 1.29 or newer) to the app pod automatically. The sidecar starts before the app container and is terminated after it, allowing a final sync during orderly shutdown. Apps with a SQLite binding run as a single replica with the Recreate update strategy, preventing multiple app pods from writing to the same SQLite volume during an update.
Recovery Scenarios
For a lost app volume, recovery is automatic: the next start sees the empty volume, runs restore containers, and starts the app against restored data. The replica is keyed by the binding, so attaching the same binding to a new app restores data into that app's fresh volume too.
For a complete node loss, with metadata replication enabled, the recovery procedure is: install OpenRun on a new machine, start the server with the same config file. On startup, the server finds its metadata database missing, restores the metadata and audit databases from the replica, and comes up with all apps, bindings, services, versions, and audit history intact. Each app then redeploys on first request, restoring its SQLite data from its own replica before the container starts.
Replication is asynchronous. With the default one-second sync_interval, a sudden crash can lose roughly the most recent second of writes that haven't reached object storage. The node-loss scenario is exercised end-to-end in CI tests: the test hard-kills the server, deletes containers, volumes, and the OpenRun installation directory, then verifies everything is rebuilt automatically from the object store.
Monitoring
openrun replication status reports the state of every replicated database, combining the replica listing in object storage with the replication container's state, so a failed replication container is visible even when object storage still contains a recent replica. Status is also visible in the Console App.
Application developers use SQLite normally without having to install Litestream, configure object storage, modify their container image, or implement restore logic.
Discussion
0 Comments
Be the first to start the discussion.