Repository navigation
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.
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.
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.
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.
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 currentAPP_KEYis 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.
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 --forcecortendesk: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.
- 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.
- Sign in as the first-boot admin, open Settings → Backups, upload the archive and restore it.
- Restart the container so the restored server key pair is adopted.
- Check the log for
Private key comes from id_ed25519and that theKey: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.
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).