Restrict access to internet while still being able to access IPs on the private network

My general question is: How can I restrict my containers from being able to access the internet (ping apple.com wouldn’t work) but still be able to access other containers on my private network via their hostname (ping container_a would still work).

My setup follows as such: I have an Orange Pi Zero running three docker containers, lets say container_a, container_b, and container_c. I have a user defined bridge network set up and all containers are connected to it.

I have removed internet access from my OPiZ by emptying the /etc/resolv.conf file.
I then noticed that my containers can still resolve, e.g. ping apple.com does work in my container.

Each of my containers /etc/resolv.conf file looks like this by default:

nameserver 127.0.0.11
options edns0 trust-ad ndots:0

As an effort to restrict internet access I commented out the lines in the /etc/resolv.conf file on container startup.

After doing this I noticed that my container_b couldn’t communicate with container_a via hostname anymore. e.g. ping container_a no longer worked.

I had the thought that I could add

container_a         <container ip>

to container_b’s /etc/hosts file and that would allow it to access container_a via hostname and obviously, this way container_b doesn’t have to reach out to the network to see if any container has the hostname “container_a” because it will be in the /etc/hosts file.

I ran this command to get the IP of container_a: sudo docker container inspect <container name> | jq -r '.[0].NetworkSettings.Networks.<network name>.IPAddress'

(substitute the values in the <> with real values)

Anyways, this worked and I was able to ping container_a but I wonder if there is a “better” or “correct” way to do this.

What I would like to have happen is I can still reach outward to my private network so I don’t have to add an entry to each containers /etc/hosts file and the docker network can help me connect to the other containers via hostname but I want to prevent my containers from being able to access the internet.

How can I accomplish this?

resolv.conf is just the configuration of the name resolution not the internet. The container would still be able to access any IP address and even virtual hosts by sending a request to a specific IP address with the correct HTTP headers. Domain name resolution just lets you use a domain name now knowing the IP address.

If you want a private Docker network, you cn use an “internal” network.

docker network create --internal privatenet

Make sure all of yontainers that need sto communicate with eachother are connected to the “privatenet” internal network. Of course you can use any name you like. The key is the --internal flag when you create the network.

Note that internal network will not allow you to forward ports to the container that has no public networks. Once you add a public network to the container it will be able to communicate with the internet too.

Although you can’t foward ports to these containers using Docker’s builtin method, you can connect to the container’s ip address from the same host. Which means, if you want to, you can use a proxy server on the host or simply the “socat” command to forward a public port to a container’s port if you need to.

Thank you for the info.

So the problem I am now running into is this:

I have added

internal: true

to my docker-compose.yml file so the network is internal.

However, container_b was serving a web page that was forwarded by the hosts localhost.

Now accessing localhost on the host doesn’t connect (Just like how you mentioned it wouldn’t)

So I am now trying to forward localhost:80 to container_b:80

This command isn’t working: sudo socat TCP-LISTEN:80,fork TCP:172.21.0.3:80 and I can’t figure out why.

I should mention 172.21.0.3 is the IP of the container. And I did put the container IP straight in my browser’s url field and the page did come up. But I would still like to access it from typing localhost if possible.

I know this doesn’t really fall under the same umbrella as docker but I would appreciate any help.

Well, in case of internal network, as I discovered recently, Docker does not forward ports to the internal network and doesn’t add the accept rules to the iptables either including traffic coming from the WAN/LAN network if I remember correctly. Which means you need to find a way to make Docker “think” the traffic is coming from the host or from the same internal network and I have never checked what the connection looks like from the container. You can check it by using a normal container having the default bridge and forward request to it using socat.

If socat doesn’t work, a proxy server should work. For example Nginx can forward ports to containers. The nginx container should be on the same private network but also should have a public network. Outgoing request will not go thorugh the nginx proxy so you will still not have internet, but the nginx proxy will have it and can forward ports through the internal network.

If that nginx proxy is not running in a container, but on the host, than I believe the container should “see” the request is comming from the gateway which is 172.21.0.1 in your case. I don’t recommend this solution since containers can get different IP addresses next time unless you configure static ip addresses.

A container can use other containers name instad of ip addresses to forward requests or you can use nginx-proxy to automatically generate proxy configuration.

Note that I have never tried nginx proxy with internal networks, but in theory, it should work.

Thank you, this really helps!