feat: add Restic backup stack with Backrest UI
Added comprehensive backup solution to The Falcon infrastructure:
- **Restic Stack** (restic.pivoine.art):
- Backrest web UI for managing restic backups
- Automated scheduled backups with retention policies
- Real-time backup status and monitoring
- Restore capabilities via web interface
- **Backup Configuration**:
- Target: /mnt/hidrive/users/valknar/Backup
- Backs up all critical Docker volumes read-only:
- PostgreSQL, Redis, Directus (uploads/bundle)
- Awesome, Gotify, Scrapy (data/code)
- n8n workflows, Filestash state
- Linkwarden bookmarks/search index
- Let's Encrypt SSL certificates
- **Infrastructure Updates**:
- Added RESTIC_* environment variables to arty.yml
- Updated compose.yaml to include restic stack
- Updated README.md and CLAUDE.md documentation
- Configured Traefik routing with SSL
All volumes mounted read-only to backup container for safety.
Backrest data persisted across: data, config, cache, tmp volumes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
30
CLAUDE.md
30
CLAUDE.md
@@ -20,6 +20,8 @@ Root `compose.yaml` uses Docker Compose's `include` directive to orchestrate mul
|
|||||||
- **n8n**: Workflow automation platform (PostgreSQL)
|
- **n8n**: Workflow automation platform (PostgreSQL)
|
||||||
- **stash**: Filestash web-based file manager
|
- **stash**: Filestash web-based file manager
|
||||||
- **links**: Linkwarden bookmark manager (PostgreSQL + Meilisearch)
|
- **links**: Linkwarden bookmark manager (PostgreSQL + Meilisearch)
|
||||||
|
- **restic**: Backrest backup system with restic backend
|
||||||
|
- **sablier**: Dynamic scaling plugin for Traefik
|
||||||
- **vpn**: WireGuard VPN (wg-easy)
|
- **vpn**: WireGuard VPN (wg-easy)
|
||||||
|
|
||||||
All services connect to a single external Docker network (`falcon_network` by default, defined by `$NETWORK_NAME`).
|
All services connect to a single external Docker network (`falcon_network` by default, defined by `$NETWORK_NAME`).
|
||||||
@@ -195,6 +197,33 @@ Linkwarden bookmark manager with full-text search:
|
|||||||
- `LINKS_NEXTAUTH_SECRET`: NextAuth.js secret for session encryption
|
- `LINKS_NEXTAUTH_SECRET`: NextAuth.js secret for session encryption
|
||||||
- `LINKS_MEILI_MASTER_KEY`: Meilisearch master key for API authentication
|
- `LINKS_MEILI_MASTER_KEY`: Meilisearch master key for API authentication
|
||||||
|
|
||||||
|
### Restic (restic/compose.yaml)
|
||||||
|
Backrest backup system with restic backend:
|
||||||
|
- **backrest**: Backrest web UI exposed at `restic.pivoine.art:9898`
|
||||||
|
- Web-based interface for managing restic backups
|
||||||
|
- Automated scheduled backups with retention policies
|
||||||
|
- Support for multiple backup plans and repositories
|
||||||
|
- Real-time backup status and history
|
||||||
|
- Restore capabilities via web UI
|
||||||
|
- Data persisted in `backrest_data`, `backrest_config`, `backrest_cache` volumes
|
||||||
|
|
||||||
|
**Backup Configuration**:
|
||||||
|
- **Backup Target**: `/mnt/hidrive/users/valknar/Backup` (mounted to container as `/repos`)
|
||||||
|
- **Volumes Backed Up** (all mounted read-only to `/volumes/`):
|
||||||
|
- `core_postgres_data` - PostgreSQL database files
|
||||||
|
- `core_redis_data` - Redis data
|
||||||
|
- `directus_uploads` - Directus media files
|
||||||
|
- `directus_bundle` - Directus extensions
|
||||||
|
- `awesome_data` - AWSM SQLite database
|
||||||
|
- `gotify_data` - Gotify notifications
|
||||||
|
- `scrapyd_data`, `scrapy_code` - Scrapy spider data
|
||||||
|
- `n8n_data` - n8n workflow configurations
|
||||||
|
- `filestash_data` - Filestash state
|
||||||
|
- `linkwarden_data`, `linkwarden_meili_data` - Linkwarden bookmarks and search index
|
||||||
|
- `letsencrypt_data` - SSL certificates
|
||||||
|
|
||||||
|
**Important**: The backup destination path must be accessible from the container. For HiDrive, ensure the mount point exists on the host and is properly mounted before starting the backup service.
|
||||||
|
|
||||||
## Important Environment Variables
|
## Important Environment Variables
|
||||||
|
|
||||||
Key variables defined in `arty.yml` and overridden in `.env`:
|
Key variables defined in `arty.yml` and overridden in `.env`:
|
||||||
@@ -218,6 +247,7 @@ Each service uses named volumes prefixed with project name:
|
|||||||
- `n8n_n8n_data`: n8n workflow data
|
- `n8n_n8n_data`: n8n workflow data
|
||||||
- `stash_filestash_data`: Filestash configuration and state
|
- `stash_filestash_data`: Filestash configuration and state
|
||||||
- `links_data`, `links_meili_data`: Linkwarden bookmarks and Meilisearch index
|
- `links_data`, `links_meili_data`: Linkwarden bookmarks and Meilisearch index
|
||||||
|
- `restic_data`, `restic_config`, `restic_cache`, `restic_tmp`: Backrest backup system
|
||||||
- `proxy_letsencrypt_data`: SSL certificates
|
- `proxy_letsencrypt_data`: SSL certificates
|
||||||
|
|
||||||
Volumes can be inspected with:
|
Volumes can be inspected with:
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ The **Falcon** is a state-of-the-art containerized starship, powered by Docker's
|
|||||||
| **N8N** | *Automated workflow command center* | [n8n.pivoine.art](https://n8n.pivoine.art) |
|
| **N8N** | *Automated workflow command center* | [n8n.pivoine.art](https://n8n.pivoine.art) |
|
||||||
| **STASH** | *Universal file management portal* | [stash.pivoine.art](https://stash.pivoine.art) |
|
| **STASH** | *Universal file management portal* | [stash.pivoine.art](https://stash.pivoine.art) |
|
||||||
| **LINKS** | *Interstellar bookmark archive* | [links.pivoine.art](https://links.pivoine.art) |
|
| **LINKS** | *Interstellar bookmark archive* | [links.pivoine.art](https://links.pivoine.art) |
|
||||||
|
| **RESTIC** | *Automated backup vault system* | [restic.pivoine.art](https://restic.pivoine.art) |
|
||||||
| **PROXY** | *Shield control dashboard* | [proxy.pivoine.art](https://proxy.pivoine.art) |
|
| **PROXY** | *Shield control dashboard* | [proxy.pivoine.art](https://proxy.pivoine.art) |
|
||||||
| **VPN** | *Cloaking device network* | [vpn.pivoine.art](https://vpn.pivoine.art) |
|
| **VPN** | *Cloaking device network* | [vpn.pivoine.art](https://vpn.pivoine.art) |
|
||||||
|
|
||||||
@@ -74,6 +75,11 @@ The **Falcon** is a state-of-the-art containerized starship, powered by Docker's
|
|||||||
├─────────────────────────────────────────────────┤
|
├─────────────────────────────────────────────────┤
|
||||||
│ ⚡ REDIS CACHE HYPERDRIVE │
|
│ ⚡ REDIS CACHE HYPERDRIVE │
|
||||||
│ └─ Warp-speed data acceleration │
|
│ └─ Warp-speed data acceleration │
|
||||||
|
├─────────────────────────────────────────────────┤
|
||||||
|
│ 🔐 BACKREST BACKUP VAULT (Restic) │
|
||||||
|
│ ├─ Automated volume snapshots │
|
||||||
|
│ ├─ Incremental backup engine │
|
||||||
|
│ └─ HiDrive remote repository │
|
||||||
└─────────────────────────────────────────────────┘
|
└─────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -172,6 +178,7 @@ THE FALCON (falcon_network)
|
|||||||
│ ├─ n8n Workflows [n8n.pivoine.art]
|
│ ├─ n8n Workflows [n8n.pivoine.art]
|
||||||
│ ├─ Filestash Files [stash.pivoine.art]
|
│ ├─ Filestash Files [stash.pivoine.art]
|
||||||
│ ├─ Linkwarden Marks [links.pivoine.art]
|
│ ├─ Linkwarden Marks [links.pivoine.art]
|
||||||
|
│ ├─ Backrest Backups [restic.pivoine.art]
|
||||||
│ └─ WireGuard VPN [vpn.pivoine.art]
|
│ └─ WireGuard VPN [vpn.pivoine.art]
|
||||||
│
|
│
|
||||||
└─ 💾 STORAGE VOLUMES
|
└─ 💾 STORAGE VOLUMES
|
||||||
@@ -185,6 +192,8 @@ THE FALCON (falcon_network)
|
|||||||
├─ filestash_data → File manager state
|
├─ filestash_data → File manager state
|
||||||
├─ linkwarden_data → Bookmark archives
|
├─ linkwarden_data → Bookmark archives
|
||||||
├─ meili_data → Search index database
|
├─ meili_data → Search index database
|
||||||
|
├─ backrest_data → Backup system state
|
||||||
|
├─ backrest_config → Backup configurations
|
||||||
└─ letsencrypt_data → Shield certificates
|
└─ letsencrypt_data → Shield certificates
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
7
arty.yml
7
arty.yml
@@ -87,6 +87,13 @@ envs:
|
|||||||
LINKS_DB_NAME: linkwarden
|
LINKS_DB_NAME: linkwarden
|
||||||
LINKS_MEILI_IMAGE: getmeili/meilisearch:v1.12.8
|
LINKS_MEILI_IMAGE: getmeili/meilisearch:v1.12.8
|
||||||
LINKS_MEILI_NO_ANALYTICS: true
|
LINKS_MEILI_NO_ANALYTICS: true
|
||||||
|
# Restic
|
||||||
|
RESTIC_TRAEFIK_ENABLED: true
|
||||||
|
RESTIC_COMPOSE_PROJECT_NAME: restic
|
||||||
|
RESTIC_IMAGE: garethgeorge/backrest:latest
|
||||||
|
RESTIC_TRAEFIK_HOST: restic.pivoine.art
|
||||||
|
RESTIC_HOSTNAME: falcon
|
||||||
|
RESTIC_BACKUP_PATH: /mnt/hidrive/users/valknar/Backup
|
||||||
# Proxy
|
# Proxy
|
||||||
PROXY_COMPOSE_PROJECT_NAME: proxy
|
PROXY_COMPOSE_PROJECT_NAME: proxy
|
||||||
PROXY_DOCKER_IMAGE: traefik:latest
|
PROXY_DOCKER_IMAGE: traefik:latest
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ include:
|
|||||||
- n8n/compose.yaml
|
- n8n/compose.yaml
|
||||||
- stash/compose.yaml
|
- stash/compose.yaml
|
||||||
- links/compose.yaml
|
- links/compose.yaml
|
||||||
|
- restic/compose.yaml
|
||||||
- umami/compose.yaml
|
- umami/compose.yaml
|
||||||
- sablier/compose.yaml
|
- sablier/compose.yaml
|
||||||
- proxy/compose.yaml
|
- proxy/compose.yaml
|
||||||
|
|||||||
111
restic/compose.yaml
Normal file
111
restic/compose.yaml
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
services:
|
||||||
|
backrest:
|
||||||
|
image: ${RESTIC_IMAGE:-garethgeorge/backrest:latest}
|
||||||
|
container_name: ${RESTIC_COMPOSE_PROJECT_NAME}_app
|
||||||
|
restart: unless-stopped
|
||||||
|
hostname: ${RESTIC_HOSTNAME:-falcon}
|
||||||
|
volumes:
|
||||||
|
# Backrest application data
|
||||||
|
- backrest_data:/data
|
||||||
|
- backrest_config:/config
|
||||||
|
- backrest_cache:/cache
|
||||||
|
- backrest_tmp:/tmp
|
||||||
|
|
||||||
|
# Backup destination
|
||||||
|
- ${RESTIC_BACKUP_PATH:-/mnt/hidrive/users/valknar/Backup}:/repos
|
||||||
|
|
||||||
|
# Docker volumes to backup (read-only)
|
||||||
|
- core_postgres_data:/volumes/core_postgres_data:ro
|
||||||
|
- core_redis_data:/volumes/core_redis_data:ro
|
||||||
|
- directus_uploads:/volumes/directus_uploads:ro
|
||||||
|
- directus_bundle:/volumes/directus_bundle:ro
|
||||||
|
- awesome_data:/volumes/awesome_data:ro
|
||||||
|
- gotify_data:/volumes/gotify_data:ro
|
||||||
|
- scrapyd_data:/volumes/scrapyd_data:ro
|
||||||
|
- scrapy_code:/volumes/scrapy_code:ro
|
||||||
|
- n8n_data:/volumes/n8n_data:ro
|
||||||
|
- filestash_data:/volumes/filestash_data:ro
|
||||||
|
- linkwarden_data:/volumes/linkwarden_data:ro
|
||||||
|
- linkwarden_meili_data:/volumes/linkwarden_meili_data:ro
|
||||||
|
- letsencrypt_data:/volumes/letsencrypt_data:ro
|
||||||
|
|
||||||
|
environment:
|
||||||
|
TZ: ${TIMEZONE:-Europe/Berlin}
|
||||||
|
BACKREST_DATA: /data
|
||||||
|
BACKREST_CONFIG: /config/config.json
|
||||||
|
XDG_CACHE_HOME: /cache
|
||||||
|
TMPDIR: /tmp
|
||||||
|
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
|
||||||
|
labels:
|
||||||
|
- 'traefik.enable=${RESTIC_TRAEFIK_ENABLED}'
|
||||||
|
- 'traefik.http.middlewares.${RESTIC_COMPOSE_PROJECT_NAME}-redirect-web-secure.redirectscheme.scheme=https'
|
||||||
|
- 'traefik.http.routers.${RESTIC_COMPOSE_PROJECT_NAME}-web.middlewares=${RESTIC_COMPOSE_PROJECT_NAME}-redirect-web-secure'
|
||||||
|
- 'traefik.http.routers.${RESTIC_COMPOSE_PROJECT_NAME}-web.rule=Host(`${RESTIC_TRAEFIK_HOST}`)'
|
||||||
|
- 'traefik.http.routers.${RESTIC_COMPOSE_PROJECT_NAME}-web.entrypoints=web'
|
||||||
|
- 'traefik.http.routers.${RESTIC_COMPOSE_PROJECT_NAME}-web-secure.rule=Host(`${RESTIC_TRAEFIK_HOST}`)'
|
||||||
|
- 'traefik.http.routers.${RESTIC_COMPOSE_PROJECT_NAME}-web-secure.tls.certresolver=resolver'
|
||||||
|
- 'traefik.http.routers.${RESTIC_COMPOSE_PROJECT_NAME}-web-secure.entrypoints=web-secure'
|
||||||
|
- 'traefik.http.middlewares.${RESTIC_COMPOSE_PROJECT_NAME}-web-secure-compress.compress=true'
|
||||||
|
- 'traefik.http.routers.${RESTIC_COMPOSE_PROJECT_NAME}-web-secure.middlewares=${RESTIC_COMPOSE_PROJECT_NAME}-web-secure-compress'
|
||||||
|
- 'traefik.http.services.${RESTIC_COMPOSE_PROJECT_NAME}-web-secure.loadbalancer.server.port=9898'
|
||||||
|
- 'traefik.docker.network=${NETWORK_NAME}'
|
||||||
|
- 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}'
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
backrest_data:
|
||||||
|
name: ${RESTIC_COMPOSE_PROJECT_NAME}_data
|
||||||
|
backrest_config:
|
||||||
|
name: ${RESTIC_COMPOSE_PROJECT_NAME}_config
|
||||||
|
backrest_cache:
|
||||||
|
name: ${RESTIC_COMPOSE_PROJECT_NAME}_cache
|
||||||
|
backrest_tmp:
|
||||||
|
name: ${RESTIC_COMPOSE_PROJECT_NAME}_tmp
|
||||||
|
|
||||||
|
# External volumes from other stacks (read-only mounts)
|
||||||
|
core_postgres_data:
|
||||||
|
name: core_postgres_data
|
||||||
|
external: true
|
||||||
|
core_redis_data:
|
||||||
|
name: core_redis_data
|
||||||
|
external: true
|
||||||
|
directus_uploads:
|
||||||
|
name: core_directus_uploads
|
||||||
|
external: true
|
||||||
|
directus_bundle:
|
||||||
|
name: core_directus_bundle
|
||||||
|
external: true
|
||||||
|
awesome_data:
|
||||||
|
name: awesome_data
|
||||||
|
external: true
|
||||||
|
gotify_data:
|
||||||
|
name: messaging_data
|
||||||
|
external: true
|
||||||
|
scrapyd_data:
|
||||||
|
name: scrapy_scrapyd_data
|
||||||
|
external: true
|
||||||
|
scrapy_code:
|
||||||
|
name: scrapy_scrapy_code
|
||||||
|
external: true
|
||||||
|
n8n_data:
|
||||||
|
name: n8n_n8n_data
|
||||||
|
external: true
|
||||||
|
filestash_data:
|
||||||
|
name: stash_filestash_data
|
||||||
|
external: true
|
||||||
|
linkwarden_data:
|
||||||
|
name: links_data
|
||||||
|
external: true
|
||||||
|
linkwarden_meili_data:
|
||||||
|
name: links_meili_data
|
||||||
|
external: true
|
||||||
|
letsencrypt_data:
|
||||||
|
name: proxy_letsencrypt_data
|
||||||
|
external: true
|
||||||
|
|
||||||
|
networks:
|
||||||
|
compose_network:
|
||||||
|
name: ${NETWORK_NAME}
|
||||||
|
external: true
|
||||||
Reference in New Issue
Block a user