Compare commits

..

3 Commits

Author SHA1 Message Date
192972b624 changed domain 2026-02-26 03:10:13 +03:00
9c0a3c19f6 added backup script 2026-02-25 01:47:35 +03:00
9f36a48864 upd loki conf 2026-02-25 01:02:08 +03:00
14 changed files with 215 additions and 50 deletions

3
.gitignore vendored
View File

@@ -1,2 +1,3 @@
/data
/config/media
/config/media
scripts/restic-backup.env

View File

@@ -81,3 +81,87 @@ docker compose -f stacks/media/compose.yaml down
| **Storage** | | |
| Gitea | 3000, 222 | 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)).

View File

@@ -42,43 +42,43 @@ pages:
- same-tab: true
links:
- title: Jellyfin
url: https://jellyfin.home
url: https://jellyfin.internal
icon: mdi:television-play
- title: Seer
url: https://jellyseerr.home
url: https://seerr.internal
icon: mdi:movie-search
- title: Radarr
url: https://radarr.home
url: https://radarr.internal
icon: mdi:film
- title: Sonarr
url: https://sonarr.home
url: https://sonarr.internal
icon: mdi:television
- title: Lidarr
url: https://lidarr.home
url: https://lidarr.internal
icon: mdi:music
- title: Prowlarr
url: https://prowlarr.home
url: https://prowlarr.internal
icon: mdi:radar
- title: qBittorrent
url: https://qbit.home
url: https://qbit.internal
icon: mdi:download
- title: Portainer
url: https://portainer.home
url: https://portainer.internal
icon: mdi:docker
- title: Immich
url: https://photo.home
url: https://photo.internal
icon: mdi:image-multiple
- title: Navidrome
url: https://music.home
url: https://music.internal
icon: mdi:music-box-multiple
- title: CopyParty
url: https://copyparty.home
url: https://copyparty.internal
icon: mdi:folder-multiple
- title: Gitea
url: https://git.home
url: https://git.internal
icon: mdi:git
- title: Grafana
url: https://grafana.home
url: https://grafana.internal
icon: mdi:chart-line
- name: Media
columns:

View File

@@ -19,50 +19,50 @@
title: Service status
sites:
- title: Jellyfin
url: https://jellyfin.home
url: https://jellyfin.internal
icon: mdi:television-play
- title: Seer
url: https://jellyseerr.home
url: https://seerr.internal
icon: mdi:movie-search
- title: Radarr
url: https://radarr.home
url: https://radarr.internal
icon: mdi:film
- title: Sonarr
url: https://sonarr.home
url: https://sonarr.internal
icon: mdi:television
- title: Lidarr
url: https://lidarr.home
url: https://lidarr.internal
icon: mdi:music
- title: Prowlarr
url: https://prowlarr.home
url: https://prowlarr.internal
icon: mdi:radar
- title: qBittorrent
url: https://qbit.home
url: https://qbit.internal
icon: mdi:download
- title: Portainer
url: https://portainer.home
url: https://portainer.internal
icon: mdi:docker
- title: Immich
url: https://photo.home
url: https://photo.internal
icon: mdi:image-multiple
- title: Navidrome
url: https://music.home
url: https://music.internal
icon: mdi:music-box-multiple
- title: CopyParty
url: https://copyparty.home
url: https://copyparty.internal
icon: mdi:folder-multiple
- title: Gitea
url: https://git.home
url: https://git.internal
icon: mdi:git
- title: Grafana
url: https://grafana.home
url: https://grafana.internal
icon: mdi:chart-line
- type: docker-containers
title: Docker
show-stats: true
- type: custom-api
title: Portainer
title-url: https://portainer.home
title-url: https://portainer.internal
cache: 1h
url: ${PORTAINER_URL}/api/endpoints/${PORTAINER_ENDPOINT_ID}
headers:

View File

@@ -2,26 +2,26 @@
title: Media
sites:
- title: Jellyfin
url: https://jellyfin.home
url: https://jellyfin.internal
icon: mdi:television-play
- title: Jellyseerr
url: https://jellyseerr.home
- title: seerr
url: https://seerr.internal
icon: mdi:movie-search
- title: Radarr
url: https://radarr.home
url: https://radarr.internal
icon: mdi:film
- title: Sonarr
url: https://sonarr.home
url: https://sonarr.internal
icon: mdi:television
- title: Lidarr
url: https://lidarr.home
url: https://lidarr.internal
icon: mdi:music
- title: Prowlarr
url: https://prowlarr.home
url: https://prowlarr.internal
icon: mdi:radar
- title: qBittorrent
url: https://qbit.home
url: https://qbit.internal
icon: mdi:download
- title: TorrServe
url: https://torrserve.home
url: https://torrserve.internal
icon: mdi:server-network

View File

@@ -48,8 +48,5 @@ pattern_ingester:
metric_aggregation:
loki_address: localhost:3100
ruler:
alertmanager_url: http://localhost:9093
frontend:
encoding: protobuf

View File

@@ -21,4 +21,4 @@ scrape_configs:
tls_config:
insecure_skip_verify: true
static_configs:
- targets: ["metrics.home:443"]
- targets: ["metrics.internal:443"]

View 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
View 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

View File

@@ -7,3 +7,4 @@ include:
- ./seer.yaml
- ./navidrome.yaml
- ./immich.yaml
- ./plex.yaml

13
stacks/media/plex.yaml Normal file
View File

@@ -0,0 +1,13 @@
version: '2'
services:
plex:
container_name: plex
image: plexinc/pms-docker
restart: unless-stopped
environment:
- TZ=Europe/Moscow
network_mode: host
volumes:
- /srv/homelab/config/media/plex:/config
- /tmp/plex:/transcode
- /srv/media:/data

View File

@@ -4,19 +4,19 @@
MY_SECRET_TOKEN=123456
# *arr stack API base URL and key (http from container)
RADARR_URL=http://radarr.home
RADARR_API_URL=http://radarr.home
RADARR_URL=http://radarr.internal
RADARR_API_URL=http://radarr.internal
RADARR_KEY=512cab3acfe84420957a9c8585560f8f
SONARR_URL=http://sonarr.home
SONARR_API_URL=http://sonarr.home
SONARR_URL=http://sonarr.internal
SONARR_API_URL=http://sonarr.internal
SONARR_KEY=b3a84ef407ca42d99f5bc22fb8afc401
LIDARR_URL=http://lidarr.home
LIDARR_API_URL=http://lidarr.home
LIDARR_URL=http://lidarr.internal
LIDARR_API_URL=http://lidarr.internal
LIDARR_KEY=e0862cb9aa8c4c0f8115ec794c5bebc1
# Portainer (Settings → API → Enable API; endpoint ID from URL e.g. !#/2/docker → 2)
PORTAINER_URL=http://portainer.home
PORTAINER_URL=http://portainer.internal
PORTAINER_ENDPOINT_ID=3
PORTAINER_API_KEY=ptr_zmLlSaAbw8nQRoJlDRb006IDVtJLojneToSVNWJxo3c=

View File

@@ -30,7 +30,7 @@ services:
image: prom/prometheus:latest
container_name: prometheus
extra_hosts:
- "metrics.home:192.168.1.70"
- "metrics.internal:192.168.1.70"
ports:
- "9094:9090"
volumes:

View File

@@ -10,7 +10,7 @@ services:
- "9443:9443"
- "8000:8000"
environment:
- TRUSTED_ORIGINS=portainer.home
- TRUSTED_ORIGINS=portainer.internal
logging:
driver: json-file
options: