You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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>
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
+
106
131
## Caddyfile Generation
107
132
108
133
The platform Caddyfile at `/opt/platform/Caddyfile` contains a single import directive:
0 commit comments