# Back up and restore the panel
URL: https://synquic.tech/docs/guides/panel-backups.md

Protect Synq's own data. Schedule panel backups of the control-plane database to S3, SFTP, Dropbox, Google Drive or another destination from Settings, Instance, run one by hand, and restore it on the same or a new server.

import { Step, Steps } from 'fumadocs-ui/components/steps';

The **panel** (the control plane) keeps everything Synq knows in its own Postgres database: your projects and
their settings, servers and SSH credentials, domains, environment variables, users and workspaces, backup policies,
jobs and their history. If that database is lost, your apps keep running, but Synq no longer knows about them.
Panel backups protect that database.

<Callout title="What a panel backup does not contain" type="info">
Your apps' own data (their volumes and databases) is not in it: protect those with
[project backups](/docs/guides/backups-restore). Certificates and edge routes aren't either: routes are rewritten
from the database when Synq starts, and missing certificates are requested again.
</Callout>

## How panel backups work

| | Scheduled panel backups |
| --- | --- |
| Made by | The **Panel database backup** job, on a schedule or by hand (**Back up now**) |
| Stored | On a backup destination (S3-compatible, SFTP, FTP, Dropbox, Google Drive, an existing server, local disk) |
| Kept | The newest N (you choose, default 7) |
| Turned on | Off until you choose a destination and turn it on |
| Restore with | The steps [below](#restore-a-panel-backup) |

They protect you from losing the server, so send them somewhere other than the server itself. Run one by hand
before a big update, too.

## Set up scheduled panel backups

You need to be an **instance administrator** (the admin account created when Synq was installed) on a
self-hosted install. Other users don't see the card.

<Steps>

<Step>

### Add a backup destination

Open **Backups** in the sidebar and add a destination: **S3-compatible** (AWS S3, Cloudflare R2, Backblaze B2,
Wasabi, MinIO), **SFTP**, **Existing server**, **FTP / FTPS**, **Dropbox**, **Google Drive** or **Local disk**. Verify it. See
[Add a destination](/docs/dashboard/backups#add-a-destination). Pick storage that is **not** the Synq server
itself (so not **Local disk**), or the backup is lost together with the server.

</Step>

<Step>

### Open the Panel backups card

Go to **Settings**, choose the **Instance** tab and scroll to **Panel backups** ("Back up this control plane's
database to a backup destination on a schedule").

</Step>

<Step>

### Choose what and when

| Field | What to set |
| --- | --- |
| **Destination** | The destination from step 1. If you have none yet, **Add a destination** opens Backups. |
| **Back up on a schedule** | Turn it on. It can't be turned on without a destination. |
| **Schedule (cron)** | A 5-field cron in server time. The default `11 2 * * *` is every day at 02:11. |
| **Keep the newest** | How many backups to keep, from 1 to 365. Default 7. |
| **Include instance settings (.env)** | On by default. Adds the server settings a restore needs, including `BETTER_AUTH_SECRET` (see below). |

Press **Save**.

</Step>

<Step>

### Take the first backup now

Press **Back up now**. The backup runs in the background; the card shows **Backup in progress…** and then
**Last backup** with its result. **Next backup** shows when the schedule runs next. Only one backup runs at a
time: pressing the button again while one runs says **A backup is already running**.

</Step>

<Step>

### Check what the destination holds

Press **Show stored backups**. Each backup is listed with its time and size. **with settings** marks a backup that
includes `instance.env`; **incomplete** marks one that never finished.

</Step>

</Steps>

Every run is also recorded under **Jobs** as the system job **Panel database backup**, with its output. Changes to
the settings and every **Back up now** appear in the [audit log](/docs/guides/audit-log) (**Panel backup settings
changed**, **Panel backup started**).

## What a backup contains

Each run writes one folder to the destination:

```text
synq-panel-backups/
  20260926T021100Z-<id>/
    database.dump     the control-plane database (pg_dump custom format)
    instance.env      the server settings, when "Include instance settings" is on
    manifest.json     written last: version, sizes, checksums and the restore steps
```

A folder without `manifest.json` is an incomplete run. When a run finishes, Synq deletes the complete backups beyond
your **Keep the newest** count and old incomplete folders.

<Callout title="Protect instance.env like a key" type="warn">
Stored secrets (environment variables, SSH keys, Git tokens, backup credentials) stay **encrypted** inside
`database.dump`, exactly as they are in the database. What decrypts them is `BETTER_AUTH_SECRET`, which is in
`instance.env`. With the setting on, the destination holds both halves, so restrict who can read it. With the
setting off, keep a copy of `BETTER_AUTH_SECRET` from `/root/.synq/compose/.env` somewhere safe yourself: a restored
database can't decrypt its secrets without it.
</Callout>

## Restore a panel backup

These are the same steps the card shows under **How to restore**, and that every `manifest.json` repeats. They work
on the original server or on a new one.

<Steps>

<Step>

### Download the backup

Copy the whole backup folder (`database.dump`, `instance.env`, `manifest.json`) from the destination to the target
server.

</Step>

<Step>

### Install Synq and let it start once

On a new server, install Synq as usual with your license key ([Installation](/docs/getting-started/installation)),
with the same panel domain as before if you want to keep it. Wait until the panel answers.

</Step>

<Step>

### Copy the secrets across

From `instance.env`, copy `BETTER_AUTH_SECRET` and `INTERNAL_TOKEN` (and any other settings you need, such as
`SYNQ_PUBLIC_URL` and the `SYNQ_ACME_*` keys) into `/root/.synq/compose/.env` on the target server (as root, with
`sudo`). **Keep the new install's `POSTGRES_PASSWORD`**: it belongs to the new database. Keep its
`SYNQ_INSTALLATION_ID` and `SYNQ_LICENSE_KEY` too: they belong to this installation.

</Step>

<Step>

### Stop the API

So nothing writes to the database during the restore:

```bash
sudo docker compose -f /root/.synq/compose/docker-compose.yml stop api
```

</Step>

<Step>

### Restore the database

From the folder that holds `database.dump`:

```bash
sudo docker compose -f /root/.synq/compose/docker-compose.yml exec -T postgres pg_restore --clean --if-exists --no-owner --no-acl --single-transaction -U synq -d synq < database.dump
```

</Step>

<Step>

### Start Synq again

Run `sudo synq up` again. The API starts with the restored data and applies any newer database migrations, so a backup
from an older version can be restored into a newer Synq.

</Step>

</Steps>

<Callout title="Restoring on a new server" type="info">
The panel comes back with every project, server and domain it knew. Apps that ran on the **old machine itself**
("This Server") are not moved by this: move their data with a [server-to-server
migration](/docs/guides/server-to-server-migration) or restore their [project backups](/docs/guides/backups-restore)
there. Point DNS at the new server once it is ready. For a move between two running installs, the export and import
in [Move your setup to another install](/docs/guides/migrate-control-plane) is an alternative.
</Callout>

## From the API

| Call | What it does |
| --- | --- |
| `GET /api/system/panel-backup` | Settings, status and recent runs |
| `PUT /api/system/panel-backup` | Change the destination, schedule, on/off, retention and the `.env` option |
| `POST /api/system/panel-backup/run` | Start a backup now |
| `GET /api/system/panel-backup/backups` | List the backups at the destination |

All four need instance authority. They are also MCP tools, so an AI agent with enough access can check that
backups run. See the [System API](/docs/api/system).

## Limits

- Servers installed with the installer (Docker Compose) only: the dump runs inside the stack's own
  Postgres container.
- Instance administrators only, and the destination must belong to your current workspace.
- One destination at a time. A manual run may take up to 2 hours before it is stopped.
- Times in **Schedule (cron)** are the Synq server's time, which is UTC in the standard install.

## Related guides

<Cards>
  <Card title="Updating Synq" href="/docs/guides/updating" description="Upgrade by running the installer again." />
  <Card title="Backups and restores" href="/docs/guides/backups-restore" description="Back up your apps' data." />
  <Card title="Scheduled jobs" href="/docs/guides/jobs" description="Where every backup run is recorded." />
  <Card title="Move your setup to another install" href="/docs/guides/migrate-control-plane" description="Export and import a whole instance." />
</Cards>
