Updating and backups
one command each.
How to install a new version, how to back up the database and .env every night, and how to restore on the same or on a new server.
01Install a new version
From a new ZIP
- Upload the new version and extract it over the same
kestrelfolder on the server. Keep your.envand thebackups/folder. - Run the updater:
cd kestrel ./update.sh
From Git
If you installed with git clone, ./update.sh runs git pull --ff-only itself.
The updater (update.sh) does four things: it runs ./backup.sh, pulls new code when the folder is a Git checkout, rebuilds and restarts with docker compose up -d --build --remove-orphans, and waits until the server is healthy. Database migrations run automatically when the server starts. It removes unused Docker images at the end.
Check the version afterwards: curl -s https://your-domain/health.
The update rebuilds the web app. The Android, iOS and macOS apps are separate builds: rebuild and publish them when a release changes the app (Changelog).
If the server is not healthy after an update, the updater prints the last 40 log lines. Restore the backup it just made with the steps below.
02Backups
cd kestrel
./backup.sh
It writes into ./backups, safely while KESTREL is running (backup.sh):
- the database: an online SQLite backup (
kestrel-YYYYMMDD-HHMMSS.db.gz) or apg_dumpfor PostgreSQL (kestrel-YYYYMMDD-HHMMSS.sql.gz); - a copy of
.env(env-YYYYMMDD-HHMMSS), which holds the master key.
It keeps the newest 14 sets; set KEEP=30 ./backup.sh to keep more. Files are created with permission 600.
Every night
Run crontab -e and add this line (use your real folder path):
15 3 * * * cd /root/kestrel && ./backup.sh >> backups/backup.log 2>&1
A backup on the same disk is lost with the server. Copy ./backups regularly to another machine or to storage you control, for example with scp or rsync. Keep the copies private: they contain the master key.
The SQLite backup covers the trading database. The console's own file admin.sqlite lives in the same Docker volume; to keep console settings too, also copy it with docker compose cp server:/data/admin.sqlite backups/admin-$(date +%Y%m%d).sqlite, or export the settings in the console (Export / Import).
03Restore (SQLite)
cd kestrel
docker compose stop server web
gunzip -k backups/kestrel-YYYYMMDD-HHMMSS.db.gz
docker compose run --rm --no-deps --entrypoint sh server \
-c 'rm -f /data/kestrel.db-wal /data/kestrel.db-shm; cp /backups/kestrel-YYYYMMDD-HHMMSS.db /data/kestrel.db'
cp backups/env-YYYYMMDD-HHMMSS .env # only if you lost .env
chmod 600 .env
docker compose up -d
Replace YYYYMMDD-HHMMSS with the time stamp of the backup you restore.
04Restore (PostgreSQL)
docker compose stop server web
gunzip -c backups/kestrel-YYYYMMDD-HHMMSS.sql.gz | docker compose exec -T postgres psql -U kestrel -d kestrel
docker compose up -d
05Move to a new server
- Copy the folder and the backups to the new server.
- Put your old
.envin place, with the same master key. UpdateSERVER_PUBLIC_IPif the IP changes, and point the DNS A record at the new server. - Run
sudo ./install.sh, then restore as above. - Update the IP whitelist on every exchange key if the IP changed. Until then the exchanges refuse the keys.