2 Commits
Author SHA1 Message Date
deytenit 53d3bedca6 feat: add resticontainer backup labels for traefik/adguard/xray
Per the "Core Apex (all nodes)" policy: traefik /etc/traefik/dynamic,
adguard /opt/adguardhome/conf, xray /etc/xray/config.jsonc. Profile-gated
services are only discovered on nodes that run them.
2026-07-07 21:38:25 +03:00
deytenit c100db57fe fix: mount /srv in resticontainer so absolute tierN symlinks resolve
The tierN bind mounts are absolute symlinks into /srv (compositions/<p>/tierN ->
/srv/com-*-tierN/<p>). Under /:/hostfs those targets are dangling inside the
container (restic reported "does not exist, skipping" for every path). Mount
/srv:/srv:ro at the same path with RESTIC_HOSTFS=/ so restic follows the
symlinks and records the real host paths.
2026-07-07 21:15:15 +03:00
2 changed files with 26 additions and 8 deletions

No files matched your search

+4 -3
View File
@@ -65,9 +65,10 @@ action to its bash source and the behaviors that must match.
`restic.*` compose labels: `restic.enable`, `restic.backup.paths` (comma-separated
container mount destinations — matched exactly, whole mount dir backed up),
`restic.backup.stop`, and `restic.hooks.pre-backup`/`post-backup` (run via docker exec).
- It mounts the docker socket (list/inspect/exec/stop/start) and the host root
`/:/hostfs:ro` (`RESTIC_HOSTFS=/hostfs`); it resolves each labelled mount to
`/hostfs` + the mount's host source and snapshots the union in one restic run.
- It mounts the docker socket (list/inspect/exec/stop/start) and `/srv:/srv:ro`
(`RESTIC_HOSTFS=/`); apex data + checkouts live under /srv and the `@tierN` mounts
are absolute symlinks into /srv, so mounting /srv at the same path lets restic
follow them and record the real host paths, and snapshots the union in one run.
- The whole-tier-root RO mounts and the explicit `/data/@tier1,2` backup args are gone;
a service is backed up only if it carries `restic.enable=true`. DB consistency is
per-service: a pre-backup hook dumps into a dedicated backed-up mount (e.g. postgres
+22 -5
View File
@@ -23,6 +23,10 @@ services:
command: ["-c", "/etc/xray/config.jsonc"]
restart: unless-stopped
user: "0:0"
labels:
# backup (resticontainer, core/all-nodes): xray config only (logs + shm are ephemeral)
- "restic.enable=true"
- "restic.backup.paths=/etc/xray/config.jsonc"
security_opt:
- no-new-privileges:true
@@ -32,11 +36,11 @@ services:
# (restic.enable / restic.backup.paths / restic.backup.stop / restic.hooks.*).
# On `backup` it queries the docker daemon, runs each service's pre-hook (e.g.
# pg_dump), stops any container flagged restic.backup.stop, resolves the labeled
# container mounts to host paths (via /hostfs + mount source), snapshots the union
# container mounts to host paths (via the /srv mount), snapshots the union
# in a single restic run, then restarts + runs post-hooks. Every other subcommand
# (init/snapshots/forget/…) passes straight through to restic. Needs the docker
# socket (list/inspect/exec/stop/start) and the host root read-only (to read the
# data) — a privileged manual one-shot, same trust surface as the old restic core.
# socket (list/inspect/exec/stop/start) and /srv read-only (the fleet's data root)
# — a privileged manual one-shot, same trust surface as the old restic core.
resticontainer:
image: ghcr.io/deytenit/resticontainer:0.19.1
container_name: apex-resticontainer
@@ -44,10 +48,15 @@ services:
volumes:
- ${APEX_TIER3}/restic/cache:/var/restic-cache
- /var/run/docker.sock:/var/run/docker.sock # query + exec/stop/start
- /:/hostfs:ro # read the data off the host
# apex tier data + checkouts live under /srv, and the @tierN bind mounts are
# ABSOLUTE symlinks into /srv (compositions/<p>/@tierN -> /srv/com-…-tierN/<p>).
# Mount /srv at the same path with RESTIC_HOSTFS=/ so restic follows those
# symlinks and records the real host paths — a bare /:/hostfs cannot, because
# the absolute symlink target /srv/… is dangling inside the container.
- /srv:/srv:ro # read the data (resolves @tierN symlinks)
environment:
<<: *shared-environment
RESTIC_HOSTFS: /hostfs # prefix for resolved mount sources
RESTIC_HOSTFS: "/" # mount sources are already absolute (/srv/…)
RESTIC_REPOSITORY: "${APEX_RESTIC_REPOSITORY?error}"
RESTIC_PASSWORD: "${APEX_RESTIC_PASSWORD?error}"
AWS_ACCESS_KEY_ID: "${APEX_RESTIC_AWS_ACCESS_KEY_ID?error}"
@@ -139,6 +148,10 @@ services:
- "traefik.http.middlewares.apex-adguard-strip-prefix.stripprefix.prefixes=/adguard"
- "traefik.http.routers.apex-adguard.service=apex-adguard"
- "traefik.http.services.apex-adguard.loadbalancer.server.port=3000"
# backup (resticontainer, core/all-nodes): dynamic routing rules only
# (letsencrypt certs are regenerable via ACME/Cloudflare DNS-01)
- "restic.enable=true"
- "restic.backup.paths=/etc/traefik/dynamic"
security_opt:
- no-new-privileges:true
@@ -152,6 +165,10 @@ services:
- ${APEX_TIER1}/adguard/conf:/opt/adguardhome/conf
environment:
<<: *shared-environment
labels:
# backup (resticontainer, core/all-nodes): adguard config only (work data regenerable)
- "restic.enable=true"
- "restic.backup.paths=/opt/adguardhome/conf"
network_mode: "service:traefik"
restart: unless-stopped
cap_add: