I’m trying to set up a simple web application in a docker container with a nginx reverse proxy (not in a container, on the host).
Here is how I run the container:
docker run -d --name mywebapp -v /webapp/:/data/ --restart unless-stopped -p 5665:80 mywebapp/server:latest
The web application listens on port 80 inside the container, that I forward to 5665 host port.
The nginx reverse proxy listens on port 5666 and forwards the requests to the forwarded container port 5665.
The netstat -lntup output (only relevant lines):
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:5666 0.0.0.0:* LISTEN 29369/nginx: master
tcp 0 0 0.0.0.0:5665 0.0.0.0:* LISTEN 151974/docker-proxy
I want to configure the firewall block all connections from outside except to the 5666 port.
Here are my nftables rules (exact copy, nothing is removed):
define IIFNAME = "ens3";
table inet filter {
chain input {
type filter hook input priority filter
policy drop
ct state invalid drop comment "early drop of invalid connections"
ct state {established, related} accept comment "allow tracked connections"
iifname lo accept comment "allow from loopback"
ip protocol icmp accept comment "allow icmp"
meta l4proto ipv6-icmp accept comment "allow icmp v6"
tcp dport ssh accept comment "allow sshd"
tcp dport 5666 accept comment "webserver";
pkttype host limit rate 5/second counter reject with icmpx type admin-prohibited
counter
}
chain forward {
type filter hook forward priority filter
policy drop
iifname "docker0" oifname $IIFNAME accept;
iifname $IIFNAME oifname "docker0" accept;
}
I can connect to port 5666, which is expected and desired.
However, the problem is that despite having connections to 5665 port blocked (at least I thought so), I still can connect to 5665 port, bypassing the nginx reverse proxy.
After some trial and error I found the problem was with the "forward" chain rules, that is:
iifname "docker0" oifname $IIFNAME accept;
iifname $IIFNAME oifname "docker0" accept;
Removing these rules fixes this problem, but it also prevents the container from accessing the internet.
My two questions:
-
Why do "forward" rules even matter? I thought that "forward" rules only apply when a packet is supposed to be received by another machine (or a container). However, the
5665port is listening on the current host port bydocker-proxy. Even though the data is "forwarded" to the container, it is not forwarded by the kernel, it is forwarded by a user-space application –docker-proxy, so I’d expect the kernel to useINPUTchain instead ofFORWARDchain. Yet, it seems likeFORWARDrules do matter. -
(maybe the answer to this question would be clear having the answer to the previous one, yet I’ll ask it)
How can I block the access to the forwarded5665port from outside (fromens3interface), while allowing the container to access the internet (that is, make requests through theens3interface on the host) ?
>Solution :
Docker uses the firewall to route traffic, so it can get confusing to also use the firewall to restrict access.
An easier solution is just to have docker bind to the localhost interface explicitly with ... -p 127.0.0.1:5665:80. By default, without an address, docker will listen on all interfaces, but you don’t want that in this case.