Every POS device also keeps a full copy of its shop’s sales, so a lost hub doesn’t lose sales. Backups of the hub keep the rest: the menu and staff as the back office left them, back office accounts, device pairings and plugin data.
Snapshots (on by default)
Section titled “Snapshots (on by default)”Every 24 hours the hub takes a snapshot of every database in its data folder into
<data>/backups/<date and time>/, and keeps the last 7. The first one is taken a minute after
the hub starts, unless a recent one exists.
A snapshot is a consistent copy taken while the hub keeps running (SQLite’s online backup), one
gzip file per database, plus a manifest.json written last. A folder without a manifest is
unfinished; ignore it.
| Setting | Default |
|---|---|
OPENKEDAI_BACKUP_INTERVAL_HOURS |
24; 0 turns snapshots off |
OPENKEDAI_BACKUP_KEEP |
7 snapshots |
Snapshots are in the same place as the data, so they protect against mistakes and bad updates, not against losing the machine or its disk. For that, copy them elsewhere.
Copies to S3-compatible storage (optional)
Section titled “Copies to S3-compatible storage (optional)”The hub can upload every snapshot to a bucket you own: Cloudflare R2, Backblaze B2, AWS S3, DigitalOcean Spaces, MinIO and others. Nothing leaves the hub unless you set this up.
-
Create a bucket, and an access key that can write to it (read and delete aren’t needed).
-
Set:
Setting Example OPENKEDAI_BACKUP_S3_URLthe bucket’s URL: https://<account>.r2.cloudflarestorage.com/kedai-backups,https://s3.us-west-004.backblazeb2.com/kedai-backups,https://kedai-backups.s3.ap-southeast-1.amazonaws.comOPENKEDAI_BACKUP_S3_ACCESS_KEY_IDthe key’s id OPENKEDAI_BACKUP_S3_SECRET_ACCESS_KEYthe key’s secret OPENKEDAI_BACKUP_S3_REGIONoptional: read from AWS and Backblaze URLs, else us-east-1(R2 and MinIO accept it)OPENKEDAI_BACKUP_S3_PREFIXoptional, default openkedai/ -
Restart the hub. Its log says
backupswith the bucket on start, andbackup uploaded to S3after each snapshot.
Objects go to <prefix><snapshot>/…, with manifest.json last. Old snapshots stay in the bucket:
set a lifecycle rule on the bucket (e.g. delete after 30 days) to keep its size in check.
Before updates
Section titled “Before updates”When an update changes a shop’s database, the hub first keeps a plain copy of the file in
<data>/backups/pre-migration/<date and time>/. These aren’t deleted automatically.
Restoring
Section titled “Restoring”-
Stop the hub (
docker compose stop,sudo systemctl stop openkedai…). -
Move the current data folder aside, keeping it until you’re sure.
-
For each
.gzfile in the snapshot, unzip it to the same path in a new data folder. With the snapshot folder as the current directory:Terminal window for f in $(find . -name '*.sqlite.gz'); domkdir -p "/var/lib/openkedai/$(dirname "$f")"gunzip -c "$f" > "/var/lib/openkedai/${f%.gz}"donechown -R openkedai:openkedai /var/lib/openkedai # installer: the service's user(With Docker, unzip into the
openkedai-datavolume the same way, e.g. from a temporaryalpinecontainer with the volume mounted.) -
Start the hub. Every snapshot carries its own log id, so when a device next syncs, it sees the hub was put back from a backup. It sends all of its own sales and its copy of the menu again, and reads the hub’s records from the start. The hub keeps one copy of each, so sales made since the snapshot come back from the devices that made them, and every device ends up with all of them.
What a snapshot can’t bring back: back office accounts and settings changed after it, and devices paired after it. Those devices say they were removed; pair them again from Settings → Hub, and their sales follow.
A pre-migration copy is a plain SQLite file: put it back at tenants/<shop>/shop.sqlite with
the older version of OpenKedai.
For AI tools: llms.txt ·llms-full.txtopenkedai.com