This guide provides a Ansible playbook to install and configure CoreDNS with distro-aware package handling, security best practices, and service management for Debian 11+, Ubuntu 20.04+, and RHEL 9+ compatible systems.
Create a playbook file coredns-install.yml:
---
- name: Install and configure CoreDNS
hosts: coredns
become: true
vars:
coredns_user: "coredns"
coredns_group: "coredns"
coredns_config_dir: "/etc/coredns"
coredns_binary_path: "/usr/local/bin/coredns"
coredns_version: "1.14.1"
coredns_architecture: "linux_amd64" # Change as needed (arm64, etc.)
tasks:
- name: Create CoreDNS system user
user:
name: "{{ coredns_user }}"
group: "{{ coredns_group }}"
system: true
shell: "/usr/sbin/nologin"
home: "/"
create_home: false
state: present
- name: Download CoreDNS binary
get_url:
url: "https://github.com/coredns/coredns/releases/download/v{{ coredns_version }}/coredns_{{ coredns_version }}_{{ coredns_architecture }}.tgz"
dest: "/tmp/coredns_{{ coredns_version }}_{{ coredns_architecture }}.tgz"
mode: '0644'
force: true
register: download_result
- name: Extract CoreDNS archive
unarchive:
src: "/tmp/coredns_{{ coredns_version }}_{{ coredns_architecture }}.tgz"
dest: "/tmp"
remote_src: yes
when: download_result.changed
- name: Install CoreDNS binary
copy:
src: "/tmp/coredns"
dest: "{{ coredns_binary_path }}"
mode: '0755'
owner: "{{ coredns_user }}"
group: "{{ coredns_group }}"
remote_src: yes
notify: restart coredns
- name: Create CoreDNS configuration directory
file:
path: "{{ coredns_config_dir }}"
state: directory
owner: "{{ coredns_user }}"
group: "{{ coredns_group }}"
mode: '0755'
- name: Create CoreDNS configuration file
template:
src: coredns.j2
dest: "{{ coredns_config_dir }}/Corefile"
owner: "{{ coredns_user }}"
group: "{{ coredns_group }}"
mode: '0644'
notify: reload coredns
tags: configuration
- name: Create systemd service file
template:
src: coredns.service.j2
dest: "/etc/systemd/system/coredns.service"
owner: root
group: root
mode: '0644'
notify: restart coredns
- name: Enable and start CoreDNS service
systemd:
name: coredns
state: started
enabled: true
daemon_reload: true
- name: Verify CoreDNS is running
systemd:
name: coredns
state: started
when: inventory_hostname in groups['coredns']
- name: Verify health endpoint (requires health plugin)
uri:
url: "http://localhost:8080/health"
method: GET
status_code: 200
retries: 5
delay: 2
ignore_errors: true
comment: "Health endpoint requires 'health' plugin in Corefile"
when: inventory_hostname in groups['coredns']
- name: Show CoreDNS version
command: "{{ coredns_binary_path }} -version"
register: coredns_version_output
changed_when: false
- name: Display CoreDNS version
debug:
msg: "CoreDNS version: {{ coredns_version_output.stdout }}"
Create the Jinja2 templates referenced in the playbook:
Create templates/coredns.j2:
.:53 {
errors
log
health
ready
# Forward queries to upstream resolvers
forward . 1.1.1.1 8.8.8.8 {
max_fails 3
expire 10s
except localhost
}
# Cache responses for performance
cache 30 {
success 30
denial 10
}
# Prevent loops
loop
# Load balancing for responses
loadbalance
# Prometheus metrics
prometheus :9153
}
Create templates/coredns.service.j2:
[Unit]
Description=CoreDNS DNS server
Documentation=https://coredns.io
After=network.target
[Service]
User={{ coredns_user }}
Group={{ coredns_group }}
PermissionsStartOnly=true
ExecStart={{ coredns_binary_path }} -conf {{ coredns_config_dir }}/Corefile
ExecReload=/bin/kill -SIGUSR1 $MAINPID
Restart=on-failure
RestartSec=10
WorkingDirectory={{ coredns_config_dir }}
# Security settings
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths={{ coredns_config_dir }}
[Install]
WantedBy=multi-user.target
Create handlers/main.yml in your role directory:
---
- name: restart coredns
systemd:
name: coredns
state: restarted
daemon_reload: true
- name: reload coredns
systemd:
name: coredns
state: reloaded
Create an inventory file inventory.ini:
[coredns]
coredns-server ansible_host=192.168.1.100 ansible_user=ubuntu
[coredns:vars]
ansible_python_interpreter=/usr/bin/python3
Execute the playbook:
ansible-playbook -i inventory.ini coredns-install.yml
If deploying for Kubernetes, modify the Corefile template:
.:53 {
errors
log
health
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
upstream
fallthrough in-addr.arpa ip6.arpa
}
forward . /etc/resolv.conf
cache 30
loop
reload
loadbalance
}
For authoritative-only DNS serving:
.:53 {
errors
log
health
ready
file /etc/coredns/zones/db.example.com example.com {
reload 10s
}
prometheus :9153
}
For better organization, create an Ansible role structure:
roles/
└── coredns/
├── tasks/
│ └── main.yml
├── handlers/
│ └── main.yml
├── templates/
│ ├── coredns.j2
│ └── coredns.service.j2
└── vars/
└── main.yml
After deployment, verify the installation:
# Check service status
systemctl status coredns
# Test DNS resolution
dig @127.0.0.1 google.com
# Check logs
journalctl -u coredns -f
journalctl -u corednscoredns -check-config -conf /etc/coredns/CorefileWe develop tailored automation solutions for:
Let’s discuss your requirements: office@linux-server-admin.com | Contact