summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAhmed AbdelHalim <[email protected]>2026-06-17 18:37:49 +0200
committerAhmed AbdelHalim <[email protected]>2026-06-17 18:42:02 +0200
commit38691ef7e615bc8ff7a221969dde08eb848c7391 (patch)
treefe8a0bfc1bc31dc93a8138cce179df2416875bf4
parent6f0a83261a73808fd7d4ace408140bed2775c359 (diff)
Refactor pi roles to use .home.arpa subdomains for services
-rw-r--r--.gitignore1
-rw-r--r--README.md15
-rw-r--r--host_vars/rpi5.local.ymlbin2061 -> 2359 bytes
-rw-r--r--host_vars/rpi5.local.yml.example10
-rw-r--r--roles/grafana/defaults/main.yml1
-rw-r--r--roles/grafana/handlers/main.yml6
-rw-r--r--roles/grafana/meta/argument_specs.yml4
-rw-r--r--roles/grafana/tasks/main.yml15
-rw-r--r--roles/grafana/templates/grafana.ini.j24
-rw-r--r--roles/grafana/templates/grafana.nginx.conf.j210
-rw-r--r--roles/nginx/tasks/main.yml9
-rw-r--r--roles/nginx/templates/nginx.conf.j22
-rw-r--r--roles/pihole/defaults/main.yml3
-rw-r--r--roles/pihole/handlers/main.yml12
-rw-r--r--roles/pihole/meta/argument_specs.yml13
-rw-r--r--roles/pihole/tasks/main.yml22
-rw-r--r--roles/pihole/templates/pihole.nginx.conf.j217
-rw-r--r--roles/pihole/templates/pihole.toml.j23
-rw-r--r--roles/prometheus/defaults/main.yml1
-rw-r--r--roles/prometheus/handlers/main.yml6
-rw-r--r--roles/prometheus/meta/argument_specs.yml4
-rw-r--r--roles/prometheus/tasks/main.yml15
-rw-r--r--roles/prometheus/templates/prometheus.nginx.conf.j210
-rw-r--r--roles/wg_portal/defaults/main.yml2
-rw-r--r--roles/wg_portal/meta/argument_specs.yml8
-rw-r--r--roles/wg_portal/tasks/main.yml25
-rw-r--r--roles/wg_portal/templates/wg_portal.nginx.conf.j210
27 files changed, 184 insertions, 44 deletions
diff --git a/.gitignore b/.gitignore
index 18d7d2ab..f6d4c7d6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
.ansible
CLAUDE.md
+.claude
diff --git a/README.md b/README.md
index 9dca1949..8f05865b 100644
--- a/README.md
+++ b/README.md
@@ -48,6 +48,21 @@ ansible-galaxy install -r requirements.yml
ansible-playbook site.yml --ask-become-pass --limit ${HOSTNAME}
```
+## Raspberry Pi Services
+
+Services deployed on `rpi5.local` and their default FQDNs (resolved via Pi-hole DNS):
+
+| Service | Default FQDN | Description |
+|---|---|---|
+| Pi-hole | `dns.home.arpa` | DNS filtering and ad blocking |
+| WireGuard Portal | `vpn.home.arpa` | WireGuard VPN management UI |
+| Grafana | `monitor.home.arpa` | Metrics dashboards |
+| Prometheus | `metrics.home.arpa` | Metrics collection |
+
+DNS records are managed via `pihole_dns_hosts` in `host_vars/rpi5.local.yml`.
+Override the default FQDN per service using `pihole_hostname`, `wg_portal_hostname`,
+`grafana_hostname`, or `prometheus_hostname`.
+
## Special Thanks to
- [Jeff Geerling](https://www.jeffgeerling.com/), who I learned a **LOT** from his open-source work.
diff --git a/host_vars/rpi5.local.yml b/host_vars/rpi5.local.yml
index fd4cb1d4..356a1076 100644
--- a/host_vars/rpi5.local.yml
+++ b/host_vars/rpi5.local.yml
Binary files differ
diff --git a/host_vars/rpi5.local.yml.example b/host_vars/rpi5.local.yml.example
index 49fcc3ba..95308832 100644
--- a/host_vars/rpi5.local.yml.example
+++ b/host_vars/rpi5.local.yml.example
@@ -5,6 +5,11 @@ network_ipv4_gateway: "10.0.0.1"
network_ipv6_address: "fd5c:fd8b:2b8c::254/64"
network_ipv6_gateway: "fd5c:fd8b:2b8c::1"
+pihole_hostname: "dns.home.arpa"
+wg_portal_hostname: "vpn.home.arpa"
+grafana_hostname: "monitor.home.arpa"
+prometheus_hostname: "metrics.home.arpa"
+
# TOTP generator: `openssl rand -base64 32 | head -c "20" | base32`
pihole_totp_secret: "CHANGEME"
pihole_password: "{{ ('changeme' | hash('sha256') | hash('sha256'))[:64] }}"
@@ -16,6 +21,11 @@ pihole_dhcp_router: "{{ network_ipv4_address }}"
pihole_dhcp_hosts:
- "ff:ff:ff:ff:ff:fe, 10.0.0.252,TV"
- "ff:ff:ff:ff:ff:ff, 10.0.0.253,Printer"
+pihole_dns_hosts:
+ - "{{ network_ipv4_address }} {{ pihole_hostname }}"
+ - "{{ network_ipv4_address }} {{ wg_portal_hostname }}"
+ - "{{ network_ipv4_address }} {{ grafana_hostname }}"
+ - "{{ network_ipv4_address }} {{ prometheus_hostname }}"
wireguard_autostart_connection: "vpn2"
wireguard_connections:
diff --git a/roles/grafana/defaults/main.yml b/roles/grafana/defaults/main.yml
index e61aeded..0cbbb71b 100644
--- a/roles/grafana/defaults/main.yml
+++ b/roles/grafana/defaults/main.yml
@@ -11,3 +11,4 @@ grafana_datasources:
default: true
grafana_dashboards: []
+grafana_hostname: "monitor.home.arpa"
diff --git a/roles/grafana/handlers/main.yml b/roles/grafana/handlers/main.yml
index 408c8c3d..b212487b 100644
--- a/roles/grafana/handlers/main.yml
+++ b/roles/grafana/handlers/main.yml
@@ -4,3 +4,9 @@
ansible.builtin.systemd_service:
name: "{{ grafana_service }}"
state: "restarted"
+
+- name: "Restart nginx"
+ become: true
+ ansible.builtin.systemd_service:
+ name: "nginx"
+ state: "restarted"
diff --git a/roles/grafana/meta/argument_specs.yml b/roles/grafana/meta/argument_specs.yml
index fee43a8c..5a38b97d 100644
--- a/roles/grafana/meta/argument_specs.yml
+++ b/roles/grafana/meta/argument_specs.yml
@@ -48,6 +48,10 @@ argument_specs:
description: "Whether this is the default datasource"
type: "bool"
default: false
+ grafana_hostname:
+ type: "str"
+ description: "FQDN for the grafana nginx vhost (e.g. 'monitor.home.arpa')."
+ default: "monitor.home.arpa"
grafana_dashboards:
description: "List of community dashboards to download and provision"
type: "list"
diff --git a/roles/grafana/tasks/main.yml b/roles/grafana/tasks/main.yml
index 3e29489b..f1fa479e 100644
--- a/roles/grafana/tasks/main.yml
+++ b/roles/grafana/tasks/main.yml
@@ -86,3 +86,18 @@
name: "{{ grafana_service }}"
state: "started"
enabled: true
+
+- name: "Create grafana nginx vhost configuration"
+ become: true
+ when: grafana_hostname | length > 0
+ ansible.builtin.template:
+ src: "grafana.nginx.conf.j2"
+ dest: "/etc/nginx/vhosts.d/grafana.conf"
+ owner: "root"
+ group: "root"
+ mode: "0644"
+ backup: true
+ validate: >
+ bash -c 'echo "events { worker_connections 64; } http { include %s; }" > /tmp/nginx-vhost.conf;
+ sudo nginx -T -c /tmp/nginx-vhost.conf; ec=$?; rm -f /tmp/nginx-vhost.conf; exit $ec'
+ notify: "Restart nginx"
diff --git a/roles/grafana/templates/grafana.ini.j2 b/roles/grafana/templates/grafana.ini.j2
index 7685bed2..05166994 100644
--- a/roles/grafana/templates/grafana.ini.j2
+++ b/roles/grafana/templates/grafana.ini.j2
@@ -1,6 +1,8 @@
[server]
http_port = {{ grafana_port }}
-root_url = http://localhost:{{ grafana_port }}/
+{% if grafana_hostname | length > 0 %}
+root_url = http://{{ grafana_hostname }}/
+{% endif %}
[database]
type = {{ grafana_database_type }}
diff --git a/roles/grafana/templates/grafana.nginx.conf.j2 b/roles/grafana/templates/grafana.nginx.conf.j2
new file mode 100644
index 00000000..e6e1052c
--- /dev/null
+++ b/roles/grafana/templates/grafana.nginx.conf.j2
@@ -0,0 +1,10 @@
+server {
+ listen 80;
+ listen [::]:80;
+
+ server_name {{ grafana_hostname }};
+
+ location / {
+ proxy_pass http://127.0.0.1:{{ grafana_port }}/;
+ }
+}
diff --git a/roles/nginx/tasks/main.yml b/roles/nginx/tasks/main.yml
index f913272e..456f088f 100644
--- a/roles/nginx/tasks/main.yml
+++ b/roles/nginx/tasks/main.yml
@@ -21,6 +21,15 @@
- "/etc/nginx/modules-enabled"
- "/var/log/nginx"
+- name: "Ensure nginx vhosts.d directory exists"
+ become: true
+ ansible.builtin.file:
+ path: "/etc/nginx/vhosts.d"
+ state: "directory"
+ owner: "root"
+ group: "root"
+ mode: "0755"
+
- name: "Check if SSL certificate exists"
become: true
ansible.builtin.stat:
diff --git a/roles/nginx/templates/nginx.conf.j2 b/roles/nginx/templates/nginx.conf.j2
index 1bce57da..1ebbe3df 100644
--- a/roles/nginx/templates/nginx.conf.j2
+++ b/roles/nginx/templates/nginx.conf.j2
@@ -76,4 +76,6 @@ http {
include /etc/nginx/conf.d/*.conf;
}
+
+ include /etc/nginx/vhosts.d/*.conf;
}
diff --git a/roles/pihole/defaults/main.yml b/roles/pihole/defaults/main.yml
index 4e1d0bf7..d980c67c 100644
--- a/roles/pihole/defaults/main.yml
+++ b/roles/pihole/defaults/main.yml
@@ -16,4 +16,5 @@ pihole_dhcp_domain: "local"
pihole_dhcp_hosts: []
pihole_domain: ""
pihole_port: "8081"
-pihole_by_nginx: false
+pihole_hostname: "dns.home.arpa"
+pihole_dns_hosts: []
diff --git a/roles/pihole/handlers/main.yml b/roles/pihole/handlers/main.yml
index 1cad8eff..d839828e 100644
--- a/roles/pihole/handlers/main.yml
+++ b/roles/pihole/handlers/main.yml
@@ -14,3 +14,15 @@
- name: "Show install output"
ansible.builtin.debug:
var: pihole_install.stdout
+
+- name: "Restart pihole-FTL"
+ become: true
+ ansible.builtin.systemd_service:
+ name: "pihole-FTL"
+ state: "restarted"
+
+- name: "Restart nginx"
+ become: true
+ ansible.builtin.systemd_service:
+ name: "nginx"
+ state: "restarted"
diff --git a/roles/pihole/meta/argument_specs.yml b/roles/pihole/meta/argument_specs.yml
index adca47b9..40662436 100644
--- a/roles/pihole/meta/argument_specs.yml
+++ b/roles/pihole/meta/argument_specs.yml
@@ -63,7 +63,12 @@ argument_specs:
type: "str"
description: "The port to serve pihole on, when empty use pihole default 80,433"
default: "8081"
- pihole_by_nginx:
- description: "Serve pihole behind nginx reverse proxy"
- type: "bool"
- default: false
+ pihole_hostname:
+ type: "str"
+ description: "FQDN for the pihole nginx vhost (e.g. 'dns.home.arpa')."
+ default: "dns.home.arpa"
+ pihole_dns_hosts:
+ type: "list"
+ description: "Custom DNS A records written to pihole.toml [dns] hosts (format: 'IP HOSTNAME')"
+ elements: "str"
+ default: []
diff --git a/roles/pihole/tasks/main.yml b/roles/pihole/tasks/main.yml
index 52ccafcf..66208bdf 100644
--- a/roles/pihole/tasks/main.yml
+++ b/roles/pihole/tasks/main.yml
@@ -149,25 +149,17 @@
tags:
- molecule-idempotence-notest
-- name: "Create pihole nginx configurations"
+- name: "Create pihole nginx vhost configuration"
become: true
- when: pihole_by_nginx is defined and pihole_by_nginx | bool
- ansible.builtin.copy:
- content: |
- location /admin/ {
- proxy_pass http://127.0.0.1:{{ pihole_port }}/admin/;
- }
- location /api/ {
- proxy_pass http://127.0.0.1:{{ pihole_port }}/api/;
- }
- dest: "/etc/nginx/conf.d/pihole.conf"
+ when: pihole_hostname | length > 0
+ ansible.builtin.template:
+ src: "pihole.nginx.conf.j2"
+ dest: "/etc/nginx/vhosts.d/pihole.conf"
owner: "root"
group: "root"
mode: "0644"
backup: true
- # workaround issue: https://github.com/ansible/ansible/issues/9112
- # ref: https://serverfault.com/a/811520
validate: >
- bash -c 'echo "events { worker_connections 2; } http { server { include %s; } }" > /tmp/nginx.conf;
- sudo nginx -T -c /tmp/nginx.conf; ec=$?; rm -f /tmp/nginx.conf; exit $ec'
+ bash -c 'echo "events { worker_connections 64; } http { include %s; }" > /tmp/nginx-vhost.conf;
+ sudo nginx -T -c /tmp/nginx-vhost.conf; ec=$?; rm -f /tmp/nginx-vhost.conf; exit $ec'
notify: "Restart nginx"
diff --git a/roles/pihole/templates/pihole.nginx.conf.j2 b/roles/pihole/templates/pihole.nginx.conf.j2
new file mode 100644
index 00000000..91f0fea4
--- /dev/null
+++ b/roles/pihole/templates/pihole.nginx.conf.j2
@@ -0,0 +1,17 @@
+server {
+ listen 80;
+ listen [::]:80;
+
+ server_name {{ pihole_hostname }};
+
+ location = / {
+ return 301 /admin/;
+ }
+
+ location /admin/ {
+ proxy_pass http://127.0.0.1:{{ pihole_port }}/admin/;
+ }
+ location /api/ {
+ proxy_pass http://127.0.0.1:{{ pihole_port }}/api/;
+ }
+}
diff --git a/roles/pihole/templates/pihole.toml.j2 b/roles/pihole/templates/pihole.toml.j2
index 13f7ba1f..a755040b 100644
--- a/roles/pihole/templates/pihole.toml.j2
+++ b/roles/pihole/templates/pihole.toml.j2
@@ -37,6 +37,9 @@ interface = "{{ pihole_interface }}"
# - "NONE"
# Do not add any configuration concerning the listening mode to the dnsmasq config file.
listeningMode = "LOCAL"
+{% if pihole_dns_hosts | length > 0 %}
+hosts = {{ pihole_dns_hosts | to_json }}
+{% endif %}
[dns.cache]
size = 10000 # Cache size of the DNS server.
diff --git a/roles/prometheus/defaults/main.yml b/roles/prometheus/defaults/main.yml
index 7a231b5c..cd91dee6 100644
--- a/roles/prometheus/defaults/main.yml
+++ b/roles/prometheus/defaults/main.yml
@@ -8,3 +8,4 @@ prometheus_targets:
- "{{ prometheus_host }}:{{ prometheus_port }}"
prometheus_node_exporter_targets: []
+prometheus_hostname: "metrics.home.arpa"
diff --git a/roles/prometheus/handlers/main.yml b/roles/prometheus/handlers/main.yml
index d35a8531..b42a2391 100644
--- a/roles/prometheus/handlers/main.yml
+++ b/roles/prometheus/handlers/main.yml
@@ -4,3 +4,9 @@
ansible.builtin.systemd_service:
name: "prometheus"
state: "restarted"
+
+- name: "Restart nginx"
+ become: true
+ ansible.builtin.systemd_service:
+ name: "nginx"
+ state: "restarted"
diff --git a/roles/prometheus/meta/argument_specs.yml b/roles/prometheus/meta/argument_specs.yml
index e1a72307..5f908119 100644
--- a/roles/prometheus/meta/argument_specs.yml
+++ b/roles/prometheus/meta/argument_specs.yml
@@ -28,3 +28,7 @@ argument_specs:
type: "list"
elements: "str"
default: []
+ prometheus_hostname:
+ type: "str"
+ description: "FQDN for the prometheus nginx vhost (e.g. 'metrics.home.arpa')."
+ default: "metrics.home.arpa"
diff --git a/roles/prometheus/tasks/main.yml b/roles/prometheus/tasks/main.yml
index 1f639c6d..8e315bec 100644
--- a/roles/prometheus/tasks/main.yml
+++ b/roles/prometheus/tasks/main.yml
@@ -61,3 +61,18 @@
name: "prometheus"
state: "started"
enabled: true
+
+- name: "Create prometheus nginx vhost configuration"
+ become: true
+ when: prometheus_hostname | length > 0
+ ansible.builtin.template:
+ src: "prometheus.nginx.conf.j2"
+ dest: "/etc/nginx/vhosts.d/prometheus.conf"
+ owner: "root"
+ group: "root"
+ mode: "0644"
+ backup: true
+ validate: >
+ bash -c 'echo "events { worker_connections 64; } http { include %s; }" > /tmp/nginx-vhost.conf;
+ sudo nginx -T -c /tmp/nginx-vhost.conf; ec=$?; rm -f /tmp/nginx-vhost.conf; exit $ec'
+ notify: "Restart nginx"
diff --git a/roles/prometheus/templates/prometheus.nginx.conf.j2 b/roles/prometheus/templates/prometheus.nginx.conf.j2
new file mode 100644
index 00000000..5ae9c20c
--- /dev/null
+++ b/roles/prometheus/templates/prometheus.nginx.conf.j2
@@ -0,0 +1,10 @@
+server {
+ listen 80;
+ listen [::]:80;
+
+ server_name {{ prometheus_hostname }};
+
+ location / {
+ proxy_pass http://127.0.0.1:{{ prometheus_port }}/;
+ }
+}
diff --git a/roles/wg_portal/defaults/main.yml b/roles/wg_portal/defaults/main.yml
index 38f1bda7..3d47add4 100644
--- a/roles/wg_portal/defaults/main.yml
+++ b/roles/wg_portal/defaults/main.yml
@@ -2,4 +2,4 @@
wg_portal_version: "latest"
wg_portal_port: "8080"
wg_portal_password: "{{ ('changeme' | hash('sha256') | hash('sha256'))[:64] }}"
-wg_portal_by_nginx: false
+wg_portal_hostname: "vpn.home.arpa"
diff --git a/roles/wg_portal/meta/argument_specs.yml b/roles/wg_portal/meta/argument_specs.yml
index 3ffdc604..eee9d7ed 100644
--- a/roles/wg_portal/meta/argument_specs.yml
+++ b/roles/wg_portal/meta/argument_specs.yml
@@ -14,7 +14,7 @@ argument_specs:
description: "Password hash for wg-portal authentication"
type: "str"
default: "{{ ('changeme' | hash('sha256') | hash('sha256'))[:64] }}"
- wg_portal_by_nginx:
- description: "Serve wg_portal behind nginx reverse proxy"
- type: "bool"
- default: false
+ wg_portal_hostname:
+ type: "str"
+ description: "FQDN for the wg-portal nginx vhost (e.g. 'vpn.home.arpa')."
+ default: "vpn.home.arpa"
diff --git a/roles/wg_portal/tasks/main.yml b/roles/wg_portal/tasks/main.yml
index a7962919..78a235a1 100644
--- a/roles/wg_portal/tasks/main.yml
+++ b/roles/wg_portal/tasks/main.yml
@@ -94,28 +94,17 @@
state: "started"
enabled: true
-- name: "Create wg-portal nginx configurations"
+- name: "Create wg-portal nginx vhost configuration"
become: true
- when: wg_portal_by_nginx is defined and wg_portal_by_nginx | bool
- ansible.builtin.copy:
- content: |
- location / {
- proxy_pass http://127.0.0.1:{{ wg_portal_port }}/;
- }
- location /api/connections {
- proxy_pass http://127.0.0.1:{{ wg_portal_port }}/api/connections;
- }
- location /api/status {
- proxy_pass http://127.0.0.1:{{ wg_portal_port }}/api/status;
- }
- dest: "/etc/nginx/conf.d/wg-portal.conf"
+ when: wg_portal_hostname | length > 0
+ ansible.builtin.template:
+ src: "wg_portal.nginx.conf.j2"
+ dest: "/etc/nginx/vhosts.d/wg-portal.conf"
owner: "root"
group: "root"
mode: "0644"
backup: true
- # workaround issue: https://github.com/ansible/ansible/issues/9112
- # ref: https://serverfault.com/a/811520
validate: >
- bash -c 'echo "events { worker_connections 2; } http { server { include %s; } }" > /tmp/nginx.conf;
- sudo nginx -T -c /tmp/nginx.conf; ec=$?; rm -f /tmp/nginx.conf; exit $ec'
+ bash -c 'echo "events { worker_connections 64; } http { include %s; }" > /tmp/nginx-vhost.conf;
+ sudo nginx -T -c /tmp/nginx-vhost.conf; ec=$?; rm -f /tmp/nginx-vhost.conf; exit $ec'
notify: "Restart nginx"
diff --git a/roles/wg_portal/templates/wg_portal.nginx.conf.j2 b/roles/wg_portal/templates/wg_portal.nginx.conf.j2
new file mode 100644
index 00000000..734ecac9
--- /dev/null
+++ b/roles/wg_portal/templates/wg_portal.nginx.conf.j2
@@ -0,0 +1,10 @@
+server {
+ listen 80;
+ listen [::]:80;
+
+ server_name {{ wg_portal_hostname }};
+
+ location / {
+ proxy_pass http://127.0.0.1:{{ wg_portal_port }}/;
+ }
+}