Install Pi-hole and manage local DNS with Ansible
ansible homelab networking piholeIn this article we will install Pi-hole as our DNS server, and create local hosts and DNS records.
Prerequisites
- Ansible
- A host to install Pi-hole with Docker and Python library for Docker installed
Install Pi-hole
Disable network resolution:
- name: disable systemd-resolved
systemd:
name: systemd-resolved.service
state: stopped
enabled: no
become: yes
We are going to bind two configuration folders from the host to docker: one for Pi-hole settings and the other for dnsmasq settings. Let’s define them as variables:
pihole_conf_dir: "{{ ansible_user_dir }}/pihole_data/etc-pihole"
pihole_dnsmasq_dir: "{{ ansible_user_dir }}/pihole_data/etc-dnsmasq.d"
Create the required directories:
- name: create data directories
file:
path: "{{ item }}"
state: directory
loop:
- "{{ pihole_conf_dir }}"
- "{{ pihole_dnsmasq_dir }}"
Before running the container creation, set the resolver namespaces to Cloudflare ones temporarily:
- name: set temporary dns server
replace:
path: /etc/resolv.conf
regexp: "^nameserver .*$"
replace: "nameserver 1.1.1.1"
become: yes
Run Pi-hole container:
- name: run pihole
docker_container:
name: pihole
state: started
image: pihole/pihole:latest
restart_policy: unless-stopped
hostname: pi.hole
env:
TZ: "{{ lookup('pipe', 'cat /etc/timezone') }}"
VIRTUAL_HOST: "pi.hole"
PROXY_LOCATION: "pi.hole"
ServerIP: "127.0.0.1"
dns_servers:
- "127.0.0.1"
- "1.1.1.1"
ports:
- "53:53"
- "53:53/udp"
- "8001:80"
volumes:
- "{{ pihole_conf_dir }}/:/etc/pihole/"
- "{{ pihole_dnsmasq_dir }}/:/etc/dnsmasq.d/"
Now, replace the Cloudflare DNS resolver to 127.0.0.1:
- name: set localhost dns server
replace:
path: /etc/resolv.conf
regexp: "^nameserver .*$"
replace: "nameserver 127.0.0.1"
become: yes
Configure Pi-hole
Now, we can go to http://{host_ip}:8001/admin and log in with our password (in the docker container logs). There, we go to Settings > DNS and enable conditional forwarding, pointint to our DHCP (our router in most of the cases)
Then, in our DHCP configuration, we need to add the host IP as our first DNS server. If we deploy more Pi-hole instances for redundancy, we’ll need to add thir IPs there as well. In Unifi, we can go to networks, select our LAN network and edit the DHCP DNS server.
At this point, we may need to reconnect to our network or forget the network and connect again.
DNS configuration
In Pi-hole, if we go to Local DNS / DNS Records, we can see that our
hosts list will be read from /etc/hosts and /etc/pihole/custom.list. We
mounted pihole_conf_dir
at /etc/pihole/, so we can create
the hosts template (templates/hosts.j2
) as:
{% for item in pihole_hosts %}
{{ item.ip }} {{ item.domain }}
{% endfor %}
Define our hosts, for example:
pihole_hosts:
- { domain: rpi, ip: 192.168.1.16 }
- { domain: mgmt, ip: 192.168.1.19 }
And create our hosts file:
- name: create pihole hosts
template:
src: templates/hosts.j2
dest: "{{ pihole_conf_dir }}/custom.list"
become: yes
Our CNAME records are displayed in Local DNS / CNAME Records. We can
add CNAME records by creating a file in our dnsmasq directory
(pihole_dnsmasq_dir
) usint the template
(templates/cnames.j2
):
{% for item in pihole_cnames %}
cname={{ item.domain }},{{ item.target_domain }}
{% endfor %}
Define our CNAME records, for example:
pihole_cnames:
- { domain: homeassistant, target_domain: rpi}
- { domain: nginx, target_domain: mgmt}
And create our dnsmasq configuration file:
- name: create pihole cname records
template:
src: templates/cnames.j2
dest: "{{ pihole_dnsmasq_dir }}/02-custom-cnames.conf"
become: yes
The hosts file (DNS Records in Pi-hole) don’t act as a DNS records,
since wildcard domains are not supported. To add wildcard domains we can
use the following template (templates/domains.js
):
{% for item in pihole_domains %}
address=/{{ item.domain }}/{{ item.ip }}
{% endfor %}
Let’s say we want to create a local domain called homelab.local with subdomains allowed, so we can use pihole.homelab.local pointing to our Pi-hole host, say 192.168.1.23:
pihole_domains:
- { domain: homelab.local, ip: 192.168.1.23 }
Then, create another dnsmasq configuration file:
- name: create pihole domain records
template:
src: templates/domains.j2
dest: "{{ pihole_dnsmasq_dir }}/03-custom-domains.conf"
become: yes