Skip to content

Commit e35b731

Browse files
baijumclaude
andcommitted
docs: add server hardening section to server contract
Document the security measures applied by the bootstrap script (firewall, auto-updates, non-root deploy, credential isolation, resource limits) and explain why AppArmor is used instead of SELinux. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 14ad706 commit e35b731

1 file changed

Lines changed: 25 additions & 0 deletions

File tree

docs/server-contract.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,31 @@ All scripts live in the platform repo under `infrastructure/` and are copied to
103103
| `update-images.sh` | Pull latest Docker images and recreate containers | Cron: weekly Sunday at 03:00 |
104104
| `usage-report.sh` | Generate 6-section resource usage report | Manual (`bash`) |
105105

106+
## Server Hardening
107+
108+
The bootstrap script applies several security measures automatically. Self-hosters get these out of the box; no manual hardening steps are needed beyond running the bootstrap.
109+
110+
**Firewall** — UFW is configured to deny all incoming traffic except ports 22 (SSH), 80 (HTTP), and 443 (HTTPS). All other ports, including PostgreSQL (5432), Redis (6379), and MinIO (9000), are only reachable via the internal Docker network.
111+
112+
**Automatic security updates**`unattended-upgrades` is installed and configured for the Debian security channel. Security patches are applied automatically without manual intervention.
113+
114+
**Non-root deployment** — A `deploy` user with Docker group membership handles all deployments. Workflows SSH in as `deploy`, never as root. The deploy user cannot modify system packages or firewall rules.
115+
116+
**Credential isolation** — The platform `.env` file is mode 600 (readable only by its owner). Per-app credentials are generated by `create-app-credentials.sh` and stored in separate files under `/opt/platform/credentials/`, each also mode 600.
117+
118+
**Container resource limits** — Every platform service and every app container has explicit CPU and memory limits in its Docker Compose file. This prevents any single container from exhausting server resources.
119+
120+
**Mandatory Access Control (AppArmor)** — Debian 12 ships with AppArmor enabled by default. Docker automatically applies the `docker-default` AppArmor profile to all containers, which restricts capabilities like writing to `/proc` and `/sys`, mounting filesystems, and accessing raw sockets. No configuration is needed — this works out of the box.
121+
122+
SELinux is **not** used. While SELinux is the standard MAC system on RHEL/Fedora, it is not well-suited for Debian:
123+
124+
- AppArmor is Debian's native MAC system, maintained by the Debian security team
125+
- SELinux policies on Debian are incomplete and poorly maintained — the `selinux-policy-default` package lags far behind RHEL equivalents
126+
- Docker + SELinux on Debian causes bind-mount labeling issues (`:z`/`:Z` volume flags) with no community support for troubleshooting
127+
- Enabling SELinux on Debian requires switching from AppArmor, losing Docker's automatic profile enforcement
128+
129+
Since AppArmor is already active and Docker integrates with it automatically, the platform's MAC requirements are met without any additional configuration.
130+
106131
## Caddyfile Generation
107132

108133
The platform Caddyfile at `/opt/platform/Caddyfile` contains a single import directive:

0 commit comments

Comments
 (0)