# Backups and restore

Back up the database offsite and restore it on another machine.

Use `kogut backup` to copy the live database. Do not copy `kogut.db` with `cp` while
kogut runs. Keep the backup at another provider.

## What to back up

- The `kogut backup` file: accounts, the objects made in the panel, incidents, and all
  history.
- `kogut.toml`, or the file that `KOGUT_CONFIG` names.
- The values `kogut.toml` reads with `${NAME}`, from the environment or
  `$CREDENTIALS_DIRECTORY`, and server variables such as `KOGUT_URL`. See
  [Secrets](https://docs.kogut.dev/reference/configuration/#secrets).
- The logo file in the data directory, if `[brand] logo` names a file rather than a URL.

The rest of the data directory needs no backup: `kogut.lock`, `setup-token`, the
`kogut.db-wal` and `kogut.db-shm` files, and the `kogut.db.pre-NNNN.bak` copies made
before migrations. Agents keep their own settings on each host, such as
`/etc/kogut/agent.env` for an install-script agent.

## Create a backup

**systemd**

For an install-script deployment, run:

```sh
sudo env KOGUT_DATA=/var/lib/kogut kogut backup /var/backups/kogut.db
```

**Docker**

```sh
docker exec kogut /usr/local/bin/kogut backup /data/backup.db
docker cp kogut:/data/backup.db ./kogut-backup.db
```

The command writes a compact SQLite file and replaces the destination only when the copy
is complete. It leaves out visitor salts, so visitors already counted on the day of a
restore can be counted again. See the [backup command](https://docs.kogut.dev/reference/cli/#kogut-backup).

## Schedule offsite copies

1. Configure your transfer tool. The example uses an rclone remote named `r2` and a bucket
   named `acme-kogut`. Limit its credentials to that bucket.
2. Save the service and timer below, with your own transfer command.

```ini title="/etc/systemd/system/kogut-backup.service"
[Unit]
Description=Back up the kogut database

[Service]
Type=oneshot
Environment=KOGUT_DATA=/var/lib/kogut
ExecStart=/usr/local/bin/kogut backup /var/backups/kogut/kogut.db
ExecStartPost=/usr/bin/rclone copyto /var/backups/kogut/kogut.db r2:acme-kogut/kogut.db
```

```ini title="/etc/systemd/system/kogut-backup.timer"
[Unit]
Description=Back up the kogut database every night

[Timer]
OnCalendar=*-*-* 03:30:00
Persistent=true

[Install]
WantedBy=timers.target
```

3. Create the destination directory and enable the timer:

```sh
sudo mkdir -p /var/backups/kogut
sudo systemctl daemon-reload
sudo systemctl enable --now kogut-backup.timer
```

4. Turn on object versioning or keep dated copies, so a bad backup cannot replace every
   good one. Add a [heartbeat](https://docs.kogut.dev/monitoring/heartbeats/) to catch missed backup jobs.

To lose less than one backup interval, run [Litestream](https://litestream.io) beside
kogut to stream changes offsite.

## Restore the database

1. Install kogut on the destination and stop it. For systemd, run
   `sudo systemctl stop kogut`. For Docker, run `docker stop kogut`.

2. Restore to the install-script data directory:

   ```sh
   sudo env KOGUT_DATA=/var/lib/kogut kogut restore /var/backups/kogut.db
   ```

   Add `--force` to replace an existing database. Restore refuses to run while the server
   holds the data directory's lock.

   For Docker, restore to the server's volume:

   ```sh
   docker run --rm -v kogut-data:/data -v "$PWD":/backup:ro \
   ghcr.io/piotrkowski/kogut:0.1 restore /backup/kogut-backup.db --force
   ```

3. For an install-script deployment, return the restored files to the service's dynamic
   user before starting kogut:

   ```sh
   sudo chown -R --reference=/var/lib/private/kogut /var/lib/private/kogut
   ```

4. Restore `kogut.toml`, the values and credentials it reads, and the logo file, if any.
   Start kogut and update DNS if the address changed. Older databases migrate on startup,
   and agents send their buffered data when they reconnect.

Restore accepts a database from the current or an older schema version, not a newer one.
See the [restore command](https://docs.kogut.dev/reference/cli/#kogut-restore). Practise a restore on a
separate machine before you need it.
