CI/CD all the things: PiHole
Tags: raspberrypi, gitlab
Published: 2020-03-24 13:47:31

---
title: CI/CD all the things: PiHole
published: false
date: 2019-01-11 00:01:12 UTC
tags: raspberrypi, gitlab
canonical_url: https://medium.com/gitlab-magazine/ci-cd-all-the-things-pihole-625a0ceaf12
published: true
---

![](https://cdn-images-1.medium.com/max/1024/0*5kVeCxUk4wY4Ge4g)<figcaption>Photo by <a href="https://unsplash.com/@rawpixel?utm_source=medium&amp;utm_medium=referral">rawpixel</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption>

### CI/CD all the things: Pi-hole

I’ve spent some time exploring how to apply the concepts of CI/CD to everyday life. In [my first post](https://dev.to/olearycrew/ci-cd-all-the-things-introducing-auto-breakfast-from-gitlab-sort-of-ldn-temp-slug-5187764), I went all in — making breakfast with GitLab CI/CD as the orchestrator. In this post, I’ll tell you about a home project I undertook over the holidays: getting a [Pi-hole](https://pi-hole.net/) up and running at my house. (mmmm 🥧)

Pi-hole is a great little [open source](https://github.com/pi-hole) tool that lets you run your own DNS server on your network and send advertisement and tracking requests to a “black hole” of 0.0.0.0, providing network-level ad blocking…rather than installing ad blockers on every device, browser, and IoT item in the house.

Pi-hole even ships with a great dashboard and has a number of extension points to customize it. I added an [hourly speed test](https://github.com/arevindh/pihole-speedtest/wiki/Installing-Speedtest-Mod) — just to keep my ISP honest 😉.

![](https://cdn-images-1.medium.com/max/1024/1*wwR_IBlOfTguthA00Ha7bQ.png)<figcaption>PiHole Dashboard with Speedtest plugin</figcaption>

### Installing Pi-hole

Installing Pi-hole is relatively simple, with [straightforward instructions](https://github.com/pi-hole/pi-hole/#method-1-clone-our-repository-and-run), and the only thing I had to watch out for was DHCP. Since my router provides Circle from Disney for parental controls, it has to retain the DNS/DHCP server but I could still map its upstream DNS to Pi-hole. This means I lost some of the granularity in the logs as most requests come from my router rather than the individual devices, but once I had it all set up Pi-Hole worked as designed.

### Source control for Pi-hole

There are a lot of great resources out there for Pi-hole, including things like [commonly whitelisted domains](https://discourse.pi-hole.net/t/commonly-whitelisted-domains/212) to make sure some general services aren’t negatively impacted by it. There are also many [additional blacklists](https://firebog.net/) available on the internet, depending on what you’re concerned about. And, since [FTL](https://github.com/pi-hole/FTL) is extensible, it is even possible to use it as a lightweight local DNS server.

Because all of those elements are presented in a fashion that says, “Here’s how you can run a command in the terminal,” or “Here’s how you add it in the UI,” my internal “must source control all things” tick was activated…and so I [created a repository on GitLab](https://gitlab.com/olearycrew/pihole/).

I added a couple of scripts to automate the whitelisting for common and custom domains as well as a file to contain the hosts on my network. But this still meant I had to manually check out the repository on my Raspberry Pi and manually run the scripts. That’s where [GitLab CI/CD](https://about.gitlab.com/product/continuous-integration/) comes to the rescue! Luckily, it’s available on our free tier, because I was using my [personal account](https://gitlab.com/oleary) for all of this, [while I was on holiday](https://about.gitlab.com/handbook/paid-time-off/#a-gitlabbers-guide-to-time-off).

### Enabling CI/CD to Pi-hole

Now that I had a repository ready to go, I just had two steps until I had access to all the CI/CD goodness my little heart would ever desire.

1. Make my Raspberry Pi a [GitLab Runner](https://docs.gitlab.com/runner/) so that GitLab.com changes could get into my home network with no holes poked in my firewall.
2. Set up a [.gitlab-ci.yml](https://docs.gitlab.com/ee/ci/yaml/) to run updates when changes are made.

#### Installing GitLab Runner on my Raspberry Pi

Installing GitLab Runner is easy on any platform that supports Golang, including [Linux](https://docs.gitlab.com/runner/install/linux-manually.html), [OSX](https://docs.gitlab.com/runner/install/osx.html), [Windows](https://docs.gitlab.com/runner/install/windows.html), [FreeBSD](https://docs.gitlab.com/runner/install/freebsd.html), [Kubernetes](https://docs.gitlab.com/runner/install/kubernetes.html) and (soon) even [z/OS](https://gitlab.com/gitlab-org/gitlab-runner/issues/3263).

The Raspberry Pi has an ARM chip, so I used the ARM binary to install it with:

```
sudo wget -O /usr/local/bin/gitlab-runner [https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-arm](https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-arm)
```

Then I made the gitlab-runner binary executable with:

```
sudo chmod +x /usr/local/bin/gitlab-runner
```

After that, I installed it as a service with these commands:

```
sudo gitlab-runner install --user=pi
sudo gitlab-runner start
```

Once it was installed, [registering the runner](https://docs.gitlab.com/runner/register/)to be a private runner on my project was easy. I also added a [tag](https://docs.gitlab.com/ee/ci/runners/#using-tags) of prod to make sure it only ran code I tagged to run on “production” aka actually on my home network. I’m hoping this protects me from someone I like to call “future Brendan” who may or may not have the best memory when it comes to breaking things.

![](https://cdn-images-1.medium.com/max/1024/1*LOnN2a7R4gh0klcdIcG4cQ.png)<figcaption>Registering the GitLab runner</figcaption>

I chose a [shell](https://docs.gitlab.com/runner/executors/shell.html) [executor](https://docs.gitlab.com/runner/executors/README.html) so that it was simple to understand. Basically, the runner would just execute the commands I put in the script: section of my YAML. Just as if I had logged in and ran them myself.

#### Setting up the .gitlab-ci.yml

I had a few thoughts in mind when it came to setting up my pipeline for deployments. Some of the scripts required restarts of the DNS services on the Pi-hole, so I didn’t want them to be running all of the time. To prevent that, I used a number of GitLab CI/CD features:

- [only:refs](https://docs.gitlab.com/ee/ci/yaml/#onlyrefs-and-exceptrefs): Ensures we only run this on master — so if I’m on a branch trying something out (\*shakes fist at future Brendan\*) I don’t break anything.
- [only:changes](https://docs.gitlab.com/ee/ci/yaml/#onlychanges-and-exceptchanges): This allows me to limit the scope of the run to only the changes needed. For instance, a change to the whitelist won’t trigger an update to the local DNS list and vice versa.
- [tags](https://docs.gitlab.com/ee/ci/yaml/#tags): I mentioned this tag before, but this also means that any job I add must have the prod tag before it will run in production (aka the live Pi-hole).

As an example, let’s look at automating the whitelist. I already created a script ([whitelistme.sh](https://gitlab.com/olearycrew/pihole/blob/master/whitelistme.sh)) that automates it when ran. So getting that to run in GitLab CI/CD is as simple as this script:

```
whitelist:
  stage: deploy-prod
  script: 
    - echo "Run whitelist.sh"
    - ./whitelistme.sh
  only:
    refs:
      - master
    changes:
      - whitelistme.sh
  tags:
    - prod
```

Let’s break down each section of that script:

- For the stage, I created my own custom stage called deploy-prod.
- The script is very simple and echoes what it is about to do and runs the script at the root of the checkout with ./whitelistme.sh.
- The only section implements the two controls I was talking about earlier. refs: — master means this will only run on the master branch of the repository. changes: — whitelistme.sh means this will only run on a change to the whitelistme.sh script and not on every change to the repository. This ensures that script only runs when it needs to.
- “Tags” ensures that it runs on a tagged runner — in this case, the Pi-hole at home.

Success! Running my jobs on my Pi-hole in my home network — orchestrated all from GitLab. 😺

![](https://cdn-images-1.medium.com/max/654/1*hIWxVZ3SHPcsk4ApqJRwnQ.png)

### DNS as Code

Since FTL is mostly just dnsmasq with some customizations for Pi-hole, it is relatively easy to customize. In fact, by default, it includes an additional local file (and hostnames for the Pi-hole itself) in /etc/pihole/local.list like this:

```
10.0.0.xx pihole
10.0.0.xx pi.hole
```

Again, I wanted to make sure this was source controlled — and the dream of source controlled DNS is now a reality for me. The way I implemented it was to:

Create a [localDNS](https://gitlab.com/olearycrew/pihole/blob/master/localDNS) file that would contain all of the local DNS entries I wanted:

```
10.0.0.xx pihole
10.0.0.xx pi.hole

10.0.0.1 orbi.local

10.0.0.xx pirack0.local
```

Then I used GitLab CI/CD to automate replacing the /etc/pihole/local.list file with this one anytime it changed:

```
local-DNS:
  stage: deploy-prod
  script: 
    - echo "Copy localDNS to /etc/pihole/local.list"
    - sudo cp ./localDNS /etc/pihole/local.list
    - echo "Restart Pi-hole DNS"
    - pihole restartdns
  only:
    refs:
      - master
    changes:
      - localDNS
  tags:
    - prod
```

And Voilà! Source controlled and automated DNS-as-code (DaaS (tm) (r) (c))

### Frequently Asked Questions

Anticipating the questions you’ll have, I’ve prepared a short primer below:

1. Yes, I did bring down the internet in the whole house for about 20 minutes while I was tinkering away. Yes, this was while all my in-laws were here on their phones. Yes, I got a lot of grief for it
2. Yes, this will restart DNS as it is running, thus I wanted to only run the jobs as restricted above
3. What is this business about pirack0 in the DNS entry?! That will just have to wait for another post 😉

* * *