server: drop in-process TLS — HTTP-only behind reverse proxy
Self-hosted deployments already terminate TLS at Caddy/Traefik/nginx; making the server do TLS too means double cert config, dual ACME plumbing, and an untested code path. Drop RM_TLS_CERT/RM_TLS_KEY, remove TLSEnabled() and the ListenAndServeTLS branch. Replace the cookie's "Secure if TLS-in-process" check with a new RM_COOKIE_SECURE flag (default true). Local HTTP-only testing sets RM_COOKIE_SECURE=false; production is always behind a TLS proxy and the cookie stays Secure. Default port :8443 → :8080. docker-compose binds 127.0.0.1 only and populates RM_TRUSTED_PROXY. spec.md §4.1/§10.1 rewritten with a Caddyfile snippet and a hard "do not expose RM_LISTEN publicly" warning. enrollResponse keeps cert_pin_sha256 in the shape but the server can't introspect a cert it doesn't terminate — operator pastes the proxy's hash into -cert-pin at install time. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -99,14 +99,20 @@ It is built for small-to-medium fleets (initial target: ~12 endpoints) and is in
|
||||
- **UI:** HTMX + Tailwind, server-rendered Go templates, no Node build step
|
||||
- **Distribution:** single static binary, packaged in a Docker image; published `docker-compose.yml`
|
||||
- **Config:** YAML or env vars:
|
||||
- `RM_LISTEN` — bind address, e.g. `:8443` (source of truth for the port;
|
||||
the `8443` in the reference compose is just a default mapping)
|
||||
- `RM_DATA_DIR`, `RM_BASE_URL`, `RM_TLS_CERT`, `RM_TLS_KEY`,
|
||||
`RM_SECRET_KEY_FILE`
|
||||
- `RM_LISTEN` — bind address, e.g. `:8080` (source of truth for the port;
|
||||
the `8080` in the reference compose is just a default mapping). Bind to
|
||||
`127.0.0.1:8080` when running behind a same-host proxy.
|
||||
- `RM_DATA_DIR`, `RM_BASE_URL`, `RM_SECRET_KEY_FILE`
|
||||
- `RM_TRUSTED_PROXY` — comma-separated CIDR list of reverse proxies
|
||||
whose `X-Forwarded-For` / `X-Forwarded-Proto` we honour. Empty (the
|
||||
default) = trust no one. Set this when fronted by Caddy/Traefik.
|
||||
- **TLS:** terminate TLS in-process (cert from Caddy/Traefik sidecar acceptable; agents require HTTPS)
|
||||
- `RM_COOKIE_SECURE` — `true` (default) marks session cookies `Secure`.
|
||||
Only set to `false` for local HTTP-only testing.
|
||||
- **TLS:** the server speaks plain HTTP and is **always** expected to sit
|
||||
behind a TLS-terminating reverse proxy (Caddy / Traefik / nginx). This
|
||||
keeps cert renewal, ACME, and SNI in the proxy where operators already
|
||||
manage it. Agents must reach the server over HTTPS; the cert pin
|
||||
(`cert_pin_sha256`) pins whatever cert the proxy serves.
|
||||
|
||||
### 4.2 Agent
|
||||
|
||||
@@ -371,6 +377,10 @@ Stack: HTMX + Tailwind + Go html/templates. No SPA framework. Server-rendered, p
|
||||
|
||||
### 10.1 Control plane (Proxmox host or LXC)
|
||||
|
||||
The server is HTTP-only by design — operators front it with their own
|
||||
TLS-terminating reverse proxy (Caddy / Traefik / nginx). Bind the
|
||||
container to localhost so the only public path is through the proxy.
|
||||
|
||||
`docker-compose.yml`:
|
||||
```yaml
|
||||
services:
|
||||
@@ -378,24 +388,34 @@ services:
|
||||
image: ghcr.io/<owner>/restic-manager:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8443:8443"
|
||||
- "127.0.0.1:8080:8080"
|
||||
volumes:
|
||||
- ./data:/data
|
||||
- ./certs:/certs:ro
|
||||
environment:
|
||||
- RM_DATA_DIR=/data
|
||||
- RM_LISTEN=:8443
|
||||
- RM_LISTEN=:8080
|
||||
- RM_BASE_URL=https://restic.lab.example
|
||||
- RM_TLS_CERT=/certs/fullchain.pem
|
||||
- RM_TLS_KEY=/certs/privkey.pem
|
||||
- RM_SECRET_KEY_FILE=/data/secret.key
|
||||
# - RM_TRUSTED_PROXY=10.0.0.0/8 # set when fronted by a reverse proxy
|
||||
- RM_TRUSTED_PROXY=172.16.0.0/12 # CIDR of your reverse proxy
|
||||
```
|
||||
|
||||
Reference Caddy snippet (operator's own Caddyfile, outside this repo):
|
||||
```
|
||||
restic.lab.example {
|
||||
encode zstd gzip
|
||||
reverse_proxy 127.0.0.1:8080
|
||||
}
|
||||
```
|
||||
Caddy provisions and renews the cert; the agent's `cert_pin_sha256`
|
||||
pins **Caddy's** leaf cert (that's what the agent actually sees).
|
||||
|
||||
`RM_LISTEN` is the source of truth for the server's bind address. The
|
||||
`8443:8443` mapping above is just the matching default; if you change
|
||||
`RM_LISTEN` to e.g. `:9443`, change the right-hand side of the port
|
||||
mapping to match.
|
||||
`8080:8080` mapping above is just the matching default; change both
|
||||
sides together if you pick a different port.
|
||||
|
||||
> ⚠️ Never expose `RM_LISTEN` directly on a public interface — the
|
||||
> server has no TLS, no rate limiting, and no DDoS protection. That
|
||||
> all belongs in the proxy.
|
||||
|
||||
### 10.2 Restic REST server (Unraid)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user