Configure SQLite
SQLite is the default database and the best fit for most Jiandu installations. It runs inside the Jiandu process, needs no database credential or network service, and is configured for WAL mode, foreign keys, full synchronous writes, and a bounded writer wait.
Use the default layout
Set one durable data directory and let Jiandu place the database, local blobs, and owner token below it:
{
"schema_version": 1,
"data_directory": "/var/lib/jiandu",
"database": {
"backend": "sqlite",
"max_connections": 4,
"busy_timeout_milliseconds": 5000
}
}
With this configuration the database is /var/lib/jiandu/jiandu.sqlite3. The explicit tuning
values equal the defaults and are shown so their intent is visible:
max_connections: 4bounds concurrent database handles; andbusy_timeout_milliseconds: 5000lets a writer wait briefly for another short write transaction instead of failing immediately.
Create the state directory for the service account:
sudo install -d -o jiandu -g jiandu -m 0700 /var/lib/jiandu
sudo -u jiandu jiandu --config /etc/jiandu/jiandu.json --check-config
Jiandu creates an absent database file and hardens it to mode 0600. The parent must be a real
directory that other users cannot modify. Do not make the file or its parent a symlink.
Put the database on a separate local disk
Use database.path only when the SQLite database belongs on a different persistent local
filesystem:
{
"schema_version": 1,
"data_directory": "/var/lib/jiandu",
"database": {
"backend": "sqlite",
"path": "/srv/jiandu-database/jiandu.sqlite3",
"max_connections": 4,
"busy_timeout_milliseconds": 5000
}
}
The path must include a parent directory. Keep it distinct from the blob root, storage work root, owner token, and every configured secret file.
Environment equivalents are:
export JIANDU_DATABASE_BACKEND=sqlite
export JIANDU_DATABASE_PATH=/srv/jiandu-database/jiandu.sqlite3
export JIANDU_DATABASE_MAX_CONNECTIONS=4
export JIANDU_DATABASE_BUSY_TIMEOUT_MS=5000
--data-dir /new/root is preferable when moving all local installation state together: it derives
the SQLite path, default blob path, and owner-token path from one command-line override. A specific
JIANDU_DATABASE_PATH is used only when --data-dir is absent.
:::warning Local filesystems only Do not place the database on NFS, SMB/CIFS, WebDAV mounts, cloud-sync folders, distributed filesystems, or a container's ephemeral writable layer. WAL locking, durability, identity, and atomic filesystem behavior must be provided by a durable local filesystem. :::
Understand WAL sidecars
While Jiandu runs, SQLite may maintain jiandu.sqlite3-wal and jiandu.sqlite3-shm beside the main
file. They are part of the live database state, not temporary clutter. Never:
- delete or exclude sidecars while the process is running;
- copy only
jiandu.sqlite3as a backup; - run a cleanup task against files matching
*.sqlite3-*; or - replace the database file behind a live process.
Jiandu's backup command takes a consistent database snapshot and inventories the corresponding blobs. Use it instead of filesystem copying. If a filesystem snapshot is part of your platform strategy, still treat the supported Jiandu backup and restore drill as the recovery contract.
Tune only for a measured problem
SQLite permits max_connections from 1 through 16 and a busy timeout from 1 through 60,000 ms.
The defaults are intentionally conservative.
Increasing max_connections does not create multiple SQLite writers or make multiple Jiandu
processes safe. It can increase concurrent readers, but it also creates more opportunities to hold a
snapshot while write-heavy document processing proceeds. Change it only after measuring pool waits
and transaction latency.
The busy timeout covers lock contention; it is not a general query timeout. A larger value can hide an unexpected long transaction by making requests wait longer. If ordinary household use exhausts five seconds, inspect workload and storage latency before increasing it.
Container configuration
Mount the whole data directory as persistent storage:
services:
jiandu:
environment:
JIANDU_DATA_DIR: /app/jiandu-data
JIANDU_DATABASE_BACKEND: sqlite
volumes:
- jiandu-data:/app/jiandu-data
volumes:
jiandu-data:
A deployment rollout must stop the old container before the new one takes ownership. A shared volume and PostgreSQL-like rolling update strategy do not make concurrent SQLite access a supported Jiandu topology.
Validate and prove recovery
sudo -u jiandu jiandu --config /etc/jiandu/jiandu.json --check-config
curl --fail --silent https://documents.example.net/api/v1/health/ready
The configuration check validates the selected path; readiness runs a bounded database check after startup. Then create a recovery archive with Jiandu's SQLite backup workflow, copy it to another medium, verify the copy, and restore it into a new destination.
Common SQLite failures
| Symptom | Likely cause |
|---|---|
| Permission denied at startup | Parent ownership/mode, read-only mount, or service UID mismatch |
| Unsafe path error | Symlink, group/world-writable parent, missing parent component, or path collision |
| Database is locked during normal use | External SQLite client, another Jiandu process, slow filesystem, or unexpectedly long transaction |
| Database is gone after container replacement | Path was not backed by a named volume or durable bind mount |
| Copied database will not restore cleanly | A live main file was copied without a consistent WAL snapshot |
If the operational requirements have genuinely outgrown embedded storage, provision a fresh PostgreSQL installation before importing data. Existing SQLite installations cannot be converted in place.