fix(web-app-pihole): migrate to meta/services.yml, fix domain resolution, disable native password

This commit is contained in:
Prageeth Panicker authored and kevinveenbirkenbach committed 2026-06-24 04:54:10 +02:00
1 parent b5bf8b4e6f
commit f65f4d60fb
7 files changed
+74 -97

No files matched your search

+19 -20
View File
@@ -14,26 +14,35 @@ Deploys [Pi-hole](https://pi-hole.net/) — a network-wide DNS sinkhole for ad a
## Authentication
Pi-hole's native web interface is protected by **OAuth2 proxy** backed by Keycloak. Only users in the `web-app-pihole-administrators` LDAP role have access to the dashboard.
Pi-hole's native web interface is protected by **OAuth2 proxy** backed by Keycloak. Only users in the `web-app-pihole-administrator` LDAP group have access to the dashboard.
Pi-hole's own password authentication is not used when OAuth2 is active (`compose.services.oauth2.enabled: true`).
Pi-hole's own password authentication is automatically disabled when OAuth2 is active.
## Configuration
Key settings in `config/main.yml`:
Key settings in `meta/services.yml`:
| Key | Default | Description |
|-----|---------|-------------|
| `compose.services.oauth2.enabled` | `true` | Enable Keycloak OAuth2 proxy protection |
| `compose.services.oauth2.allowed_groups` | `web-app-pihole-administrators` | LDAP groups allowed access |
| `compose.services.pihole.version` | `latest` | Docker image tag |
| `pihole.upstream_dns` | `1.1.1.1;1.0.0.1` | Upstream DNS servers (semicolon-separated) |
| `server.domains.canonical` | `pihole.{{ DOMAIN_PRIMARY }}` | Public domain |
| `oauth2.enabled` | `true` | Enable Keycloak OAuth2 proxy protection |
| `oauth2.origin.host` | `pihole` | Backend container name |
| `oauth2.origin.port` | `80` | Backend container port |
| `pihole.image` | `pihole/pihole` | Docker image |
| `pihole.version` | `latest` | Docker image tag |
| `pihole.ports.local.http` | `8041` | Host-bound HTTP port |
| `pihole.ports.local.oauth2` | `16493` | Host-bound OAuth2 proxy port |
Upstream DNS can be overridden in your inventory:
```yaml
applications:
web-app-pihole:
pihole:
upstream_dns: "9.9.9.9;149.112.112.112"
```
## Upstream DNS Options
Override `pihole.upstream_dns` in your inventory to change the upstream resolver:
| Provider | Value |
|----------|-------|
| Cloudflare | `1.1.1.1;1.0.0.1` |
@@ -41,16 +50,6 @@ Override `pihole.upstream_dns` in your inventory to change the upstream resolver
| Quad9 (filtered) | `9.9.9.9;149.112.112.112` |
| Quad9 (unfiltered) | `9.9.9.10;149.112.112.10` |
| OpenDNS | `208.67.222.222;208.67.220.220` |
| Custom | `<primary>;<secondary>` |
Example inventory override:
```yaml
applications:
web-app-pihole:
pihole:
upstream_dns: "9.9.9.9;149.112.112.112"
```
## DNS Configuration
-63
View File
@@ -1,63 +0,0 @@
title: "Pi-hole"
server:
status_codes:
default: [200, 301, 302, 403]
csp:
flags: {}
whitelist: {}
domains:
canonical:
- pihole.{{ DOMAIN_PRIMARY }}
aliases: []
compose:
services:
# noqa: shared
oauth2:
enabled: true
origin:
host: "pihole"
port: "80"
allowed_groups:
- "{{ [RBAC.GROUP.NAME, 'web-app-pihole-administrator'] | path_join }}"
logout:
enabled: true
shared: true
dashboard:
enabled: true
shared: true
matomo:
enabled: true
shared: true
email:
enabled: false
shared: true
redis:
enabled: true
shared: true
backup:
disabled: true
cpus: "0.25"
mem_reservation: "128m"
mem_limit: "256m"
pids_limit: 512
pihole:
enabled: false
shared: false
backup:
no_stop_required: true
image: "pihole/pihole"
version: "latest"
name: "pihole"
min_storage: "1GB"
port: 80
cpus: "0.5"
mem_reservation: "128m"
mem_limit: "256m"
pids_limit: 512
volumes:
data: "pihole_data"
dnsmasq: "pihole_dnsmasq"
network: "pihole"
pihole:
upstream_dns: "1.1.1.1;1.0.0.1"
timezone: "{{ HOST_TIMEZONE }}"
+4
View File
@@ -1,3 +1,7 @@
domains:
canonical:
- pihole.{{ DOMAIN_PRIMARY }}
aliases: []
networks:
local:
subnet: 192.168.102.240/28
+30
View File
@@ -0,0 +1,30 @@
# noqa: shared
oauth2:
enabled: true
shared: true
origin:
host: pihole
port: 80
logout:
enabled: true
shared: true
dashboard:
enabled: true
shared: true
matomo:
enabled: true
shared: true
email:
enabled: false
shared: true
redis:
enabled: true
shared: true
pihole:
image: pihole/pihole
version: latest
ports:
local:
http: 8041
oauth2: 16493
lifecycle: alpha
+7 -1
View File
@@ -1,6 +1,12 @@
- name: "Wait for Pi-hole HTTP endpoint"
wait_for:
host: "{{ DOCKER_REACH_HOST }}"
port: "{{ ports.localhost.http[application_id] }}"
port: "{{ lookup('config', application_id, 'services.pihole.ports.local.http') }}"
delay: 5
timeout: 120
- name: "Disable Pi-hole native password (OAuth2 handles auth)"
community.docker.docker_container_exec:
container: "{{ PIHOLE_CONTAINER }}"
command: pihole setpassword ''
when: PIHOLE_OAUTH2_ENABLED | bool
@@ -10,7 +10,7 @@
WEBPASSWORD: "{{ PIHOLE_PASSWORD }}"
PIHOLE_DNS_: "{{ PIHOLE_UPSTREAM_DNS }}"
ports:
- "{{ DOCKER_BIND_HOST }}:{{ ports.localhost.http[application_id] }}:80/tcp"
- "{{ DOCKER_BIND_HOST }}:{{ lookup('config', application_id, 'services.pihole.ports.local.http') }}:80/tcp"
- "{{ DOCKER_BIND_HOST }}:53:53/tcp"
- "{{ DOCKER_BIND_HOST }}:53:53/udp"
cap_add:
+13 -12
View File
@@ -1,20 +1,21 @@
# General
application_id: "web-app-pihole"
entity_name: "{{ application_id | get_entity_name }}"
domain: "{{ lookup('domain', application_id) }}"
# Pi-hole
# https://pi-hole.net/
PIHOLE_VERSION: "{{ lookup('config', application_id, 'compose.services.pihole.version') }}"
PIHOLE_IMAGE: "{{ lookup('config', application_id, 'compose.services.pihole.image') }}"
PIHOLE_CONTAINER: "{{ lookup('config', application_id, 'compose.services.pihole.name') }}"
PIHOLE_VOLUME_DATA: "{{ lookup('config', application_id, 'compose.volumes.data') }}"
PIHOLE_VOLUME_DNSMASQ: "{{ lookup('config', application_id, 'compose.volumes.dnsmasq') }}"
PIHOLE_NETWORK: "{{ lookup('config', application_id, 'compose.network') }}"
PIHOLE_UPSTREAM_DNS: "{{ lookup('config', application_id, 'pihole.upstream_dns') }}"
PIHOLE_TIMEZONE: "{{ lookup('config', application_id, 'pihole.timezone') }}"
PIHOLE_VERSION: "{{ lookup('config', application_id, 'services.pihole.version') }}"
PIHOLE_IMAGE: "{{ lookup('config', application_id, 'services.pihole.image') }}"
PIHOLE_CONTAINER: "{{ entity_name }}"
PIHOLE_VOLUME_DATA: "pihole_data"
PIHOLE_VOLUME_DNSMASQ: "pihole_dnsmasq"
PIHOLE_NETWORK: "pihole"
PIHOLE_UPSTREAM_DNS: "{{ lookup('config', application_id, 'pihole.upstream_dns', '1.1.1.1;1.0.0.1') }}"
PIHOLE_TIMEZONE: "{{ HOST_TIMEZONE }}"
# OAuth2 enabled — disable Pi-hole native password when OAuth2 is active
PIHOLE_OAUTH2_ENABLED: "{{ lookup('config', application_id, 'compose.services.oauth2.enabled') | bool }}"
# OAuth2 enabled
PIHOLE_OAUTH2_ENABLED: "{{ lookup('config', application_id, 'services.oauth2.enabled') | bool }}"
PIHOLE_PASSWORD: "{{ '' if PIHOLE_OAUTH2_ENABLED else lookup('password', application_id, 'admin') }}"
# Playwright — disable wait check because oauth2-proxy returns 403 for unauthenticated requests
# Playwright
TEST_E2E_PLAYWRIGHT_WAIT_ENABLED: false