How to Disable Docker Ports for Public Users and Limit Ports to Specific IP Addresses

How to Disable Docker Ports for Public Users and Limit Ports to Specific IP Addresses

As we know, UFW (Uncomplicated Firewall) is a frontend for managing iptables rules, and Docker uses iptables directly. Therefore, when we disable a port on UFW, it won't apply to Docker containers. Let's consider the scenario where we want to disable port 5432, the default port for PostgreSQL. We can choose not to publish this port in the Docker Compose file, but what if we want to disable this port (or other ports) for public access through UFW or limit access to a specific IP range? In other words, we want to create a whitelist and blacklist so unauthorized users cannot access specific ports.

Let's consider we are going to limit specific ports to a public IP. in this case iptables can be disabled for docker, and every things can be managed via UFW.

Step 1: Disable iptables for Docker

To disable iptables for Docker, open (or create if it doesn't exist) the file /etc/docker/daemon.json:

sudo nano /etc/docker/daemon.json        

Add the following line to the file:

{
 "iptables": false
}        

Save and close the file, then restart the Docker service:

sudo systemctl restart docker.service        

Step 2: Check and Enable UFW

Check the status of UFW:

sudo ufw status        

By default, UFW is disabled, so it should be enabled. Before enabling it, ensure that your IP has access to the VM when UFW is activated. Allow SSH access by adding your public/private IP, depending on how you connect to the VM or instance:

sudo ufw allow from x.x.x.x to any port 22        

Here, port 22 is the default SSH port. If you've changed the SSH port, replace 22 with your custom port number.

Now, enable UFW:

sudo ufw enable        

Step 3: Limit Ports

The best approach is to limit access to all ports and then open only the crucial ones. First, edit the default UFW configuration file:

sudo nano /etc/default/ufw        

In this file, you can enable/disable IPv6 and set DEFAULT_INPUT_POLICY to DROP. This setting means UFW will drop (not accept) all requests unless there is a rule to open a specific port, such as port 80.

Step 4: Enable Internet Access for Docker Networks

There is a problem with network interfaces: except for the docker0 interface, other interfaces created in Docker Compose files cannot connect to the internet. To solve this, we need to set up a masquerade type of NAT for a specific IP range, such as 192.168.1.0/24

sudo iptables -t nat -A POSTROUTING -s 192.168.1.0/24 ! -o docker0 -j MASQUERADE        

In this command:

  • -A POSTROUTING specifies packets that are leaving the network.
  • ! -o docker0 indicates packets not going out through the docker0 interface.
  • -j MASQUERADE is a specialized form of SNAT (Source NAT) used to dynamically map private source IP addresses to the public IP address of the host.

This command allows internet access for our custom private IP range. However, note that all iptables commands are temporary and not persistent. They will be deleted after a reboot or network service restart.

Step 5: Make iptables Rules Persistent

To prevent iptables from resetting to the default configuration, create a bash script, e.g., nat.sh, with the following content:

#!/bin/bash
sudo iptables -t nat -A POSTROUTING -s 192.168.1.0/24 ! -o docker0 -j MASQUERADE        

Save and close the file, then make it executable:

chmod +x nat.sh        

Set up a cron job to run this script on reboot:

crontab -e        

Select your desired editor (e.g., nano, which is number 1), and add the following line at the end:

@reboot <your_script_dir>/nat.sh        

Additionally, add your MASQUERADE to /etc/ufw/before.rules:

sudo nano /etc/ufw/before.rules        

Add the following lines at the beginning of the file, before other rules:

*nat 
:POSTROUTING ACCEPT [0:0] 
-A POSTROUTING -s 192.168.1.0/24 ! -o docker0 -j MASQUERADE 
COMMIT        

Reload UFW to apply the changes:

sudo ufw reload        

Step 6: Use the IP Range in Docker Compose Files

You can now use this IP range. Define a network in the Docker Compose file and add networks to each Docker container. Here is an example of Docker Compose file with network definitions:

version: '3.8' 
services: 
  nginx:
    image: nginx 
    ports: 
      - "80:80" 
    networks: 
      <yourNetworkName>: 
        ipv4_address: 192.168.1.20


 #------ Define network ------#
networks: 
  <yourNetworkName>: 
    name: <yourNetworkName> 
    driver: bridge 
    ipam: 
      config:
        - subnet: 192.168.1.0/24 
#------ This is the IP range defined in previous steps ------#        

Run the Docker Compose file with:

docker compose up -d        

Or specify a custom Docker Compose file name:

docker compose -f <docker-compose-custom-name> up -d        

You can now log in to your container:

docker exec -it -u0 <container-ID> bash        

and try to use

apt update        

and if your container with custom IP connected to internet, you could update your apt package manager or ping some public IP such as 8.8.8.8 , and it shows that your containers are connected to the internet.

要查看或添加评论,请登录

社区洞察