added backup script
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
/data
|
/data
|
||||||
/config/media
|
/config/media
|
||||||
|
scripts/restic-backup.env
|
||||||
84
README.md
84
README.md
@@ -81,3 +81,87 @@ docker compose -f stacks/media/compose.yaml down
|
|||||||
| **Storage** | | |
|
| **Storage** | | |
|
||||||
| Gitea | 3000, 222 | storage |
|
| Gitea | 3000, 222 | storage |
|
||||||
| Copyparty | 3923 | storage |
|
| Copyparty | 3923 | storage |
|
||||||
|
|
||||||
|
## Backup
|
||||||
|
|
||||||
|
Backups use [Restic](https://restic.net/). The script backs up `/srv/homelab` (including `data/`), `/etc/caddy/Caddyfile`, and `/etc/unbound/unbound.conf`. It **stops all Docker stacks** before backup for consistent data, then starts them again—run it manually when you can afford a few minutes of downtime.
|
||||||
|
|
||||||
|
### One-time setup
|
||||||
|
|
||||||
|
1. Install restic (e.g. `pacman -S restic` or from [restic.net](https://restic.net/)).
|
||||||
|
|
||||||
|
2. Copy the env example and set repository and password:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp scripts/restic-backup.env.example scripts/restic-backup.env
|
||||||
|
# Edit scripts/restic-backup.env: set RESTIC_REPOSITORY and RESTIC_PASSWORD
|
||||||
|
```
|
||||||
|
|
||||||
|
Examples for `RESTIC_REPOSITORY`:
|
||||||
|
- Local: `RESTIC_REPOSITORY=/backup/restic`
|
||||||
|
- SFTP: `RESTIC_REPOSITORY=sftp:user@backup-host:/restic`
|
||||||
|
- S3: `RESTIC_REPOSITORY=s3:s3.amazonaws.com/bucket-name`
|
||||||
|
|
||||||
|
3. Initialize the repo (once):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export RESTIC_PASSWORD='your-password'
|
||||||
|
restic -r /backup/restic init # use your actual repo path
|
||||||
|
```
|
||||||
|
|
||||||
|
### Create a backup
|
||||||
|
|
||||||
|
From the repo root, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ./scripts/restic-backup.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Stacks are stopped, then the backup runs, then they are started again. A failed backup still triggers the start so the homelab comes back up.
|
||||||
|
|
||||||
|
### Inspect backups
|
||||||
|
|
||||||
|
List snapshots (IDs and timestamps):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
source scripts/restic-backup.env
|
||||||
|
sudo restic snapshots -r $RESTIC_REPOSITORY
|
||||||
|
```
|
||||||
|
|
||||||
|
List files in a snapshot (e.g. latest or by ID):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
restic ls latest -r $RESTIC_REPOSITORY
|
||||||
|
restic ls -r $RESTIC_REPOSITORY <snapshot-id>
|
||||||
|
```
|
||||||
|
|
||||||
|
Browse a path inside a snapshot:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
restic ls latest -r $RESTIC_REPOSITORY /srv/homelab/config
|
||||||
|
```
|
||||||
|
|
||||||
|
### See diffs between backups
|
||||||
|
|
||||||
|
Compare two snapshots (added, changed, removed files and content diff):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
restic diff <older-snapshot-id> <newer-snapshot-id> -r $RESTIC_REPOSITORY
|
||||||
|
```
|
||||||
|
|
||||||
|
### Restore
|
||||||
|
|
||||||
|
Restore the latest snapshot into a directory (does not overwrite the repo; use a separate target dir):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
restic restore latest --target /tmp/restore -r $RESTIC_REPOSITORY
|
||||||
|
```
|
||||||
|
|
||||||
|
Restore a specific snapshot or path:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
restic restore <snapshot-id> --target /tmp/restore -r $RESTIC_REPOSITORY
|
||||||
|
restic restore latest --path /etc/caddy --target /tmp/restore -r $RESTIC_REPOSITORY
|
||||||
|
```
|
||||||
|
|
||||||
|
After restore, fix ownership on `data/` if needed (see [Monitoring permissions](#2-monitoring-permissions)).
|
||||||
|
|||||||
12
scripts/restic-backup.env.example
Normal file
12
scripts/restic-backup.env.example
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# Copy to restic-backup.env and set values.
|
||||||
|
# restic-backup.env is not committed (add to .gitignore if needed).
|
||||||
|
|
||||||
|
# Repository: local path, sftp, rclone, or S3-compatible.
|
||||||
|
# Examples:
|
||||||
|
# RESTIC_REPOSITORY=/backup/restic
|
||||||
|
# RESTIC_REPOSITORY=sftp:user@backup-host:/restic
|
||||||
|
# RESTIC_REPOSITORY=s3:s3.amazonaws.com/bucket-name
|
||||||
|
export RESTIC_REPOSITORY=""
|
||||||
|
|
||||||
|
# Repository password (used for encryption).
|
||||||
|
export RESTIC_PASSWORD=""
|
||||||
57
scripts/restic-backup.sh
Executable file
57
scripts/restic-backup.sh
Executable file
@@ -0,0 +1,57 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
ENV_FILE="${SCRIPT_DIR}/restic-backup.env"
|
||||||
|
HOMELAB_ROOT="/srv/homelab"
|
||||||
|
STACKS_STOPPED=false
|
||||||
|
|
||||||
|
start_stacks() {
|
||||||
|
if [[ "$STACKS_STOPPED" != true ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
echo "Starting Docker stacks..."
|
||||||
|
cd "$HOMELAB_ROOT"
|
||||||
|
docker compose -f stacks/media/compose.yaml up -d
|
||||||
|
docker compose -f stacks/monitoring/compose.yaml up -d
|
||||||
|
docker compose -f stacks/storage/compose.yaml up -d
|
||||||
|
echo "Stacks started."
|
||||||
|
}
|
||||||
|
trap start_stacks EXIT
|
||||||
|
|
||||||
|
if [[ -f "$ENV_FILE" ]]; then
|
||||||
|
set -a
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
source "$ENV_FILE"
|
||||||
|
set +a
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "${RESTIC_REPOSITORY:-}" ]]; then
|
||||||
|
echo "Error: RESTIC_REPOSITORY is not set. Create ${ENV_FILE} or export it." >&2
|
||||||
|
echo "Example: RESTIC_REPOSITORY=sftp:user@host:/backups/restic" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "${RESTIC_PASSWORD:-}" ]]; then
|
||||||
|
echo "Error: RESTIC_PASSWORD is not set. Create ${ENV_FILE} or export it." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
CADDYFILE="/etc/caddy/Caddyfile"
|
||||||
|
UNBOUND_CONF="/etc/unbound/unbound.conf"
|
||||||
|
|
||||||
|
echo "Stopping Docker stacks..."
|
||||||
|
cd "$HOMELAB_ROOT"
|
||||||
|
docker compose -f stacks/media/compose.yaml down
|
||||||
|
docker compose -f stacks/monitoring/compose.yaml down
|
||||||
|
docker compose -f stacks/storage/compose.yaml down
|
||||||
|
STACKS_STOPPED=true
|
||||||
|
|
||||||
|
echo "Starting restic backup..."
|
||||||
|
restic backup \
|
||||||
|
"$HOMELAB_ROOT" \
|
||||||
|
"$CADDYFILE" \
|
||||||
|
"$UNBOUND_CONF"
|
||||||
|
|
||||||
|
echo "Backup finished. Snapshot list:"
|
||||||
|
restic snapshots --latest 5
|
||||||
Reference in New Issue
Block a user