- Jinja 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
ci/woodpecker/push/linting Pipeline was successful
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> |
||
| .woodpecker | ||
| defaults | ||
| handlers | ||
| meta | ||
| roles | ||
| tasks | ||
| templates/unbound | ||
| .ansible-lint | ||
| .editorconfig | ||
| .gitattributes | ||
| .gitignore | ||
| .markdownlint-cli2.jsonc | ||
| .sops.yaml | ||
| .yamllint | ||
| AGENTS.md | ||
| ansible.cfg | ||
| playbook.yaml | ||
| readme.md | ||
| renovate.json | ||
Ansible Role: Unbound
Installs and configures the Unbound DNS server as a caching resolver that
forwards all queries to upstream servers and serves local zones with static records. The role is installed as dns
(see roles/requirements.yml and meta/main.yaml).
Requirements
| Operating System | Package manager | Service handling |
|---|---|---|
| Alpine Linux | apk |
service |
| Debian family | apt |
systemd |
Dependencies
None (dependencies: []). roles/requirements.yml only lists this role itself as dns
(https://git.simoncor.net/ansible/unbound.git).
Variables
| Variable | Required | Default | Description |
|---|---|---|---|
unbound_verbosity |
No | 1 |
Log verbosity |
unbound_port |
No | 53 |
Listen port |
unbound_do_ip6 |
No | true |
Answer queries over IPv6 |
unbound_do_tcp |
No | true |
Answer queries over TCP |
unbound_num_threads |
No | 2 |
Threads; also used for the cache slab settings |
unbound_so_reuseport |
No | true |
Use SO_REUSEPORT |
unbound_use_caps_for_id |
No | true |
Randomise case in queries (use-caps-for-id) |
unbound_qname_minimisation |
No | true |
QNAME minimisation |
unbound_harden_dnssec_stripped |
No | true |
Require DNSSEC data for trust-anchored zones |
unbound_harden_glue |
No | true |
Only trust glue within the server's authority |
unbound_hide_identity |
No | true |
Do not answer identity queries |
unbound_hide_version |
No | true |
Do not answer version queries |
unbound_cache_min_ttl |
No | 5 |
Minimum cache TTL in seconds |
unbound_cache_max_ttl |
No | 86400 |
Maximum cache TTL in seconds |
unbound_prefetch |
No | true |
Prefetch cache entries before they expire |
unbound_upstream_dns |
No | ["8.8.8.8", "1.1.1.1"] |
Upstream DNS servers (forward zone .) |
unbound_allow_access |
Yes | one example network | Networks allowed to query, see below |
unbound_zones |
No | [] |
Local DNS zones with records, see below |
The default for unbound_allow_access is a single example entry (example-lan, 192.168.1.0/24); override it with
your own networks. Unbound listens on all interfaces (interface-automatic) and only answers allowed networks.
unbound_allow_access
| Key | Required | Description |
|---|---|---|
name |
Yes | Description, used as a comment |
network |
Yes | Network in CIDR notation (access-control) |
unbound_zones
| Key | Required | Default | Description |
|---|---|---|---|
zone |
Yes | Zone name (without trailing dot) | |
type |
No | static |
Unbound local-zone type, for example static or transparent |
records |
Yes | List of records, see below |
Example
unbound_upstream_dns:
- "1.1.1.1"
- "8.8.8.8"
unbound_allow_access:
- name: "internal-lan"
network: "10.0.0.0/8"
- name: "dmz"
network: "192.168.1.0/24"
unbound_zones:
- zone: "internal.example.com"
type: "static"
records:
# A records (default type)
- name: "server1.internal.example.com"
value: "10.0.1.10"
# AAAA record
- name: "server2.internal.example.com"
type: "AAAA"
value: "2001:db8::1"
# CNAME record
- name: "internal.example.com"
type: "CNAME"
value: "server1.internal.example.com"
# MX record
- name: "internal.example.com"
type: "MX"
priority: 10
value: "mail.internal.example.com"
# TXT record
- name: "internal.example.com"
type: "TXT"
value: "v=spf1 include:internal.example.com ~all"
# SRV record
- name: "_sip._tcp.internal.example.com"
type: "SRV"
priority: 10
weight: 60
port: 5060
value: "server1.internal.example.com"
# PTR record (manual reverse DNS)
- name: "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa"
type: "PTR"
value: "server1.internal.example.com"
Supported Record Types
Records are written as local-data entries. The type defaults to A; any other type value that is not listed below
is rendered as <name>. IN <type> <value>.
| Type | Required Fields | Description |
|---|---|---|
A (default) |
name, value |
IPv4 address record |
AAAA |
name, value, type |
IPv6 address record |
CNAME |
name, value, type |
Canonical name |
MX |
name, value, type, priority |
Mail exchange |
TXT |
name, value, type |
Text record |
SRV |
name, value, type, priority, weight, port |
Service locator |
PTR |
name, value, type |
Pointer record |
Reverse DNS
Reverse DNS (PTR) records are automatically generated from IPv4 A records in zones whose type is not
transparent, for addresses in these networks:
192.168.x.x: one reverse zone per /24 (for example1.168.192.in-addr.arpa)10.8.x.x: reverse zone8.10.in-addr.arpa10.0.x.x: reverse zone0.10.in-addr.arpa
Addresses in other networks get no PTR record. IPv6 reverse DNS is not auto-generated. Use manual PTR records in a dedicated zone instead.
Usage
Run playbook.yaml through Semaphore. The playbook first runs ansible-galaxy install -f -r roles/requirements.yml
on localhost, then includes the dns role. It runs with serial: 1, so hosts are configured one at a time.
Operational notes
- The role installs
unbound, renders/etc/unbound/unbound.confand/etc/unbound/zones.conf(the main file includes the second) and restarts and enables the service on every change. - All other queries are forwarded to
unbound_upstream_dns. - There are no tags.