# Backups
URL: https://synquic.tech/docs/dashboard/backups.md

The Backups page is where you add the places backups are stored (S3 buckets, SFTP or FTP hosts, Dropbox, Google Drive, one of your servers, or a local folder), test them, and see what uses each one.

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

The **Backups** page (in the sidebar, or at `/backups`) is where you set up the storage your backups are
written to. Synq calls these **destinations**. A destination answers one question: "when a backup runs,
where do the files go?"

This page manages destinations and gives an overview. **What** to back up and **when** is set in each
project: databases and services on the project's **Backup** tab (see
[Backups & restore](/docs/guides/backups-restore)), single volumes in its **Storage** section (see
[Volumes & volume backups](/docs/guides/volumes-backups)).

<Callout title="One-time setup, reused everywhere">
You add a destination once here, then any project's backup policy can point at it. One destination shared by
many projects is normal.
</Callout>

## What the page shows

- The title **Backups** with **External storage targets for project and service backups**, and **Add
  Destination** at the top right.
- A **Storage** summary: **Total stored**, the number of **Backups**, and the number of **Destinations**.
- One row per destination:
  - its name, a **Default** badge if it's the default, and its kind: **S3-compatible**, **SFTP**, **Existing
    server**, **FTP / FTPS**, **Dropbox**, **Google Drive**, **Local disk** or **HTTP upload**;
  - its status: **Verified**, **Failed**, **Verifying...** or **Not verified**;
  - where it points (bucket, region and endpoint, or `user@host:port`, or a path), which credentials are
    stored (**Access key stored**, **Private key stored**, **Reuses server credentials**, **Connected as
    you@example.com**...), how much it holds and when it was last used;
  - a **Verify connection** button and a menu with **Edit**, **Set as default** and **Delete**.
- **Volume backups**: every volume backup schedule across your projects, with its last run.

Click a destination to open its own page: the same summary for that destination and a **Used by** list of the
projects, services and volumes that back up to it, each with its schedule and an **Open in project** link.

## Add a destination

<Steps>

<Step>

### Press Add Destination

(Or **Add Your First Destination** when there are none.) The dialog **Add backup destination** asks you to
**Pick where your backups will be stored.**

| Kind | Best for | What it is |
| --- | --- | --- |
| **S3-compatible** | Most setups | Any S3 storage: AWS S3, Cloudflare R2, Backblaze B2, Wasabi, DigitalOcean Spaces, MinIO. |
| **SFTP** | A backup box or NAS | Push backups over SSH to any host, with credentials you enter. |
| **Existing server** | A server you already added | Reuses the SSH login of a server from the **Servers** page. |
| **FTP / FTPS** | Web hosting space, a NAS | Upload over FTP, or FTPS with explicit TLS, with credentials you enter. |
| **Dropbox** | A Dropbox account | Connect once through a Dropbox app you create. Backups go to a folder you choose. |
| **Google Drive** | A Google account | Connect once through a Google OAuth client you create. Backups go to a folder Synq creates. |
| **Local disk** | A second disk on the Synq machine | Writes to a folder where Synq's API runs. Off until you enable it (see below). |

</Step>

<Step>

### Fill in the details

Every kind starts with a **Name**, for example `Production R2`.

<Tabs items={["S3-compatible", "SFTP", "Existing server", "FTP / FTPS", "Dropbox", "Google Drive", "Local disk"]}>
<Tab value="S3-compatible">

Pick the **Provider** first; it decides which helper field you fill in:

| Provider | You fill in | Synq builds |
| --- | --- | --- |
| **AWS S3** | **Region**, for example `us-east-1` | The AWS endpoint. |
| **Cloudflare R2** | **Account ID** | `https://<account>.r2.cloudflarestorage.com`, region `auto`. |
| **Backblaze B2** | **Region**, for example `us-west-004` | `https://s3.<region>.backblazeb2.com`. |
| **Wasabi** | **Region**, for example `us-east-1` | `https://s3.<region>.wasabisys.com`. |
| **DigitalOcean Spaces** | **Region**, for example `nyc3` | `https://<region>.digitaloceanspaces.com`. |
| **MinIO / Custom** | **Endpoint** (full URL, for example `https://minio.example.com:9000`) and **Region** | What you typed. |

Then:

- **Bucket**, for example `my-backups`. It must exist.
- **Path prefix** (optional): a folder inside the bucket, for example `synq/`.
- **Access key ID** and **Secret access key**. The key needs permission to write, read, list and delete in
  that bucket (retention deletes old copies).
- **Storage class** (optional): **Provider default** sends none, so the bucket's own default applies. Or pick
  `STANDARD`, `STANDARD_IA`, `ONEZONE_IA`, `INTELLIGENT_TIERING` or `GLACIER_IR`; every backup file (and the
  test object) is uploaded with that class. These are AWS names: some S3-compatible providers ignore them or
  reject anything but `STANDARD`, and **Test connection** shows that rejection. The infrequent-access classes
  and `GLACIER_IR` have a minimum storage duration (90 days for `GLACIER_IR` on AWS) and a fee per GB read
  back, which a restore or a download pays.

</Tab>
<Tab value="SFTP">

- **Host** (for example `backups.example.com`), **Port** (default `22`) and **User**.
- **Path prefix**: the remote folder, for example `/backups/synq`.
- **Password**, or leave it empty and paste a **Private key (PEM)**.

</Tab>
<Tab value="Existing server">

- **Server**: one of the servers on the **Servers** page. Synq reuses its SSH credentials, so there's nothing
  new to enter. With no servers yet, the form links to **Servers**.
- **Remote path**: an absolute folder on that server, for example `/backups/synq`.

A backup on the same server as the data protects against mistakes, not against losing the server. Prefer
another server or a bucket for real disaster recovery.

</Tab>
<Tab value="FTP / FTPS">

- **Host** (for example `ftp.example.com`), **Port** (default `21`), **User** and **Password**.
- **Path prefix**: the folder on the server, for example `/backups/synq`. Without a leading `/` it is inside
  the folder you land in after logging in.
- **Encryption**: **FTPS (explicit TLS)**, the default, or **None (plain FTP)**. FTPS upgrades the normal
  control connection with `AUTH TLS` and encrypts the transfers too. Plain FTP sends the password and the
  backups unencrypted, so keep it to a network you trust. Implicit FTPS (a separate port, usually 990) is not
  supported.
- **Allow a self-signed certificate** (shown with FTPS): off by default, so the server's certificate must be
  valid for the host name. Tick it only for a server you control: the connection stays encrypted, but the
  server's identity is no longer checked. Without it, **Test connection** says the certificate was rejected
  and points at this box.

Transfers use passive mode, and data connections always go to the same host as the login, so the server's
passive port range must be open in its firewall. Each file is uploaded under a temporary `.uploading-` name,
its size is checked, and only then is it renamed into place: a backup that fails midway leaves nothing a
restore could pick up.

</Tab>
<Tab value="Dropbox">

Synq connects through a Dropbox app that you own, so the access it gets is the access you give that app.

1. Open the [Dropbox App Console](https://www.dropbox.com/developers/apps) and press **Create app**. Choose
   **Scoped access** and **App folder** (recommended: Synq then only ever sees its own folder,
   `Apps/<app name>` in your Dropbox). **Full Dropbox** works too.
2. On the app's **Permissions** tab, tick `files.metadata.read`, `files.content.read` and
   `files.content.write` (`account_info.read` is on by default), then press **Submit**.
3. On the **Settings** tab, under **OAuth 2**, add the **Redirect URI** the form shows, for example
   `https://panel.example.com/backups/oauth/callback`. It must match exactly, port included.
4. Copy the **App key** and **App secret** from the **Settings** tab into the form.
5. **Folder** (optional): where backups go, for example `/Synq Backups`. Empty means the top of the app folder.
6. Press **Save and connect**. Dropbox asks you to allow access, then sends you back to the destination's page,
   where Synq runs a test and shows **Connected as** your Dropbox email.

Large backups are sent in 8 MiB pieces through a Dropbox upload session, and a file only appears once every
piece has arrived. Synq checks Dropbox's content hash of every file against what it sent.

</Tab>
<Tab value="Google Drive">

Synq connects through an OAuth client in your own Google Cloud project, with the `drive.file` scope: it can
see and change only the files it creates, never the rest of your Drive.

1. In the [Google Cloud console](https://console.cloud.google.com/), create or pick a project and enable the
   **Google Drive API** (**APIs & Services**, **Library**).
2. In **Google Auth Platform**, set up the consent screen (**Branding** and **Audience**), add the scope
   `https://www.googleapis.com/auth/drive.file` under **Data access**, and on **Audience** press **Publish
   app**. While an app is in **Testing**, Google ends its connections after 7 days and backups start failing
   with a "press Reconnect" error.
3. Under **Clients**, create an OAuth client of type **Web application** and add the **Authorized redirect
   URI** the form shows, for example `https://panel.example.com/backups/oauth/callback`.
4. Copy the **Client ID** and **Client secret** into the form.
5. **Folder name** (optional, default `Synq Backups`): Synq creates this folder at the top of your Drive, or
   reuses the one it created before.
6. Press **Save and connect**, pick the Google account and allow access. You land back on the destination's
   page, which runs a test and shows **Connected as** that account, with an **Open in Drive** button.

Every backup file is one file in that folder, named by its full path, for example
`synq/shop/postgres/bkr_.../postgres.dump`, so sorting by name keeps a run's files together. Uploads are
resumable, in 8 MiB pieces, and each file's MD5 is checked after it lands. Backups count against the
account's Drive storage; a full Drive fails the backup with "Google Drive storage is full".

</Tab>
<Tab value="Local disk">

- **Absolute path**: a folder on the machine that runs Synq's API, for example `/var/lib/synq/backups/main`.

Local disk is **off by default**. Saving one fails with "Local destinations are disabled" until you set
`BACKUP_ALLOW_LOCAL_DESTINATION=true` in the API's environment (for an install made with `synq up`, the file
`~/.synq/compose/.env`) and restart Synq. The path must be inside `BACKUP_LOCAL_ROOT`, which defaults to
`/var/lib/synq/backups` and must be a dedicated folder (not `/`, `/var`, `/etc` or Docker's own folders).

When Synq's API runs in a container, as it does after `synq up`, that folder is **inside the container** and
is lost when the container is replaced, unless you mount a host folder at that path yourself. An SFTP or
**Existing server** destination that logs in to the machine over SSH writes to its real disk instead. Like any
same-machine target, it doesn't help if the machine itself is lost.

</Tab>
</Tabs>

</Step>

<Step>

### Test, then save

Press **Test connection**. Synq tries the settings for real (it writes and deletes a small test object, or
opens the SSH session) before anything is saved. A success message (for a bucket, that it is reachable and
writable) means it works; otherwise the reason is shown. Press **Save destination**. The toast says **Destination created.**

</Step>

</Steps>

<Callout title="Credentials are encrypted" type="info">
Keys, passwords, private keys, app secrets and the Dropbox and Google connection tokens are encrypted at rest
and never shown again. When you edit a destination, secret fields show dots and say a value is stored: leave
them blank to keep the stored value, or type a new one to replace it.
</Callout>

## Connect Dropbox or Google Drive

Dropbox and Google only send the browser back to an address the panel is really served on, so:

- Open the panel over **HTTPS** (for example on its domain), or on `localhost`. On a plain-HTTP address the
  form warns you and **Save and connect** stays off.
- Register the redirect URI exactly as the form shows it: the panel's address followed by
  `/backups/oauth/callback`. If you open the panel at another address later, add that one too.

The destination's page has **Connect** (or **Reconnect**). Press it when a backup or **Verify connection**
says the access "was revoked or has expired", for example after you removed the app's access in your Dropbox
or Google account, or after 7 days for a Google app still in **Testing**. Reconnecting keeps the destination,
its policies and its backups. Changing the **App key** or **Client ID** disconnects the destination, since the
old connection belonged to the other app.

## Verify a destination

Press **Verify connection** on a row. The badge changes to **Verifying...**, then **Verified** (hover for
the last check time) or **Failed** (hover for the error). Verify again whenever you rotate credentials: a
destination that can't be reached can't take backups.

## Default, edit and delete

- **Set as default** (in the row's menu) marks your usual destination with the **Default** badge. It's a
  label; each policy still names its own destination.
- **Edit** opens the form on the details step. The kind can't be changed after creation. **HTTP upload**
  destinations can't be edited here.
- **Delete** asks for confirmation. A destination that a backup policy still uses **can't be deleted**:
  change or remove those policies first (the destination's **Used by** list shows them). Backups already
  stored at the destination are not deleted from it.

## CLI

```bash
# Add an SFTP destination with a key file, and make it the default
synq backup destination create --name "NAS" --kind sftp \
  --ssh-host backups.example.com --ssh-port 22 --ssh-user backup \
  --path-prefix /backups/synq --sftp-private-key-file ~/.ssh/backup_key --default

# Add an FTPS destination
synq backup destination create --name "Hosting" --kind ftp \
  --ftp-host ftp.example.com --ftp-user backup --ftp-password "$FTP_PASSWORD" \
  --ftp-tls explicit --path-prefix /backups/synq

# List, check, and see what uses one
synq backup destination list
synq backup destination preflight <destinationId>
synq backup destination usage <destinationId>
```

`--kind` is `s3_compatible`, `sftp`, `synq_server` (an existing server, with `--server <id>`), `ftp`,
`dropbox`, `google_drive` or `local` (with the folder in `--endpoint`). For `dropbox` and `google_drive`, pass
the app's credentials with `--oauth-client-id` and `--oauth-client-secret`, then press **Connect** on the
destination's page: approving access happens in the browser. `preflight-draft <file>` tests settings from a
JSON file before saving them.

## Next steps

<Cards>
  <Card title="Backups & restore" href="/docs/guides/backups-restore" description="Back up databases and services on a schedule, then restore with the wizard." />
  <Card title="Volumes & volume backups" href="/docs/guides/volumes-backups" description="Schedule backups of a single volume." />
  <Card title="Servers" href="/docs/guides/custom-servers" description="Add the servers whose SSH login the Existing server kind reuses." />
</Cards>
