Files
platform/scripts/setup/machine-setup/ufw-docker-rules.conf
T
pastilhasandClaude Opus 5 e36c6bb431 allow port 22 through the docker-user allowlist
the DOCKER-USER chain is the only thing gating docker-published ports from
the internet — docker writes its own DNAT/FORWARD rules and bypasses ufw, so
`ufw allow <port>` has no effect on a published container port. the allowlist
permitted only 80 and 443, so a machine provisioned from this template dropped
gitea ssh silently.

the failure is hard to spot: the port looks open locally and docker ps shows it
published, but external clients hang at TCP connect with no refusal. local tests
pass because they arrive via lo and match the loopback RETURN before reaching the
DROP. comments added so the next person recognises it faster.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 09:51:22 +00:00

47 lines
1.7 KiB
Plaintext

# UFW Docker compatibility rules
# Append these to /etc/ufw/after.rules (after the existing COMMIT)
# Blocks all external access to Docker-published ports except:
# - Trusted IPs (add your own)
# - Explicitly allowed public ports (80, 443, 22)
# - Docker internal and loopback traffic
#
# This chain is the ONLY thing gating Docker-published ports from the internet:
# Docker writes its own DNAT/FORWARD rules and bypasses ufw entirely, so a
# `ufw allow <port>` has no effect on a published container port. If a container
# port must be reachable publicly, it needs a RETURN line below.
#
# Failure mode to recognise: the port appears open locally and `docker ps` shows
# it published, but external clients hang at TCP connect with no refusal. Local
# tests pass because they arrive via `lo` and match the loopback RETURN above,
# never reaching the DROP. Test from another machine, not from the host itself.
*filter
:DOCKER-USER - [0:0]
# Allow established/related
-A DOCKER-USER -m conntrack --ctstate ESTABLISHED,RELATED -j RETURN
# Allow loopback
-A DOCKER-USER -i lo -j RETURN
# Allow Docker internal networks
-A DOCKER-USER -s 172.16.0.0/12 -j RETURN
# Allow trusted external sources (add more lines as needed)
# -A DOCKER-USER -s <TRUSTED_IP> -j RETURN
# Allow public ports
-A DOCKER-USER -i eth0 -p tcp --dport 80 -j RETURN
-A DOCKER-USER -i eth0 -p tcp --dport 443 -j RETURN
# gitea SSH (NPM stream -> gitea:22). Host sshd does not use :22 publicly on a
# box that serves gitea — it moves to :2022 plus the tailnet IP, see ssh.socket.
-A DOCKER-USER -i eth0 -p tcp --dport 22 -j RETURN
# Drop everything else from external
-A DOCKER-USER -i eth0 -j DROP
# Return for non-external traffic
-A DOCKER-USER -j RETURN
COMMIT