Files
Portainer/backups/kopia
Eduardo David Paredes Vara 616b20f285 feat(backups): añadir stack de backups cifrados con Kopia + Cloudflare R2
- init-r2-repository.sh: inicializa repositorio Kopia en R2
- run-backup.sh: ejecuta backup de rutas definidas en backup-paths.txt
- pre-backup-dumps.sh: vuelca bases de datos (Postgres, MariaDB) antes del backup
- kopia-common.sh: funciones compartidas de autenticación y configuración
- restore-smoke-test.sh: test de restauración para verificar integridad
- backup-paths.txt / excludes.txt: rutas y exclusiones del backup
- systemd/: unidades kopia-server, kopia-docker-backup (service + timer)
- traefik-kopia.yml: exposición del servidor Kopia vía Traefik
- env.example: plantilla de variables (credenciales R2, contraseña repo)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 05:48:38 +00:00
..

Kopia backups to Cloudflare R2

This directory defines restore-focused backups for the Docker services that are actually running on the host. It uses Kopia with Cloudflare R2 as an S3-compatible repository.

Policy

  • Use Kopia as the only backup engine.
  • Store the repository in Cloudflare R2.
  • Keep secrets outside this repo in /opt/kopia/kopia.env.
  • Snapshot data needed to restore services and configuration.
  • Generate logical database dumps before each snapshot.
  • Include Paperless documents and Gitea repositories.
  • Exclude Nextcloud user data/multimedia until storage usage and R2 cost are explicitly accepted.

Current size check on 2026-04-27:

Path Size
/opt/paperless 316M
/opt/gitea 6.0M
/opt/nextcloud 2.8G
/opt/onlyoffice 4.3M
/opt/authentik 8.3M
/opt/trilium 3.6M
/opt/karakeep 5.2M
/opt/spintools 335M

What is backed up

The snapshot paths are listed in backup-paths.txt. The important choices are:

  • Paperless: /opt/paperless/data, /opt/paperless/media, export and consume directories.
  • Gitea: /opt/gitea/data and runner data.
  • Nextcloud: config, themes and a MariaDB dump only. /opt/nextcloud/data, /opt/nextcloud/custom_apps and /opt/nextcloud/html are excluded.
  • Databases: PostgreSQL and MariaDB dumps are written to /opt/kopia/staging/dumps/latest.
  • Service configuration: deployment repo, Traefik, Authentik, n8n, Memos, Vikunja, Trilium, Karakeep, AdGuard, WireGuard, mail relay, Beszel, Homepage, Dozzle, Kasm and OpenCode.
  • Local active deployments: Scheduler, Spintools, THSCOM, OpenClaw restore state and OpenCode runtime state.

Live database directories are excluded when a logical dump exists. Kasm's PostgreSQL database is backed up with pg_dump; Docker image/layer storage under /opt/kasm/opt/docker is intentionally excluded because it is rebuildable and large. OpenProject's embedded PostgreSQL data is not dumped by this first version; treat its restore as best-effort unless a service-specific dump command is added.

Install Kopia

Install Kopia on the host using the package method appropriate for the server. Then create the runtime directory:

sudo mkdir -p /opt/kopia
sudo cp backups/kopia/env.example /opt/kopia/kopia.env
sudo chmod 600 /opt/kopia/kopia.env

Edit /opt/kopia/kopia.env and set the R2 bucket, endpoint, access keys and KOPIA_PASSWORD.

Cloudflare R2 endpoint format:

<account_id>.r2.cloudflarestorage.com

Initialize

backups/kopia/init-r2-repository.sh

Run manually

backups/kopia/run-backup.sh

The script:

  1. Creates database dumps.
  2. Snapshots the paths in backup-paths.txt.
  3. Applies retention: latest 7, daily 7, weekly 4, monthly 6.
  4. Runs kopia repository validate-provider.

Enable timer

Install the scripts under /opt/kopia/scripts; systemd should not execute them directly from a home directory on SELinux-enforcing hosts.

sudo install -d -m 0755 /opt/kopia/scripts
sudo install -m 0755 backups/kopia/*.sh /opt/kopia/scripts/
sudo install -m 0644 backups/kopia/backup-paths.txt backups/kopia/excludes.txt /opt/kopia/scripts/
sudo cp backups/kopia/systemd/kopia-docker-backup.* /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now kopia-docker-backup.timer

Web UI

Kopia UI is exposed at:

https://kopia.sherlockhomeless.net

The service listens only on the Docker host gateway 10.0.0.1:51515 and is published through Traefik using traefik-kopia.yml.

Credentials are stored outside the repo in /opt/kopia/kopia.env:

sudo awk -F= '/^KOPIA_SERVER_USERNAME|^KOPIA_SERVER_PASSWORD/ {print}' /opt/kopia/kopia.env

Install or update the service and Traefik route:

sudo cp backups/kopia/systemd/kopia-server.service /etc/systemd/system/
sudo cp backups/kopia/traefik-kopia.yml /opt/traefik/dynamic/kopia.yml
sudo systemctl daemon-reload
sudo systemctl enable --now kopia-server.service

Restore smoke test

Requires jq.

backups/kopia/restore-smoke-test.sh /tmp/kopia-restore-test

For real restores, restore into a temporary directory first, stop the target service, move data into place with correct ownership, then start the stack and validate the application.