Categories
tech

Docker, Pi-hole and MACVLANs

A couple of weeks ago, I started to move all the apps installed on my Raspberry Pi 4 to docker. This was a new way to learn docker and explore all apps that existed in the Docker world that can be deployed on the Raspberry Pi ARM platform. One of these apps was Pi-hole, a network wide ad blocking service.

Pi-hole intercepts ads by redirecting ad domains to a DNS black hole. Pi-hole can act as a DHCP server on your network and will advertise itself as the DNS server in the DHCP offer when a client requests for an IP address. Alternatively, you can keep your router as the DHCP server and change the DNS settings on your router and point it to the IP address of the Pi-hole device. This may not be feasible all the time.

Pi-hole Dashboard

While the system wide install of Pi-hole is easy to follow along, there can be some glitches while using Pi-hole on Docker. The official docker guide of Pi-hole from the Github repo is not so easy to follow if you have a custom setup. The guide has certain assumptions about the availability of free network ports

From the docs –

Port 80 is highly recommended because if you have another site/service using port 80 by default then the ads may not transform into blank ads correctly. To make sure docker-pi-hole plays nicely with an existing web server you run you’ll probably need a reverse proxy web server config.

You can still map other ports to Pi-hole port 80 using Docker’s port forwarding like this -p 8080:80, but again the ads won’t render properly.

Also, to run Pi-hole as the DHCP server the suggested techniques are pointed in another doc. This doc explains the different network configurations that can be used to run Pi-hole in docker.

  1. Host network mode – it requires that the device you are using to run Pi-hole is not already using ports 80 and 443. This is not usually true as most people run a web server or a reverse proxy on the same device
  2. Bridge network mode – The router needs to relay the DHCP requests to the Pi-hole container. This functionality is not present in most of the home routers.
  3. MACVLAN network – This is the hardest of them all. With this mode, docker will create a separate LAN network on your Pi-hole and you can assign different IP address to the same device on which Pi-hole is running.

MACVLANs solve multiple problems and then introduce some more. The problem that is solved is of port conflicts. Since a new IP address can be assigned to the Pi-hole device, all ports are available and can be bound to this new IP address. With this config, your Pi-hole device will now have 2 IP addresses, the original one and the new one created for the Pi-hole container.

Here is my docker-compose file to run the Pi-hole container –

# Docker compose for Pihole

version: '3.5'

services:
  pihole:
    container_name: pihole
    image: pihole/pihole:latest
    hostname: pihole
    domainname: pihole.domain.com
    cap_add:
      - NET_ADMIN
    networks:
      pihole:
        ipv4_address: 192.168.0.178
    dns:
      - 127.0.0.1
      - 1.1.1.1
    ports:
      - "192.168.0.178:443:443/tcp"
      - "192.168.0.178:53:53/tcp"
      - "192.168.0.178:53:53/udp"
      - "192.168.0.178:67:67/udp"
      - "192.168.0.178:80:80/tcp"
    environment:
      ServerIP: 192.168.0.178
      VIRTUAL_HOST: pihole.domain.com
      WEBPASSWORD: "test123"
      TZ: 'America/Los_Angeles'
      DNS1: '127.0.0.1'
      DNS2: '1.1.1.1'
    restart: always
    volumes:
      - './etc-pihole/:/etc/pihole/'
      - './etc-dnsmasq.d/:/etc/dnsmasq.d/'
      - './resolv.conf:/etc/resolv.conf'

networks:
  pihole:
    name: pihole
    driver: macvlan
    driver_opts:
      parent: eth0
    ipam:
      config:
        - subnet: 192.168.0.0/24

Let’s see what the above config file does. We assign the Pi-hole container an IP address of 192.168.0.178. This address is arbitrary. You should choose an IP address that is free and yet not been assigned by your router. You can see the DHCP client list in the router and then pick any free IP address so that no conflicts occur.

A MACVLAN network is created with subnet 192.168.0.0/24 with the parent device as eth0. The parent device is the one which is holding your current IP address. The subnet should be the same as what your router is using. Only then will be able to access the Pi-hole device from any other device in your home network.

You should now be able to ping this new IP address from any other device except the Pi-hole device. You can’t ping from the same device because docker security policies deny traffic between the two networks. This can be overcome by creating another network interface on the same MACVLAN network and adding a route to the new IP address so that Linux routes the packet from one network to another. Here are the commands that I used –

sudo ip link add pihole link eth0 type macvlan mode bridge
sudo ip addr add 192.168.0.177/32 dev pihole
sudo ip link set pihole up
sudo ip route add 192.168.0.178/32 dev pihole

These commands create a new network interface with IP address 192.168.0.177 and add a route to the Pi-hole container running at 192.168.0.178. Now you should be able to ping the Pi-hole container from the same device.

While I was doing this, I saw that pings from other devices on the same network were not going through to the Pi-hole container. They would only work from inside the Pi-hole container to other devices on the same network. After browsing much of the forums, I found out on Stack Overflow that this was a known bug on Raspbian. To fix this, I had to update the Linux kernel on my Raspberry Pi using the command sudo rpi-update

After all these small problems were solved, Pi-hole started working. I disabled my Router’s DHCP server and now Pi-hole is serving as my DHCP server.

Pi-hole on IP 192.168.0.178
Pi-hole as DHCP server

There was much learning needed. The docker world is still a mystery to me and I keep demystifying it one service at a time.

References –

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.