As my first noteworthy venture in containerization I decided to jump on the hype train and run a Pi-hole instance on my NAS to block ads and the-like in my local network.

The NAS runs Arch Linux and I opted for LXC as it seemed to be the leaner approach compared to Docker. Here's how I did it.

Install LXC

On Arch all you need to do for being able to run (privileged) LXC containers is installing it:

$ pacman -S lxc

I want containers to look like proper network clients instead of having them NAT'ed and routed by their host (the NAS) so I changed the default config to use macvlan in bridge mode for container networking:

# /etc/lxc/default.conf

lxc.net.0.type = macvlan
lxc.net.0.macvlan.mode = bridge
lxc.net.0.link = eth0
lxc.net.0.flags = up
lxc.net.0.name = eth0

Note: the last line sets the name of the virtual interface that appears inside the container to eth0. This is not required, but many images seem to have issues dealing with generated interface names.

Create the Container

I chose to go with the current Debian release for my Pi-hole container, which is Buster.

$ lxc-create -t download -n pi-hole -- -d debian -r buster -a amd64

This sets up a (refreshingly minimal) Debian image.

The only thing that I changed inside the container is switching to static addressing for IPv4 as I did not want the container to query my router for DHCP:

# /etc/network/interfaces

auto eth0
eth0 inet static
  address 10.0.0.3
  netmask 255.255.255.0
  gateway 10.0.0.1

(Urr, feels so ancient when you're used to systemd-networkd...)

Install Pi-hole

There are some requirements to install first:

$ apt-get install wget curl

Then the official Pi-hole install script can be used.

I really hate the attitude behind curl'ing install scripts and directly piping them to Bash as root user which seems en vogue these days. In my head this rings all alarm bells in terms of security. But I guess that's what comes with the nature of containers: they're isolated and volatile, so they're a disposable object that is cared less about.

I still refuse to do so and instead download them, give them at least a quick scroll and fire them up afterwards. Thus with the Pi-hole installer:

$ curl -sSL https://install.pi-hole.net -o pi-hole.sh
$ less $_
$ bash $_

The installer then took care of the rest.

Final Touches

Don't forget to make the container autorun at boot using

$ systemctl enable lxc@pi-hole

A highly considerable improvement to my setup will be switching to unprivileged containers for increased degree of isolation.