feat: make "only the app publishes a port" a binding rule

A published database port puts the data on the public internet, and Docker's
own iptables rules bypass ufw — the server looks firewalled while the port is
open. Previously this was only a comment in compose.yaml, which an agent adding
a db service later is free to ignore.

Anchored at every point where a service could be added or shipped:
- rules/security.md: the rule, the reasoning, and the audit commands
- rules/backend.md + architecture SKILL: constraint when picking the data layer
- agents/backend-dev.md: non-negotiable for any service it adds
- agents/qa-engineer.md: a published port is a Critical finding
- skills/deploy: blocking pre-flight audit
- compose.yaml: db example now uses expose:, with depends_on healthcheck
- docs/DEPLOYMENT.md + README: SSH tunnel instead of publishing for debugging
This commit is contained in:
Florian Wilde
2026-08-09 01:12:06 +02:00
parent e30d02d41a
commit 75e99f75c6
9 changed files with 161 additions and 7 deletions
+12
View File
@@ -36,6 +36,18 @@ Then check:
- [ ] Pending migrations are committed
- [ ] Everything committed and pushed to the remote the server pulls from
**Port audit — blocking.** Only the app service may publish a port, and only on
loopback:
```bash
docker compose config | grep -B8 "published:"
```
Any service other than `app` with a published port, or any binding to `0.0.0.0`,
stops the deploy. A published database port puts the data on the public internet and
bypasses ufw, because Docker writes its own iptables rules. Fix `compose.yaml`
before continuing.
## 3. First deployment only
Walk the user through this once. It happens on the server, over SSH.