Docker – External IP for Your Docker App
Back story
I was playing around with Pi-hole on my Ubuntu host and got stuck when I was starting up the container with 53, 67 (udp / tcp both) was getting errors (“listen udp4 0.0.0.0:53: bind: address already in use”) because the Ubuntu host system itself were using those ports.
I have previously used reverse-proxies to get around such problems but this time I wanted a simpler solution so I don’t have to manage another service in my local network to run Pi-hole.
First attempt was to try out macvlan (https://docs.docker.com/network/macvlan/) using docker networks, but that turned out not so straightforward as I wasn’t able to lease an IP using the 802.1q trunk bridge network interface in the local LAN DHCP server.
Solution
Add a secondary IP address on your host interface. Which can be achieved by finding out the physical interface which you want to use for the secondary IP address first.
ip addr
Find the host interface you want to utilise for the secondary IP, in my case it was “enp59s0”.
In order to add a virtual or secondary IP to the same interface, run the following
sudo ip address add 10.10.0.254/24 dev enp59s0
You need to be matching the subnet used in your local network or your IP won’t be reachable within the local LAN. In my case, I assigned an IP address “10.10.0.254” which I have manually reserved through my router configuration so DHCP doesn’t give away that IP to a new device that registers in the network.
After adding the secondary IP, my “ip addr” command was outputting the following segment under “enp59s0” interface, which shows our virtual IP (10.10.0.254).
2: enp59s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether xx:xx:59:8b:xx:xx brd ff:ff:ff:ff:ff:ff
inet 10.10.0.10/24 brd 10.10.0.255 scope global dynamic noprefixroute enp59s0
valid_lft 86245sec preferred_lft 86245sec
inet 10.10.0.254/24 scope global secondary enp59s0
valid_lft forever preferred_lft forever
inet6 efef::dada:2372:afaf:f89d/64 scope link noprefixroute
valid_lft forever preferred_lft forever
Docker Compose Magic
Following is my Pi-hole docker-compose.yml for reference.
Pay attention to the “Ports” section, where I have specified the “virtual” or secondary IP address which we added above for the docker application to utilise when binding ports.
version: "3"
# More info at https://github.com/pi-hole/docker-pi-hole/ and https://docs.pi-hole.net/
services:
pihole:
container_name: pihole
image: pihole/pihole:latest
ports:
- "10.10.0.254:53:53/tcp"
- "10.10.0.254:53:53/udp"
- "10.10.0.254:67:67/udp"
- "10.10.0.254:81:80/tcp"
environment:
TZ: 'Australia/Sydney'
# Volumes store your data between container upgrades
volumes:
- './etc-pihole/:/etc/pihole/'
- './etc-dnsmasq.d/:/etc/dnsmasq.d/'
# Recommended but not required (DHCP needs NET_ADMIN)
# https://github.com/pi-hole/docker-pi-hole#note-on-capabilities
cap_add:
- NET_ADMIN
restart: unless-stopped
Once the docker-compose ports are setup to use the virtual IP, start the docker app.
I tested my Pi-hole setup by trying to resolve an hostname using the virtual IP address 10.10.0.254.
~ dig google.com @10.10.0.254
; <<>> DiG 9.16.1-Ubuntu <<>> google.com @10.10.0.254
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 17903
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;google.com. IN A
;; ANSWER SECTION:
google.com. 217 IN A 142.250.66.238
Making the changes permanent
Not the scope of this article, you can google “Configure Secondary IP Address on Ubuntu using Netplan” and find various articles which would explain how to add a config file to automatically enable this virtual IP when the host computer starts up.