95 lines
3.1 KiB
Markdown
95 lines
3.1 KiB
Markdown
---
|
|
id: deploy/systemd-and-container
|
|
name: Create systemd unit file, Dockerfile, and docker-compose.yml for production deployment
|
|
status: complete
|
|
depends_on: [ops/signals-and-shutdown]
|
|
scope: moderate
|
|
risk: low
|
|
impact: component
|
|
level: implementation
|
|
---
|
|
|
|
## Description
|
|
|
|
Create the deployment artifacts: systemd unit file, Dockerfile, and docker-compose.yml template.
|
|
|
|
### Systemd Unit File
|
|
|
|
```ini
|
|
[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:alpine` → `alpine`/`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 |