Files
restic-manager/deploy/docker-compose.yml
steve e8913943f9 p5-07: reference deployment (server-only compose + reverse-proxy docs)
The reverse proxy is assumed to live outside this project (Caddy,
nginx, Traefik, whatever the operator already runs). The reference
compose stands up only the server: image-pinned via RM_VERSION,
named volume for operator state, localhost-bound so the proxy
reaches it on loopback.

docs/reverse-proxy.md covers what the proxy must forward — the
X-Forwarded-* headers, Host, and Connection: upgrade for the agent
WebSocket and live-log streams — plus the RM_TRUSTED_PROXY CIDR
rule that gates header trust. Worked examples for Caddy, nginx
(with the websocket upgrade map + 1h proxy_read_timeout for live
logs), and Traefik.
2026-05-05 17:15:00 +01:00

53 lines
2.2 KiB
YAML

# Reference deployment for the restic-manager control plane.
# Mirrors spec.md §10.1 and the P5-07 reference deployment.
#
# Scope: this compose stands up the server only. TLS termination and
# the public hostname belong to a reverse proxy that lives outside
# this stack (Caddy, Traefik, nginx, HAProxy, your existing edge —
# whatever you already operate). See `docs/reverse-proxy.md` for the
# headers + CIDRs that proxy needs to forward.
#
# Architecture:
# * The server speaks plain HTTP on :8080.
# * The agent binaries + install scripts ship inside the image under
# /opt/restic-manager/dist/, so /agent/binary and /install/*
# serve out of the box without first-run staging.
# * The named volume holds *only* operator state (sqlite,
# secrets.enc, audit log, the AEAD key). Image upgrades replace
# the agents/scripts; the volume is untouched.
# * Pre-1.0 releases never publish :latest — pin to an exact
# vX.Y.Z tag and bump deliberately.
#
# Before first start:
# 1. Pick a version: export RM_VERSION=vX.Y.Z (or substitute below).
# 2. Set RM_BASE_URL to the public HTTPS URL the external proxy
# serves on.
# 3. Set RM_TRUSTED_PROXY to the IP/CIDR the proxy connects from
# (the X-Forwarded-* headers are honoured only when the immediate
# peer matches one of these).
services:
restic-manager:
image: gitea.dcglab.co.uk/steve/restic-manager:${RM_VERSION:?set RM_VERSION to a vX.Y.Z tag}
restart: unless-stopped
# Bind to localhost only — your reverse proxy reaches the server
# over loopback (or, if it runs in a separate compose / on
# another host, swap this for an internal docker network or a
# private LAN bind).
ports:
- "127.0.0.1:8080:8080"
volumes:
- rm-data:/data
environment:
- RM_DATA_DIR=/data
- RM_LISTEN=:8080
- RM_BASE_URL=${RM_BASE_URL:?set RM_BASE_URL to the public https URL}
- RM_SECRET_KEY_FILE=/data/secret.key
- RM_TRUSTED_PROXY=${RM_TRUSTED_PROXY:?set RM_TRUSTED_PROXY to the proxy CIDR}
# Cookies are Secure by default; keep that. Override only for
# local-HTTP smoke tests.
# - RM_COOKIE_SECURE=true
volumes:
rm-data: