feat(unbound): add prometheus exporter, dashboard, fix socket buffer sysctl

This commit is contained in:
Clément Désiles
2026-09-06 23:44:05 +02:00
parent 304a3fae12
commit ed5d0c68f1
11 changed files with 290 additions and 3 deletions
+25
View File
@@ -1,3 +1,28 @@
# Metrics (Prometheus)
Set `unbound_exporter_enabled: true` in inventory/host_vars. This enables
`remote-control` (no TLS, loopback only) and deploys `prometheus-unbound-exporter`
(Arch Linux only), which scrapes `unbound-control stats_noreset` on
`127.0.0.1:9167`.
Verify:
```sh
curl -s 127.0.0.1:9167/metrics | grep '^unbound_up'
```
Add a scrape job in `prometheus_scrape_configs`:
```yaml
- job_name: 'unbound'
static_configs:
- targets: ['localhost:9167']
```
Key QoS metrics: cache hit ratio (`unbound_cache_hit_rate` or
`num.cachehits`/`num.cachemiss`), recursion latency (`num.query.time.avg/median`),
requestlist backlog, and `num.answer.rcode.SERVFAIL` failure rate.
# Testing
## DNS leaks
+6
View File
@@ -25,3 +25,9 @@ unbound_firewall_allowed_sources:
unbound_custom_lan_records:
"example.lan":
v4: 192.168.1.2
# Prometheus exporter (optional, via prometheus-unbound-exporter).
# Scrapes unbound-control stats_noreset over the local control interface.
# Arch Linux only — the exporter is not packaged in Debian/Ubuntu.
unbound_exporter_enabled: false
unbound_exporter_listen_address: "127.0.0.1:9167"
+5
View File
@@ -14,3 +14,8 @@
- name: Reload AppArmor profile
ansible.builtin.command: apparmor_parser -r {{ unbound_apparmor_profile_path }}
when: ansible_facts.apparmor.status == "enabled"
- name: Restart unbound exporter
ansible.builtin.systemd:
name: "{{ unbound_exporter_service }}"
state: restarted
+35
View File
@@ -0,0 +1,35 @@
---
# Prometheus unbound exporter (optional, gated by unbound_exporter_enabled).
# Scrapes unbound-control stats_noreset over the local control interface.
- name: Assert exporter is supported (Arch Linux only)
ansible.builtin.assert:
that: ansible_facts['os_family'] == 'Archlinux'
fail_msg: |
The unbound exporter (prometheus-unbound-exporter) is only packaged for
Arch Linux. It is not available in Debian/Ubuntu repositories.
success_msg: "Unbound exporter supported"
- name: Load OS-specific exporter variables
ansible.builtin.include_vars: archlinux.yml
- name: Install prometheus-unbound-exporter
ansible.builtin.package:
name: "{{ unbound_exporter_package }}"
state: present
- name: Deploy exporter environment file
ansible.builtin.template:
src: exporter-env.conf.j2
dest: "{{ unbound_exporter_args_file }}"
owner: root
group: root
mode: "0644"
notify: Restart unbound exporter
- name: Enable and start prometheus-unbound-exporter
ansible.builtin.systemd:
name: "{{ unbound_exporter_service }}"
enabled: true
state: started
daemon_reload: true
+13 -2
View File
@@ -137,13 +137,20 @@
group: root
mode: "0644"
# Match so-rcvbuf/so-sndbuf (4m) in unbound.conf. rmem_max was 1 MiB and
# wmem_max was left at its ~208 KiB default, silently capping unbound's
# requested 4 MiB buffers (the kernel halves SO_RCVBUF/SO_SNDBUF requests
# against these sysctls before doubling them).
- name: Configure sysctl for unbound socket buffers
ansible.posix.sysctl:
name: net.core.rmem_max
value: "1048576"
name: "{{ item.name }}"
value: "{{ item.value }}"
state: present
sysctl_set: true
reload: true
loop:
- { name: net.core.rmem_max, value: "4194304" }
- { name: net.core.wmem_max, value: "4194304" }
- name: Install unbound config
ansible.builtin.template:
@@ -184,3 +191,7 @@
delay: 2
register: ufw_result
until: ufw_result is succeeded
- name: Deploy Prometheus unbound exporter
ansible.builtin.include_tasks: exporter.yml
when: unbound_exporter_enabled | bool
@@ -0,0 +1,4 @@
# Managed by Ansible - DO NOT EDIT MANUALLY
# Empty cert flags (-unbound.ca= etc.) make the exporter speak plain-text to
# unbound's control interface (control-use-cert: no).
{{ unbound_exporter_args_var }}="-web.listen-address={{ unbound_exporter_listen_address }} -unbound.ca= -unbound.cert= -unbound.key= -unbound.host tcp://127.0.0.1:8953"
+13
View File
@@ -130,5 +130,18 @@ server:
# Enable DNSSEC
auto-trust-anchor-file: "{{ unbound_anchor_root_key }}"
# Statistics for monitoring (unbound-control stats / prometheus exporter)
statistics-interval: 0
statistics-cumulative: yes
extended-statistics: yes
# Remote control for unbound-control and the prometheus exporter.
# control-use-cert: no — unbound only accepts plain control connections from
# loopback in this mode, so no TLS certs need to be generated.
remote-control:
control-enable: yes
control-interface: 127.0.0.1
control-use-cert: no
include: "{{ unbound_custom_lan_config_path }}"
include: "{{ unbound_custom_vpn_config_path }}"
+6
View File
@@ -0,0 +1,6 @@
---
# Prometheus exporter
unbound_exporter_package: prometheus-unbound-exporter
unbound_exporter_service: prometheus-unbound-exporter
unbound_exporter_args_file: /etc/conf.d/prometheus-unbound-exporter
unbound_exporter_args_var: UNBOUND_EXPORTER_ARGS