Skip to content

Backups

Marc Pope edited this page Oct 13, 2026 · 3 revisions

Backups

Settings → Backups. One archive holds everything needed to rebuild the install: the whole database, every setting, the app key the encrypted settings depend on, and, with the embedded server, the ID server's key pair and peer database. Automatic backups are on by default, every day, keeping 7 daily, 8 weekly and 6 monthly.

Treat an archive like a password. It contains the APP_KEY and every secret the database holds (SMTP password, SSO client secret, 2FA secrets, stored address book passwords). Anyone with the file can read them.

What is in an archive

cortendesk-backup-YYYYMMDD-HHMMSS.tar:

Path What
manifest.json Version, time, row count per table, which files are present
db/<table>.ndjson.gz Every data table, one JSON object per row
files/app_key APP_KEY at backup time
files/server_secret The console–server link secret, when the link is on
files/rustdesk/id_ed25519, id_ed25519.pub The server key pair (embedded server only)
files/rustdesk/db_v2.sqlite3 The ID server's peer database (embedded server only)

The dump is written by CortenDesk itself, not mysqldump, so the same archive restores into MySQL or MariaDB whichever made it. Cache, session and queue tables are not included. Uploaded client installers are not included either: they are large, you built them, and they live in /data/downloads.

Archives are written to /data/backups in the container (CORTENDESK_BACKUPS_PATH), so they survive image upgrades with the rest of the volume. They do not survive losing the volume, which is what the off-site copy is for.

Schedule and retention

Backups run every day at 03:30 server time. A box that was off at 03:30 catches up the next time the scheduler runs. Back up now writes one immediately; manual backups count toward retention like any other.

Retention has three tiers that all apply at once:

Tier Default Keeps
Daily 7 the newest 7 backups
Weekly 8 the first backup of each of the last 8 weeks
Monthly 6 the first backup of each of the last 6 months

Anything no tier covers is deleted after each run. With the defaults you have every day for a week, every week for two months and every month for half a year. Set a tier to 0 to turn it off; all three at 0 keeps everything.

Off-site copy

The target mirrors the list on this server. After each run, scheduled or manual, the new backup is uploaded and anything the server no longer has is removed there, whether retention pruned it or you deleted it on the tab (a delete on the tab also removes the off-site copy straight away). Backups that are missing at the target, say after it was set up or after a failed copy, go up on the next run, and so does one whose copy there has a different size, as an upload cut short would. The local copy stays either way. A failed copy is reported on the tab and in the log and does not stop the next run. A run that starts while another is still copying leaves the target alone; its backup goes up with the next run.

FTP / FTPS. Host, port, username, password, directory (created if missing, relative to the sign-in directory), and a TLS switch for explicit FTPS (AUTH TLS, usually port 21). Plain FTP sends the password in clear. Implicit FTPS on port 990 and SFTP are not supported.

With TLS on, the data connections are encrypted too; a server that will not do that is refused rather than sent the archive in clear. The server's certificate is not verified, so self-signed certificates work, and so would an attacker who can intercept the connection.

Transfers use passive mode, or active mode if the server refuses passive. Data connections go to the host you entered unless the server advertises a different public address, so a server behind NAT that advertises its private address still works; if the first choice does not connect, the other is tried. After each upload the size on the server is checked against the backup, and a short or broken upload is removed and reported, so it never passes for a finished copy.

S3-compatible storage. Bucket, region, access key ID and secret. Leave the endpoint empty for AWS; MinIO, Backblaze B2, Wasabi, Cloudflare R2 and the like need their own, and most self-hosted servers need path-style addressing. The optional folder is a key prefix. Only the direct children of that prefix are managed, so sharing a bucket with other things is fine.

Test connection saves the settings, then does what a backup run does, and shows the result under the button. For FTP it signs in, lists the directory, uploads a small file and deletes it again. For S3 it lists the bucket.

Restore

Restoring overwrites everything: every setting, user, device, group, address book, strategy and log is replaced with what the archive holds. Anything changed since the backup was taken is lost. There is no undo, so take a backup first if you may want to come back.

Pick an archive from the list, or upload one from another install or an off-site copy. Then:

  • Every data table is replaced inside one transaction. If anything fails, nothing is changed.
  • Encrypted values are re-keyed when the archive came from a different APP_KEY, so an archive from one install restores cleanly into a fresh one. The current APP_KEY is never changed.
  • With the embedded server, the key pair and peer database are staged next to the live files and swapped in on the next container start. Restart the container after a restore; the tab tells you when this applies.
  • Reload the page afterwards. If the account you were signed in with is not in the archive, you are signed out.

Restore into the same CortenDesk version that made the archive, or a newer one. A newer archive is refused with a message naming the version. Columns an older archive does not know about are left at their defaults; columns this version no longer has are ignored and listed in the result.

From the command line

docker compose exec -u www-data cortendesk php artisan cortendesk:backup
docker compose exec -u www-data cortendesk php artisan cortendesk:backup --no-copy
docker compose exec -u www-data cortendesk php artisan cortendesk:restore cortendesk-backup-20261012-033000.tar
docker compose exec -u www-data cortendesk php artisan cortendesk:restore /data/backups/some.tar --force

cortendesk:backup --scheduled is what the scheduler runs; it honours the switch and runs at most once a day. A bare cortendesk:backup always runs, copies off-site and applies retention.

Rebuilding on a new host

  1. Start a fresh container the normal way (see Install with Docker). It generates its own app key and server key; both are about to be replaced.
  2. Sign in as the first-boot admin, open Settings → Backups, upload the archive and restore it.
  3. Restart the container so the restored server key pair is adopted.
  4. Check the log for Private key comes from id_ed25519 and that the Key: line matches what your clients have. Devices come back online within a heartbeat.

Without the embedded server (CORTENDESK_EMBEDDED_SERVER=false), the archive carries the database only; the key pair lives with your own hbbs.

Manual installs

Set CORTENDESK_BACKUPS_PATH to a directory PHP can write and that is backed up itself. Set CORTENDESK_RUSTDESK_DIR to your hbbs data directory if the console can read it; a restore then stages *.restore files there for you to move into place while hbbs is stopped. The ftp PHP extension is needed for FTP copies; distro packages ship it with TLS. If you build PHP yourself, the FTPS switch needs an extension built with --with-ftp-ssl (the console says so when it is missing).

Clone this wiki locally