Files
reverse-proxy/tasks/deploy/systemd-and-container.md
glm-5.1 309878c561 Decompose architecture into 23 atomic tasks across 7 parallel generations
Task graph covers all Phase 1 concerns: config system, TLS termination,
proxy handler, operations (rate limiting, logging, health check, admin
socket, signals, shutdown, body size limit), deployment artifacts, and
two review checkpoints.

No circular dependencies. Critical path length of 7. Risk distribution:
3 high-risk (ACME, TLS listener setup, startup orchestration), 7 medium,
11 low, 2 trivial.
2026-06-11 11:21:10 +00:00

3.1 KiB

id, name, status, depends_on, scope, risk, impact, level
id name status depends_on scope risk impact level
deploy/systemd-and-container Create systemd unit file, Dockerfile, and docker-compose.yml for production deployment pending
ops/signals-and-shutdown
moderate low component implementation

Description

Create the deployment artifacts: systemd unit file, Dockerfile, and docker-compose.yml template.

Systemd Unit File

[Unit]
Description=Reverse Proxy
After=network.target
Wants=network-online.target

[Service]
Type=notify
NotifyAccess=all
ExecStart=/usr/local/bin/reverse-proxy --config /etc/reverse-proxy/config.toml
Restart=on-failure
RestartSec=5

# Security hardening
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
ReadWritePaths=/var/lib/reverse-proxy /var/log/reverse-proxy

# ACME challenge cache directory
StateDirectory=reverse-proxy

[Install]
WantedBy=multi-user.target

The proxy signals readiness to systemd via sd_notify("READY=1") after binding listeners and completing initial configuration load.

Dockerfile

Multi-stage build:

  • Build stage: rust:alpine with x86_64-unknown-linux-musl target for static linking
  • Run stage: alpine (or scratch for absolute minimum)
  • The aws_lc_rs crypto provider is statically linked — no OpenSSL dependency
  • Binary is self-contained, no runtime dependencies beyond libc for DNS resolution

Docker Compose Template

Example template showing:

  • Reverse proxy with volume mounts for config, ACME cache, logs, and admin socket
  • allow_wildcard_bind = true for container deployments
  • Health check using wget against local health endpoint
  • Network configuration for upstream services

Fail2ban Configuration

  • Filter definition matching the RATE_LIMIT log prefix
  • Jail configuration for rate-limiting offenders

Acceptance Criteria

  • Systemd unit file at deploy/reverse-proxy.service
  • Type=notify with sd_notify("READY=1") integration in binary
  • Security hardening directives in unit file
  • ReadWritePaths for ACME cache and log directory
  • Dockerfile with multi-stage build (rust:alpinealpine/scratch)
  • Static linking with x86_64-unknown-linux-musl target
  • Docker Compose template at deploy/docker-compose.yml
  • Volume mounts for config (ro), ACME cache (rw), logs (rw), admin socket (rw)
  • Health check in Docker Compose using wget against http://127.0.0.1:9900/health
  • Fail2ban filter definition at deploy/fail2ban/filter.d/reverse-proxy.conf
  • Fail2ban jail configuration at deploy/fail2ban/jail.d/reverse-proxy.conf
  • docker build succeeds
  • Container starts and responds to health check

References

  • docs/architecture/operations.md — systemd, container deployment, fail2ban, health check
  • docs/architecture/decisions/020-container-deployment.md — container model rationale

Notes

The Dockerfile should use musl for static linking. The aws_lc_rs crypto provider is statically linked. The resulting binary has no runtime dependencies beyond libc for DNS resolution (which musl provides).

Summary

To be filled on completion