# episode 10 - paste this block at the END of /etc/ufw/after.rules # (and the same block in /etc/ufw/after6.rules for IPv6). # # Why: Docker publishes ports by DNAT in the FORWARD path, not INPUT. ufw only # filters INPUT, so `ufw deny incoming` does NOT close a published container # port - it stays wide open. DOCKER-USER is the one chain Docker runs first in # FORWARD and never flushes on its own, so the fix goes here. # # The catch inside the catch: DNAT rewrites the destination port to the # container's port BEFORE this chain sees the packet. Matching --dport would # match the wrong (translated) port. So match the ORIGINAL published port with # conntrack --ctorigdstport instead. # # Only eth0 (the public NIC) is filtered. wt0 (the NetBird mesh) and the docker # bridges are left alone on purpose - a rule without `-i eth0` here breaks the # mesh route to n8n (episode 8) and traffic between containers. # # Replace eth0 with your public interface, and the port list with what you # actually publish. *filter :DOCKER-USER - [0:0] -A DOCKER-USER -i eth0 -m conntrack --ctstate RELATED,ESTABLISHED -j RETURN -A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 80 -j RETURN -A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 443 -j RETURN -A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 2222 -j RETURN -A DOCKER-USER -i eth0 -p udp -m conntrack --ctorigdstport 443 -j RETURN -A DOCKER-USER -i eth0 -p udp -m conntrack --ctorigdstport 3478 -j RETURN -A DOCKER-USER -i eth0 -j DROP COMMIT