> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cymph.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Backup & restore

> Back up and restore a self-hosted Cymph deployment using Docker volume snapshots.

A self-hosted deployment keeps all of its state in Docker volumes plus a handful of configuration files. Backing up means archiving both; there is no separate export step inside the application.

<Warning>
  A volume backup is only usable together with the deployment's secrets. `CYMPH_ENCRYPTION_KEY` and `CYMPH_ENCRYPTION_IV` in `.env`, and the key in `db/secrets.txt`, are generated once at setup and cannot be regenerated. Without them, sensitive integration data in a restored database cannot be decrypted. Always back up the configuration files alongside the volumes.
</Warning>

## What to back up

| Item                    | Why                                                                                                                             |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| Volume `cymph_db-data`  | The PostgreSQL data directory — playbooks, executions, users, organisations, workspaces, integration configuration, audit logs. |
| Volume `cymph_api-data` | Application data and static files under `/var/opt/cymph`.                                                                       |
| `.env`                  | Deployment configuration and the encryption and signing secrets.                                                                |
| `.dbenv`                | The on-prem administrator e-mail used to seed the database.                                                                     |
| `db/secrets.txt`        | The database key generated at setup.                                                                                            |
| `nginx/nginx.conf`      | Contains the `server_name` written in during setup.                                                                             |

`cymph_log-data` (nginx logs) is worth keeping if you retain logs for compliance reasons. `cymph_embedding-data` holds only a cached model and is re-downloaded automatically — skip it.

## Choosing a method

**Volume snapshots are the recommended approach.** One mechanism captures the database and the application data together at the same point in time, and restore is a straight extraction — no schema migration, no dump-format compatibility to think about between versions.

The trade-off is that copying a live PostgreSQL data directory is not crash-consistent, so **the stack has to be stopped while the archive is taken**. In practice this fits the maintenance window you already take for [upgrades](/deployment/self-hosted/upgrades).

<Note>
  If you need backups without downtime, use `pg_dump` against the `db` container for the database and snapshot `cymph_api-data` separately. That gives you a hot backup but two restore paths to manage instead of one.
</Note>

## Taking a backup

1. Stop the stack from the directory containing `compose.yaml`:

```bash theme={"system"}
sudo docker compose stop
```

2. Archive each volume through a throwaway container:

```bash theme={"system"}
mkdir -p backup

sudo docker run --rm \
  -v cymph_db-data:/source:ro \
  -v "$(pwd)/backup":/backup \
  alpine tar czf /backup/db-data.tar.gz -C /source .

sudo docker run --rm \
  -v cymph_api-data:/source:ro \
  -v "$(pwd)/backup":/backup \
  alpine tar czf /backup/api-data.tar.gz -C /source .
```

3. Copy the configuration files:

```bash theme={"system"}
cp .env .dbenv db/secrets.txt nginx/nginx.conf backup/
```

4. Start the stack again:

```bash theme={"system"}
sudo docker compose start
```

5. Move the `backup` directory off the host, to wherever you keep encrypted backups. It contains the deployment's secrets in plaintext, so treat it accordingly.

<Tip>
  Volume names are prefixed with the Compose project name, which is `cymph`. If you renamed the project, confirm the real names with `docker volume ls`.
</Tip>

## Restoring

Restore onto a host with the same Cymph release the backup was taken from. Restoring into a newer release is not supported — restore first, then [upgrade](/deployment/self-hosted/upgrades).

1. Extract the release bundle and put the saved configuration files back in place. Do **not** run `env.sh` — it would generate new secrets and make the backup undecryptable.

```bash theme={"system"}
tar zxvf cymph_onprem.tgz
cd cymph/
cp /path/to/backup/.env /path/to/backup/.dbenv .
mkdir -p db && cp /path/to/backup/secrets.txt db/
cp /path/to/backup/nginx.conf nginx/
```

2. Make sure nothing is running, and remove the volumes that the restore will replace:

```bash theme={"system"}
sudo docker compose down
sudo docker volume rm cymph_db-data cymph_api-data
```

3. Recreate the volumes and extract the archives, preserving ownership so PostgreSQL can read its data directory:

```bash theme={"system"}
sudo docker volume create cymph_db-data
sudo docker volume create cymph_api-data

sudo docker run --rm \
  -v cymph_db-data:/target \
  -v /path/to/backup:/backup:ro \
  alpine tar xzpf /backup/db-data.tar.gz -C /target

sudo docker run --rm \
  -v cymph_api-data:/target \
  -v /path/to/backup:/backup:ro \
  alpine tar xzpf /backup/api-data.tar.gz -C /target
```

4. Confirm the TLS certificate and key are present at the paths recorded in `.env` — those are host paths and are not part of the volume backup. See [TLS certificates](/deployment/self-hosted/tls-certificates).

5. Start the stack:

```bash theme={"system"}
sudo docker compose up -d
```

6. Verify the restore. `docker compose ps` should show every service healthy, and you should be able to log in with the credentials that were in use when the backup was taken — user accounts and passwords come from the restored database, not from setup.

If the `db` service fails its healthcheck after a restore, check its logs first — a permissions problem on the data directory is the usual cause, and it means step 3 ran without `-p` or without root:

```bash theme={"system"}
sudo docker compose logs db
```
