Chapter 6 · 6.3
Docker and the firewall: publishing ports safely
This is the trap most people fall into. A port you publish in Docker with ports: is reachable from the internet, even if ufw blocks that port. Docker sets its own firewall rules, and they take precedence over the rules of ufw.
An example of what goes wrong
services:
db:
image: mariadb:11
ports:
- "3306:3306"
Your firewall says only 22, 80 and 443 are open. Yet your database is now reachable from the entire world on port 3306.
Three rules that keep it safe
- Only publish what needs to be reachable from outside. In this manual, that is only Caddy, on 80 and 443. Apps talk to Caddy over the internal compose network. They don't need
ports:. - Should a port only be reachable on the server itself? Put
127.0.0.1:in front of it. Then only the server itself can access it, or you via an SSH tunnel (see An SSH config: log in with a short name). - A database never gets
ports:. The app finds it by the name of the service, such asdb.
ports:
- "127.0.0.1:3001:3001"
Checking from outside
On the server, check which ports are open to everyone:
anna@web1:~$ sudo ss -tlnp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 4096 0.0.0.0:443 0.0.0.0:* users:(("docker-proxy",...))
LISTEN 0 4096 127.0.0.1:3001 0.0.0.0:* users:(("docker-proxy",...))
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",...))
Anything with 0.0.0.0 or [::] is reachable from outside. Anything with 127.0.0.1 only from inside. If you want to see it from outside, use a port scanner such as nmap from your own computer on your own IP address.
Please note: Don't mount /var/run/docker.sock in a container unless you know exactly why. Anyone who takes over that container takes over your entire server.
