Hide ports of all Docker containers

I’m running Docker on my Raspberry Pi 4 with some containerized web apps and I want all traffic to go through nginx as reverse proxy.

My problem is that I can access the Docker container ports from any device in my network, i. e. I’m bypassing nginx.

This is my nginx config:

server {
    listen 80;
    server_name myRaspi;

    location /cool {
        proxy_pass         http://127.0.0.1:5000/cool;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection keep-alive;
        proxy_set_header   Connection "Upgrade";
        proxy_set_header   Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }
}

As you can see, I’m forwarding the traffic for myRaspi/cool to localhost:5000/cool (a web app running inside a Docker container). At the moment, I can access both myRaspi/cool and myRaspi:5000/cool from any device in my network.

I followed the official Docker docs and configured the following:

iptables -I DOCKER-USER -i ext_if ! -s 192.168.174.0/24 -j DROP

Executing sudo iptables --list shows the new rule.
Since all of my network devices are in the subnet 192.168.175, so I’d expect that now all traffic to both myRaspi/cool and myRaspi:5000/cool should not work (as I’m blocking everything except 192.168.174, but I’m in 192.168.175).
Unfortunately, this does not work: I can still access both myRaspi/cool and myRaspi:5000/cool.

After sudo reboot, the formerly created rule is gone and sudo iptables --list doesn’t contain it anymore.

Since I’m still a novice to the Docker/Linux/nginx network world, I’d appreciate your help on how to configure Docker/nginx so that all traffic goes through nginx as reverse proxy and access to container ports from outside this Raspi is not possible.

this is a (hopefully) friendly push :slightly_smiling_face:

You need to forward the port of Nginx only, nothing else. Nginx will see other containers on the same Docker network. So you don’t need to hide ports. You just shouldn’t make them available.

Now let’s say for some reason you have to forward other containers’ ports too. I don’t think this is the case, but even then you could forward that port from the internal loopback IP address making the port available only on 127.0.0.1

Example (part of a compose file)

    ports:
      - "127.0.0.1:5000:5000"

I have never needed to manipulate IPTables rules manually. Even if you need to add some new rules I would do it with a firewall like ufw.

I shared these ideas so you can see your alternatives, but the first idea should work for you.

One more thing. Usually you don’t need to configure the Nginx rules manually

https://hub.docker.com/r/jwilder/nginx-proxy

I guess that whole port forwarding was required for you because you didn’t know the IP addresses of the containers. Using a the above image, you don’t need to know.

1 Like

Thx for your reply, @rimelek. There seems to be a misunderstanding, maybe I wasn’t precise enough: my web apps are running inside Docker, but nginx is running on bare metal on the Raspi and not within a container.

So more precisely: nginx is running on my Raspi. My web app is running in Docker and accessible on port 5000. So on my Raspi I can curl http://localhost:5000 and access the web app.
The problem is that that the port 5000 is also accessible from outside. So I can call http://myRaspi:5000 from any other machine in my network, because Docker publishes this port. And this is want I want to change.

I tried to use Docker with ufw, but I ran into problems and guys on Stack Overflow recommended to throw away ufw and configure Docker via iptables properly.

I understood you. I am saying you should run the proxy in a container as we probably all do. And if you don’t want to do it, and you would rather configure everything manually, you don’t need iptables to hide ports. Just don’t forward the port from the public IP address. Your nginx server (unless it is running on a different machine) will see the port on 127.0.0.1 if you forward the port from that ip address only.

Ah I simply was unaware of the Docker feature to expose ports to local IP addresses only (like -p 127.0.0.1:5000:5000). Learning never stops.

Thank you so much and have a great Sunday!