Setup PiHole as a container on Alpine Linux

This weekend’s project will be staging a new DNS server leveraging PiHole within a docker container. PiHole is a free and opensource DNS sinkhole project which provides ad blocking at a network level so that clients don’t require any unique setup to take advantage of PiHole’s offerings. Containers, as I mentioned previously, are a newer technology that allows you to separate applications from host OS.

What do I need?

I will be building this server as a VM within my lab and leveraging Alpine as our OS of choice.

About Alpine: Alpine is a lightweight security-oriented OS. Since our host OS is just running docker and it’s containers, we want to make sure we are running bare essentials to limit our possible attack surface.

Download page

Here is your VMs configuration:

  • 1 CPU/Socket
  • 1 GB ram
  • 8 GB of HDD space
  • network Adapter: E1000
  • OS type to Linux (other) x64

let’s get started: OS Installation and Configuration

  1. Mount the Alpine ISO you downloaded (for our demo, we are using Alpine – Virtual – x86_64).
  2. Power on your VM and boot to disc
  3. Once the boot process has finished, you should be at the login prompt.
  4. Log in as root (there is no password)
  5. To install to the disk, we need to run the alpine install script:
    # setup-alpine
  6. Choose your keyboard layout (and a variant if prompted): US
  7. Choose your network card:
  8. Set a static IP when prompted if you want DHCP or other:
    IP: <your IP>
    GW: <your router IP>
  9. Set your root password.
  10. Choose your time zone:
  11. Chose your mirrors:
    f (determines the fastest mirror)
  12. Chose an SSH server:
    OpenSSH  (you can select none if you plan to do management from the console)
  13. Choose NTP client:
    Chrony  (no preference here – used default)
  14. Choose the disk you want to install Alpine to:
    sda  (yours may be different)
  15. How would you like to use the disk?
    Confirm choice
  16. Installation should have completed, and you can now reboot the server:
    # reboot
  17. Disconnect the ISO.
  18. Login as root using the password you previously set.
  19. Add a new user for management purposes:
    # adduser <username>
  20. Add user to sudoers:
    # vi /etc/sudoers
    a. Enter insert mode:
    <username> ALL=(ALL) ALL
    b. Exit insert mode (esc) and type: wq! (write/quite/force)
  21. Exit root and login as your new user.
  22. Type SU  to elevate permissions

Install Docker

  1. Add the community repository to the APK repositories:
    # vi /etc/apk/repositories
    a. Enter insert mode:
    b. Exit insert mode (ESC) and type wq! (write/quite/force)
  2. Update APK repositories:
    # apk update
  3. Install docker:
    # apk add docker
  4. Set docker to start on boot:
    # rc-update add docker boot
  5. Start the docker daemon manually:
    # service docker start

Install Docker-Compose

  1. 1. Install PIP
    # apk add py-pip
  2. Install dev dependencies:
    # apk add python-dev libffi-dev openssl-dev gcc libc-dev make
  3. Install docker-compose:
    # pip install docker-compose

Create your docker-compose.yml file

  1. Navigate to your users home:
    # cd /home/<username>
  2. Create your docker-compose.yml
    # vi docker-compose.yml
    a. Enter insert mode and paste the following (example template from the projects docker-hub page):

    version: "3"
        container_name: pihole
        image: pihole/pihole:latest
          - "53:53/tcp"
          - "53:53/udp"
          - "67:67/udp"
          - "80:80/tcp"
          - "443:443/tcp"
          TZ: 'America/Los_Angeles'
          WEBPASSWORD: '<your password>'
        # Volumes store your data between container upgrades
           - './etc-pihole/:/etc/pihole/'
           - './etc-dnsmasq.d/:/etc/dnsmasq.d/'
        # Recommended but not required (DHCP needs NET_ADMIN)
          - NET_ADMIN
        restart: unless-stopped
    Important Note: Update the following entries per your preference:

    Docker Hub Page:

    You can lock PiHole to a specific version by changing tags:
    pihole/pihole:latest to pihole/pihole:v4.4

    Environment variables you may want to change:

    - TZ: 'America/Los_Angeles'
    - WEBPASSWORD: '<your password>'
  3. Exit insert mode (ESC) and type wq! (write/quite/force)
  4. Let’s pull the images we defined in our docker-compose file (while in the SAME directory as your docker-compose.yml):
    # docker-compose pull
  5. Time for the moment of truth – let’s start our containers:
    # docker-compose up
  6. Verify you have no error messages.
  7. Navigate to the PiHole admin page using the IP address assigned to your host VM:
    HTTP://<your IP>/admin/
  8. Login using the password set in your docker-compose.yml file
  9. Yay, you should now see your dashboard:
  10. Go back to your SSH session and end the docker-compose process (CTRL + C)
  11. Start docker-compose as a background daemon:
    # docker-compose up -d
  12.  At this point, your PiHole server can begin to filter ADs, but you will need to either update your router’s DHCP DNS option to point to your PiHole’s IP OR disable DHCP on your router and shift DHCP to PiHole.

All done!

At this point, you’ve set up an Alpine Linux host, installed docker, installed docker-compose, created your docker-compose.yml file, and configured your PiHole to start blocking ADs.

Other options that may be worth tweaking:

  • Settings -> Privacy – Depending on your views of privacy on your local network, you may wish to either show every DNS lookup and record all details or collect nothing.
  • Settings -> Blocklist – You can add additional block lists to your PiHole. I’ve ever felt the need to do, but it’s an option.
  • Settings -> DNS – You can choose additional upstream DNS servers instead of Google. Additionally, you can also leverage DNSSEC, which provides another level of security for browsing.

Thank you for taking the time to go through this project, and I hope you found it helpful.