/
/
/
1---
2# ========================================
3# DNS STACK DEPLOYMENT (Pi-hole + Unbound)
4# ========================================
5# Deploys Pi-hole with Unbound as recursive DNS resolver
6# Provides ad-blocking and custom DNS resolution
7
8- name: "Display DNS stack deployment information"
9 ansible.builtin.debug:
10 msg:
11 - "Deploying DNS stack (Pi-hole + Unbound)"
12 - "Pi-hole enabled: {{ connectivity_pihole_enabled }}"
13 - "Unbound enabled: {{ connectivity_unbound_enabled }}"
14 - "Pi-hole Web Port: {{ connectivity_pihole_web_port }}"
15 - "DNS Port: {{ connectivity_pihole_dns_port }}"
16 - "Unbound Port: {{ connectivity_unbound_port }}"
17 tags: [dns-stack]
18
19# ========================================
20# UNBOUND RECURSIVE DNS RESOLVER
21# ========================================
22- name: "Deploy Unbound recursive DNS resolver"
23 block:
24 - name: "Create Unbound configuration directory"
25 ansible.builtin.file:
26 path: "{{ connectivity_docker_base_path }}/unbound/config"
27 state: directory
28 owner: "{{ connectivity_docker_owner }}"
29 group: "{{ connectivity_docker_group }}"
30 mode: "0755"
31
32 - name: "Create Unbound configuration file"
33 ansible.builtin.template:
34 src: unbound.conf.j2
35 dest: "{{ connectivity_docker_base_path }}/unbound/config/unbound.conf"
36 owner: "{{ connectivity_docker_owner }}"
37 group: "{{ connectivity_docker_group }}"
38 mode: "0644"
39 notify: restart unbound
40
41 - name: "Create Unbound Docker Compose file"
42 ansible.builtin.template:
43 src: unbound-compose.yml.j2
44 dest: "{{ connectivity_docker_base_path }}/unbound/docker-compose.yml"
45 owner: "{{ connectivity_docker_owner }}"
46 group: "{{ connectivity_docker_group }}"
47 mode: "0644"
48 notify: restart unbound
49
50 - name: "Start Unbound service"
51 community.docker.docker_compose:
52 project_src: "{{ connectivity_docker_base_path }}/unbound"
53 pull: yes
54 state: present
55
56 - name: "Wait for Unbound to be ready"
57 ansible.builtin.wait_for:
58 port: "{{ connectivity_unbound_port }}"
59 host: 127.0.0.1
60 delay: 5
61 timeout: 30
62
63 when: unbound_enabled | default(true)
64 tags: [dns-stack, unbound]
65
66# ========================================
67# PI-HOLE DNS SINKHOLE
68# ========================================
69- name: "Deploy Pi-hole DNS sinkhole"
70 block:
71 - name: "Create Pi-hole configuration directories"
72 ansible.builtin.file:
73 path: "{{ connectivity_docker_base_path }}/pihole/{{ item }}"
74 state: directory
75 owner: "{{ connectivity_docker_owner }}"
76 group: "{{ connectivity_docker_group }}"
77 mode: "0755"
78 loop:
79 - config
80 - dnsmasq.d
81
82 - name: "Create Pi-hole custom DNS configuration"
83 ansible.builtin.template:
84 src: pihole-custom.conf.j2
85 dest: "{{ connectivity_docker_base_path }}/pihole/dnsmasq.d/99-custom.conf"
86 owner: "{{ connectivity_docker_owner }}"
87 group: "{{ connectivity_docker_group }}"
88 mode: "0644"
89 notify: restart pihole
90
91 - name: "Create Pi-hole Docker Compose file"
92 ansible.builtin.template:
93 src: pihole-compose.yml.j2
94 dest: "{{ connectivity_docker_base_path }}/pihole/docker-compose.yml"
95 owner: "{{ connectivity_docker_owner }}"
96 group: "{{ connectivity_docker_group }}"
97 mode: "0644"
98 notify: restart pihole
99
100 - name: "Create Pi-hole environment file"
101 ansible.builtin.template:
102 src: pihole.env.j2
103 dest: "{{ connectivity_docker_base_path }}/pihole/.env"
104 owner: "{{ connectivity_docker_owner }}"
105 group: "{{ connectivity_docker_group }}"
106 mode: "0600" # Secure environment file
107 notify: restart pihole
108
109 - name: "Allow Pi-hole ports through firewall"
110 ansible.builtin.ufw:
111 rule: allow
112 port: "{{ item.port }}"
113 proto: "{{ item.proto }}"
114 comment: "{{ item.comment }}"
115 loop:
116 - { port: "{{ connectivity_pihole_web_port }}", proto: "tcp", comment: "Pi-hole Web Interface" }
117 - { port: "{{ connectivity_pihole_dns_port }}", proto: "udp", comment: "Pi-hole DNS UDP" }
118 - { port: "{{ connectivity_pihole_dns_port }}", proto: "tcp", comment: "Pi-hole DNS TCP" }
119
120 - name: "Start Pi-hole service"
121 community.docker.docker_compose:
122 project_src: "{{ connectivity_docker_base_path }}/pihole"
123 pull: yes
124 state: present
125
126 - name: "Wait for Pi-hole to be ready"
127 ansible.builtin.wait_for:
128 port: "{{ connectivity_pihole_web_port }}"
129 host: "{{ ansible_default_ipv4.address }}"
130 delay: 10
131 timeout: 60
132
133 when: pihole_enabled | default(true)
134 tags: [dns-stack, pihole]
135
136# ========================================
137# DNS STACK INTEGRATION WITH NPM
138# ========================================
139- name: "Create integrated DNS stack Docker Compose file"
140 ansible.builtin.template:
141 src: dns-stack-compose.yml.j2
142 dest: "{{ connectivity_docker_base_path }}/dns-stack-compose.yml"
143 owner: "{{ connectivity_docker_owner }}"
144 group: "{{ connectivity_docker_group }}"
145 mode: "0644"
146 when: connectivity_pihole_enabled and connectivity_unbound_enabled
147 tags: [dns-stack, compose]
148
149- name: "Configure Nginx Proxy Manager for DNS services"
150 block:
151 - name: "Create NPM proxy configuration for Pi-hole"
152 ansible.builtin.template:
153 src: npm-pihole-proxy.conf.j2
154 dest: "{{ connectivity_docker_base_path }}/nginx-proxy/conf.d/pihole-proxy.conf"
155 owner: "{{ connectivity_docker_owner }}"
156 group: "{{ connectivity_docker_group }}"
157 mode: "0644"
158 when: connectivity_nginx_proxy_enabled and connectivity_pihole_enabled
159
160 - name: "Create NPM proxy configuration for Unbound"
161 ansible.builtin.template:
162 src: npm-unbound-proxy.conf.j2
163 dest: "{{ connectivity_docker_base_path }}/nginx-proxy/conf.d/unbound-proxy.conf"
164 owner: "{{ connectivity_docker_owner }}"
165 group: "{{ connectivity_docker_group }}"
166 mode: "0644"
167 when: connectivity_nginx_proxy_enabled and connectivity_unbound_enabled
168
169 tags: [dns-stack, npm-integration]
170
171# ========================================
172# SERVICE VERIFICATION
173# ========================================
174- name: "Verify Unbound container is running"
175 community.docker.docker_container_info:
176 name: "{{ connectivity_unbound_container_name }}"
177 register: connectivity_unbound_container_status
178 when: unbound_enabled | default(true)
179 tags: [dns-stack, verify]
180
181- name: "Verify Pi-hole container is running"
182 community.docker.docker_container_info:
183 name: "{{ connectivity_pihole_container_name }}"
184 register: connectivity_pihole_container_status
185 when: pihole_enabled | default(true)
186 tags: [dns-stack, verify]
187
188- name: "Test DNS resolution through Pi-hole"
189 ansible.builtin.command: "dig @{{ ansible_default_ipv4.address }} google.com +short"
190 register: dns_test_result
191 changed_when: false
192 failed_when: false
193 when: pihole_enabled | default(true)
194 tags: [dns-stack, test]
195
196# ========================================
197# STATUS AND INFORMATION
198# ========================================
199- name: "Display DNS stack service status"
200 ansible.builtin.debug:
201 msg:
202 - "DNS stack deployed successfully"
203 - "Unbound status: {{ connectivity_unbound_container_status.container.State.Status | default('Disabled') }}"
204 - "Pi-hole status: {{ connectivity_pihole_container_status.container.State.Status | default('Disabled') }}"
205 - "Pi-hole Web UI: http://{{ ansible_default_ipv4.address }}:{{ connectivity_pihole_web_port }}/admin"
206 - "Pi-hole Password: {{ connectivity_pihole_password }}"
207 - "DNS Server: {{ ansible_default_ipv4.address }}:{{ connectivity_pihole_dns_port }}"
208 - "DNS Test Result: {{ dns_test_result.stdout | default('Not tested') }}"
209 - ""
210 - "Configuration:"
211 - "- Pi-hole uses Unbound as upstream DNS"
212 - "- Unbound performs recursive DNS resolution"
213 - "- Ad-blocking and custom DNS rules via Pi-hole"
214 - ""
215 - "Next steps:"
216 - "1. Configure client devices to use {{ ansible_default_ipv4.address }} as DNS"
217 - "2. Access Pi-hole admin interface to customize blocking lists"
218 - "3. Add custom DNS entries via Pi-hole interface"
219 tags: [dns-stack, info]
220
221
222# ========================================
223# SERVICE LABELING
224# ========================================
225- name: "Label DNS stack containers for connectivity service group"
226 community.docker.docker_container:
227 name: "{{ item.name }}"
228 labels:
229 com.connectivity.service: "dns-stack"
230 com.connectivity.type: "{{ item.type }}"
231 com.connectivity.port: "{{ item.port }}"
232 state: started
233 recreate: no
234 loop:
235 - { name: "{{ connectivity_unbound_container_name }}", type: "recursive-dns", port: "{{ connectivity_unbound_port }}" }
236 - { name: "{{ connectivity_pihole_container_name }}", type: "dns-sinkhole", port: "{{ connectivity_pihole_dns_port }}" }
237 when:
238 - item.name in (ansible_facts.docker_containers | default([]))
239 - (item.name == connectivity_unbound_container_name and connectivity_unbound_enabled) or (item.name == connectivity_pihole_container_name and connectivity_pihole_enabled)
240 tags: [dns-stack, labels]
241
242# ========================================
243# OPTIONAL DHCP CONFIGURATION
244# ========================================
245- name: "Configure Pi-hole DHCP (if enabled)"
246 block:
247 - name: "Enable Pi-hole DHCP server"
248 ansible.builtin.lineinfile:
249 path: "{{ connectivity_docker_base_path }}/pihole/dnsmasq.d/99-custom.conf"
250 line: "dhcp-range={{ connectivity_pihole_dhcp_range | default('192.168.1.100,192.168.1.200,24h') }}"
251 create: yes
252 notify: restart pihole
253
254 - name: "Allow DHCP port through firewall"
255 ansible.builtin.ufw:
256 rule: allow
257 port: "{{ connectivity_pihole_dhcp_port }}"
258 proto: udp
259 comment: "Pi-hole DHCP Server"
260
261 when: connectivity_pihole_dhcp_enabled | default(false)
262 tags: [dns-stack, dhcp]