Files
reverse-proxy/tasks/deploy/systemd-and-container.md

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