Using specific host IP (interface) for docker containers

Posted on Apr 1, 2023

Introduction

The following article describes how I select a specific host IP for egress traffic in a specific docker container.

It was a trick used few years ago, at that time 2 seperate sites were sharing the same VPS, each has its own designated IP. What I would like to achieve is that each site should only use its own IP for egress traffic.

  • Site A IP: 10.201.0.201 interface: eth0
  • Site B IP: 10.201.0.202 interface: eth0:1

Here you can see I have 2 IPs on eth0:

[root@vps ~]# ip add 
...
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP grup default qlen 1000
    link/ether AA:BB:CC:0e:ce:28 brd ff:ff:ff:ff:ff:ff
    inet 10.201.0.201/24 brd 10.201.0.255 scope global dynamic eth0
       valid_lft 80555sec preferred_lft 80555sec
    inet 10.201.0.202/24 brd 10.201.0.255 scope global eth0:1
       valid_lft forever preferred_lft forever
...

Here is the routing table on my VPS:

[root@vps ~]# ip route
default via 10.201.0.254 dev eth0
10.201.0.0/24 dev eth0 proto kernel scope link src 10.201.0.201
...

So that’s all for my network setup! Let’s look at the Docker-compose YAML file.

Docker-Compose

In my docker-compose.yaml file, you can see I have deployed softEtherVPN.

Everything is as usual except I have created a network net_iptwo and have NET_ADMIN enabled.

The network net_uptwo, applies a default route to the container, and also assigns an IP with subnet 192.168.200.0/24 to the container

Fire up the service with docker-compose up -d then we are good to prepare for firewalld rules

# docker-compose.yaml
version: '3'
services:
  softether1:
    container_name: nic-softether1
    image: siomiz/softethervpn
    networks:
      - net_iptwo
    volumes:
      - ./softether/vpn_server.config:/usr/vpnserver/vpn_server.config
    cap_add:
      - NET_ADMIN
    ports:
      - 192.168.100.100:500:500/udp
      - 192.168.100.100:4500:4500/udp
      - 192.168.100.100:1701:1701/tcp
      - 192.168.100.100:1194:1194/udp
      - 192.168.100.100:5555:5555/tcp
networks:
  net_iptwo:
    driver: bridge
    driver_opts:
      com.docker.network.bridge.enable_icc: "true"
      com.docker.network.bridge.enable_ip_masquerade: "false"
      com.docker.network.bridge.host_binding_ipv4: "0.0.0.0"
      com.docker.network.bridge.name: "br_ip2"
      com.docker.network.driver.mtu: "1500"
    ipam:
      driver: default
      config:
        - subnet: 192.168.200.0/24

Firewalld

This Firewall rule is a self-explainatory one-liner: whenever the source is from 192.168.200.0/24 subnet, do SNAT to 10.201.0.202

firewall-cmd --permanent --direct --add-rule ipv4 nat POSTROUTING 0 -s 192.168.200.0/24 -j SNAT --to-source 10.201.0.202

Viola! We are all good to go!