How to open ALL ports on a docker container (running a server in container) – Not A.I. article

In this article we will dive in the rare occasion where you don’t just need a container to run a micro-service, or just one internal service as part of a bigger stack, but instead, you want to ‘container-ize’ a whole stack of a system, maybe a server with its own WHM, and more.

For that purpose as an alternative to supervisord, you may need to run a docker image of a system that support systemd, as with supervisord you may encounter inconsistencies and issues and manual extra work. While you can achieve that with some “hackish” parameters with docker, it is not always the case where systemd images are going to work smoothly, which is why I would recommend to ditch docker for podman, as podman offers functionality equivalent to Docker, same commands and all, but excels in managing containers with systemd, thanks to its ability to operate without a daemon.

Now lets move over on what we can do network-wise, neither opening ports with -expose, or iptables is your way out in that case, as we talk about a whole stack, and servers often need their own dedicated IP address and a bunch of TCP and UDP ports, they often have their own firewalls and network managers too, which is why we need to attach the docker directly into the network with its own IP address

That could be done with two types of virtual lans, one is ipvlan and the other is macvlan

  • Macvlan operates at Layer 2 (Data Link Layer) of the OSI model. It allows you to create multiple virtual interfaces, each with its own MAC address, on top of a physical network interface, one possible issue you may face with macvlan is that if you got a switch that is configured with such security settings that wouldn’t allow more than one MAC addresses to be used on the same Ethernet port of the switch.
  • IPvlan, on the other hand, operates at Layer 3 (Network Layer) of the OSI model. It also allows you to create multiple virtual interfaces, but each interface shares the same MAC address as the physical interface. However, each IPvlan interface has its own unique IP address and behaves as an independent network interface. IPvlan can be useful for scenarios where you want to isolate traffic at the IP level while sharing the same physical network interface.

Having said that, we will approach our networking setup with macvlan, because that’s what I have experience with and what I prefer as it is one layer down. Suppose that we need to run a FreePBX – Asterisk container

  1. Creating a network that will be used with our container, the IP of the docker container suppose its IP will be “192.168.1.2” our gateway will be 192.168.1.1 and our subnet 255.255.255.0 also of cidr /24 and our network adapter will be enp3s0
docker network create -d macvlan --subnet=192.168.1.0/24 --gateway=192.168.1.1 -o parent=enp3s0 mymacvlan

2. Running first time the container

sudo docker run --network=mymacvlan --name=asterisk --ip 192.168.1.2 --cap-add=NET_ADMIN --cap-add=NET_RAW -it freepbx-image:latest
  1. NET_ADMIN: This capability allows various network-related administrative tasks such as setting network interfaces into promiscuous mode, configuring routing tables, etc. Containers with this capability can perform advanced networking operations.
  2. NET_RAW: This capability allows a process to create raw network packets. Raw sockets are typically used for low-level network operations where the protocol headers need to be constructed manually. It’s often required for applications that need to perform tasks like network scanning or crafting custom packets.

3. Now our docker container will be running, but it will not be accessible by the host system, it will be though accessible just fine from the local network. In case you need to access it from the host system you need to create a bridge on the host it self.

Our bridge suppose it will have the IP 192.168.1.200, that’s IP is just only for the bridge it self, our network adapter suppose is enp3s0, could be eth0, or anything else, choose one adapter of your own system.

sudo ip link add macvlan0 link enp3s0 type macvlan mode bridge
sudo ip addr add 192.168.1.200/32 dev macvlan0
sudo ip link set macvlan0 up
sudo ip route add 192.168.1.2/32 dev macvlan0

Now we should be able to ping the container from the host and vise versa.

Of course this is temporary and it will be lost after reboot, lets make the network configuration to persist across reboots, you can automate the setup by adding configuration to the /etc/network/interfaces file:

# macvlan for docker
auto macvlan0
iface macvlan0 inet manual
    pre-up ip link add macvlan0 link eth0 type macvlan mode bridge
    pre-up ip addr add 192.168.1.200/32 dev macvlan0
    up ip link set macvlan0 up
    post-up ip route add 192.168.1.2/32 dev macvlan0

A Recap of the IP’s we used: 1.1 For the gateway, 1.200 for the bridge of the host, 1.2 for the container server it self. CIDR 24 for the docker macvlan network as our subnet in our example network is 255.255.255.0 a common local network of 256 IP addresses, and CIDR 32 for the bridge (macvlan0) ensures that it has a single, unique IP address assigned to it.

And that was all kiddos, now your container should be visible in your network with its own IP as if it was a Virtual Machine.

One comment

Leave a Reply