Introduction

SQLite is the most deployed database engine in the world — it runs on every smartphone, inside web browsers, and in countless embedded devices. But deploying SQLite as a server-accessible database has historically required workarounds. A new generation of open-source tools has emerged to bridge this gap, adding replication, network access, continuous backup, and web-based management to SQLite’s rock-solid core.

This guide compares four leading open-source tools for self-hosting SQLite: rqlite (distributed SQLite with Raft consensus), LiteStream (continuous SQLite replication to S3), mvsqlite (SQLite on FoundationDB for distributed deployments), and sqlite-web (web-based SQLite management).

Comparison Table

FeaturerqliteLiteStreammvsqlitesqlite-web
Primary PurposeDistributed SQLite clusterContinuous backup & point-in-time recoveryDistributed SQLite on FoundationDBWeb UI for SQLite management
ReplicationRaft consensus (strongly consistent)S3-compatible object storageFoundationDB (distributed KV)None (single-node)
Network AccessHTTP API (REST + JSON)None (file-level replication)FUSE filesystemHTTP UI
ConsistencyStrong (Raft linearizability)Eventually consistentStrong (FoundationDB)N/A (single writer)
GitHub Stars~16,000~12,000~1,800~2,200
LanguageGoGoRustPython
Docker SupportOfficial imageOfficial imageSource buildDockerfile provided
LicenseMITApache 2.0MITMIT

rqlite: Distributed SQLite with Raft

rqlite combines SQLite with the Raft consensus algorithm to create a strongly consistent, fault-tolerant SQL database cluster. Every write goes through the Raft leader, which replicates to followers before committing:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# Start a 3-node rqlite cluster
# Node 1 (bootstrap)
docker run -d --name rqlite1 -p 4001:4001 -p 4002:4002 \
  rqlite/rqlite -http-addr=0.0.0.0:4001 -raft-addr=0.0.0.0:4002 data

# Nodes 2 and 3 (join)
docker run -d --name rqlite2 -p 4011:4001 -p 4012:4002 \
  rqlite/rqlite -http-addr=0.0.0.0:4001 -raft-addr=0.0.0.0:4002 \
  -join=http://node1:4001 data

docker run -d --name rqlite3 -p 4021:4001 -p 4022:4002 \
  rqlite/rqlite -http-addr=0.0.0.0:4001 -raft-addr=0.0.0.0:4002 \
  -join=http://node1:4001 data

rqlite exposes a full HTTP API, making it accessible from any language:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Create a table
curl -X POST http://localhost:4001/db/execute \
  -H "Content-Type: application/json" \
  -d '["CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)"]'

# Insert data
curl -X POST http://localhost:4001/db/execute \
  -H "Content-Type: application/json" \
  -d '[["INSERT INTO users(name, email) VALUES(?, ?)", "Alice", "alice@example.com"]]'

# Query
curl -X POST http://localhost:4001/db/query \
  -H "Content-Type: application/json" \
  -d '["SELECT * FROM users"]'

rqlite Docker Compose Cluster

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
version: '3.8'
services:
  rqlite1:
    image: rqlite/rqlite:latest
    ports:
      - "4001:4001"
      - "4002:4002"
    volumes:
      - rqlite1_data:/rqlite/file
    command: -http-addr=0.0.0.0:4001 -raft-addr=rqlite1:4002 -bootstrap-expect=3 -join=http://rqlite1:4002,http://rqlite2:4002,http://rqlite3:4002 /rqlite/file

  rqlite2:
    image: rqlite/rqlite:latest
    ports:
      - "4011:4001"
      - "4012:4002"
    volumes:
      - rqlite2_data:/rqlite/file
    command: -http-addr=0.0.0.0:4001 -raft-addr=rqlite2:4002 -bootstrap-expect=3 -join=http://rqlite1:4002,http://rqlite2:4002,http://rqlite3:4002 /rqlite/file

  rqlite3:
    image: rqlite/rqlite:latest
    ports:
      - "4021:4001"
      - "4022:4002"
    volumes:
      - rqlite3_data:/rqlite/file
    command: -http-addr=0.0.0.0:4001 -raft-addr=rqlite3:4002 -bootstrap-expect=3 -join=http://rqlite1:4002,http://rqlite2:4002,http://rqlite3:4002 /rqlite/file

volumes:
  rqlite1_data:
  rqlite2_data:
  rqlite3_data:

LiteStream: Continuous SQLite Backup

LiteStream takes a fundamentally different approach — instead of adding replication to SQLite, it continuously streams SQLite’s write-ahead log (WAL) to S3-compatible object storage. This provides point-in-time recovery and enables read replicas:

1
2
3
4
5
6
7
8
9
# Start LiteStream replication to S3
litestream replicate /data/app.db s3://mybucket/app.db \
  -access-key-id=AKIAIO...MPLE \
  -secret-access-key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

# Restore from point-in-time
litestream restore -o /data/restored.db \
  -timestamp "2026-06-17T10:30:00Z" \
  s3://mybucket/app.db

LiteStream Docker Compose with MinIO

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
version: '3.8'
services:
  app:
    image: myapp:latest
    volumes:
      - app_data:/data
    environment:
      - DB_PATH=/data/app.db

  litestream:
    image: litestream/litestream:latest
    volumes:
      - app_data:/data
      - ./litestream.yml:/etc/litestream.yml
    command: replicate

  minio:
    image: minio/minio:latest
    ports:
      - "9000:9000"
    environment:
      MINIO_ROOT_USER: minioadmin
      MINIO_ROOT_PASSWORD: minioadmin
    command: server /data
    volumes:
      - minio_data:/data

volumes:
  app_data:
  minio_data:

LiteStream excels in single-server deployments where you need disaster recovery without the operational complexity of a multi-node cluster. It integrates naturally with GitHub Actions for automated database restoration in CI/CD pipelines.

mvsqlite: FoundationDB-Backed SQLite

mvsqlite is a Rust project that runs SQLite on top of FoundationDB, giving you distributed SQL with the full SQLite API. It implements the SQLite VFS (Virtual File System) layer to redirect all I/O to FoundationDB’s distributed key-value store:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# Deploy mvsqlite with FoundationDB
docker run -d --name fdb \
  foundationdb/foundationdb:latest

# Build and run mvsqlite
git clone https://github.com/losfair/mvsqlite
cd mvsqlite
cargo build --release

# Mount mvsqlite FUSE filesystem
./target/release/mvsqlite-mount \
  --data-dir=/mnt/mvsqlite \
  --mount-point=/mnt/sqlite \
  --fdb-cluster-file=/etc/foundationdb/fdb.cluster

# Use SQLite normally — data goes to FoundationDB
sqlite3 /mnt/sqlite/mydb.db

This architecture provides strong consistency through FoundationDB while maintaining full SQLite compatibility — any application that uses SQLite can be “upgraded” to a distributed deployment by simply pointing it at the mvsqlite mount point.

sqlite-web: Web-Based Management

sqlite-web provides a browser-based interface for managing SQLite databases, useful for development, debugging, and lightweight administration:

1
2
3
4
# Launch sqlite-web
docker run -d --name sqlite-web -p 8080:8080 \
  -v /path/to/databases:/data \
  coleifer/sqlite-web /data/mydb.db

The web UI supports browsing tables, running ad-hoc queries, importing/exporting CSV and JSON, and visualizing schema relationships. While not a production server, it’s invaluable for development workflows and administrative access to SQLite databases running inside containers.

Choosing the Right SQLite Server Tool

  • Choose rqlite when you need a distributed SQL database with strong consistency, HTTP API access, and automatic leader election. Best for microservices that need a lightweight, SQL-compatible database with built-in high availability.

  • Choose LiteStream for single-server deployments where disaster recovery is critical. It’s the simplest option — no cluster to manage, just continuous backup to any S3-compatible store. Best for applications already using SQLite that need point-in-time recovery.

  • Choose mvsqlite when you need to scale SQLite across multiple nodes and already run FoundationDB. The FUSE-based approach means zero application changes for existing SQLite codebases. Best for organizations with FoundationDB infrastructure looking to add SQL capabilities.

  • Choose sqlite-web for development workflows, debugging, and light administrative access to SQLite databases. Not a production data layer, but an excellent companion tool for any SQLite deployment.

Why Self-Host SQLite-Based Systems

SQLite’s reliability is legendary — it’s one of the most thoroughly tested software libraries in existence, with over 600 times more test code than implementation code. By self-hosting SQLite-based server solutions, you get this battle-tested reliability combined with modern distributed systems patterns.

For teams that already use SQLite in development (Django’s default database, Rails’ default for testing), keeping the same SQL dialect in production eliminates the “works on my machine” problems that arise from development/production database mismatches. For related self-hosted database options, see our guide on version-controlled databases and our comparison of self-hosted database monitoring tools.

The resource efficiency is dramatic — a three-node rqlite cluster can run comfortably on 2GB RAM total, and LiteStream adds near-zero runtime overhead to any existing SQLite application. For edge deployments, IoT gateways, and single-server applications, this efficiency translates directly to lower infrastructure costs.

FAQ

Can rqlite handle concurrent writes from multiple clients?

Yes and no. rqlite uses Raft consensus, which serializes all writes through the leader. Multiple clients can submit writes concurrently via the HTTP API, but they are applied sequentially. Read requests can be served by any node. This is similar to etcd or Consul’s consistency model — ideal for configuration, metadata, and moderate-throughput workloads, but not for write-heavy OLTP.

What happens to LiteStream if my S3 bucket is unreachable?

LiteStream buffers WAL frames in memory during S3 outages and resumes replication when connectivity is restored. The buffer size is configurable. If the buffer fills up before S3 recovers, LiteStream will block writes to prevent data loss — this is a safety feature, not a bug. For production deployments, set up S3 replication to a secondary region and configure LiteStream with appropriate retry and timeout settings.

Do I need to change my application code to use mvsqlite?

No — mvsqlite uses the FUSE (Filesystem in Userspace) interface, which means SQLite sees it as a normal filesystem. Your application opens a database file path as usual, and mvsqlite transparently routes all reads and writes to FoundationDB. This is the key architectural advantage of the VFS approach.

How does sqlite-web handle concurrent access?

sqlite-web is designed for single-user administrative access. It does not handle concurrent write conflicts, as SQLite itself serializes writes at the file level. For multi-user scenarios, consider deploying rqlite with built-in concurrency control, or use SQLite in WAL mode which allows concurrent reads while a write is in progress.

What are the backup strategies for rqlite?

rqlite supports automatic backup to SQLite dump files or to S3-compatible storage. You can also take snapshots of any node’s data directory. Since each node maintains a full copy of the database, you can restore from any node. rqlite also supports automatic restore from S3 on cluster bootstrap, making it ideal for immutable infrastructure patterns.


💰 想测试你的市场判断力?我用 Polymarket 做预测市场交易——这是全球最大的预测市场平台,从大选结果到技术监管时间线,什么都可以押注。和赌博不同,这是真正的信息市场:你懂的信息越多,胜率越高。我靠预测技术相关事件的走向已经赚了不少。用我的邀请链接注册:Polymarket.com