PowerDNS Authoritative Server es un servidor DNS autoritativo de código abierto que guarda las zonas en una base de datos en lugar de en ficheros de texto, lo que permite gestionarlas con una herramienta de línea de comandos (pdnsutil) o con una API REST. En este tutorial instalarás PowerDNS con backend MySQL en Ubuntu 24.04, crearás una zona con sus registros, activarás la API para automatizar cambios y firmarás la zona con DNSSEC.
Un servidor autoritativo responde por los dominios que tú alojas. No resuelve nombres de Internet para tus clientes: para eso necesitas un resolvedor recursivo como Unbound.
Requisitos previos
- Un servidor con Ubuntu 24.04 LTS y una IP pública, por ejemplo un VPS de CubePath. Para producción conviene tener dos servidores (
ns1yns2), pero este tutorial usa uno. - Un usuario no root con privilegios
sudo. - Al menos 1 GB de RAM.
- Un dominio cuyo DNS vayas a delegar en este servidor. En los ejemplos se usa
your_domainy la IPyour_server_ip; sustitúyelos por los tuyos. - Acceso al panel de tu registrador para crear los registros glue de
ns1.your_domainy, más adelante, publicar el registro DS de DNSSEC.
Paso 1: Liberar el puerto 53
En Ubuntu 24.04, systemd-resolved ocupa el puerto 53 en 127.0.0.53 con su stub listener. PowerDNS escucha por defecto en todas las direcciones (0.0.0.0 y ::), así que ambos chocarían. Desactiva el stub listener con un fichero de configuración adicional:
sudo mkdir -p /etc/systemd/resolved.conf.d
sudo nano /etc/systemd/resolved.conf.d/no-stub.conf
Añade este contenido:
[Resolve]
DNSStubListener=no
Apunta /etc/resolv.conf al fichero que contiene los resolvedores reales (los que recibe el servidor por DHCP o netplan) y reinicia el servicio:
sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
sudo systemctl restart systemd-resolved
Comprueba que nada escucha ya en el puerto 53 y que el servidor sigue resolviendo nombres:
sudo ss -lntup 'sport = :53'
getent hosts cubepath.com
El primer comando no debe mostrar ningún socket y el segundo debe devolver una IP.
Paso 2: Instalar MySQL y PowerDNS
Ubuntu 24.04 incluye PowerDNS 4.8 en sus repositorios, una versión estable y con soporte de seguridad del propio Ubuntu. Instala el servidor, el backend MySQL y el servidor MySQL:
sudo apt update
sudo apt install mysql-server pdns-server pdns-backend-mysql
Verifica la versión instalada con apt:
apt policy pdns-server | head -n 3
pdns-server:
Installed: 4.8.3-4build3
Candidate: 4.8.3-4build3
Notasi necesitas una versión más reciente, PowerDNS publica repositorios oficiales en
repo.powerdns.com. Para la mayoría de instalaciones, el paquete de Ubuntu es suficiente y se actualiza conapt upgrade.
El paquete puede arrancar PowerDNS con el backend BIND de ejemplo. Detén el servicio mientras lo configuras:
sudo systemctl stop pdns
Paso 3: Crear la base de datos
En Ubuntu, el usuario root de MySQL se autentica por socket, así que puedes entrar con sudo sin contraseña:
sudo mysql
Crea la base de datos y un usuario dedicado. Sustituye your_strong_password por una contraseña larga y aleatoria (por ejemplo, la salida de openssl rand -base64 24):
CREATE DATABASE pdns CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'pdns'@'localhost' IDENTIFIED BY 'your_strong_password';
GRANT ALL PRIVILEGES ON pdns.* TO 'pdns'@'localhost';
EXIT;
Importa el esquema que incluye el paquete pdns-backend-mysql:
sudo mysql pdns < /usr/share/pdns-backend-mysql/schema/schema.mysql.sql
Comprueba que se han creado las tablas:
sudo mysql pdns -e "SHOW TABLES;"
+----------------+
| Tables_in_pdns |
+----------------+
| comments |
| cryptokeys |
| domainmetadata |
| domains |
| records |
| supermasters |
| tsigkeys |
+----------------+
Paso 4: Configurar el backend MySQL
El fichero principal /etc/powerdns/pdns.conf carga todo lo que haya en /etc/powerdns/pdns.d/. Si el paquete del backend BIND está instalado, habrá un bind.conf en ese directorio; quítalo para que PowerDNS use solo MySQL:
sudo rm -f /etc/powerdns/pdns.d/bind.conf
Crea la configuración del backend:
sudo nano /etc/powerdns/pdns.d/gmysql.conf
launch=gmysql
gmysql-host=127.0.0.1
gmysql-port=3306
gmysql-dbname=pdns
gmysql-user=pdns
gmysql-password=your_strong_password
gmysql-dnssec=yes
El fichero contiene la contraseña de la base de datos, así que limita quién puede leerlo:
sudo chgrp pdns /etc/powerdns/pdns.d/gmysql.conf
sudo chmod 0640 /etc/powerdns/pdns.d/gmysql.conf
Arranca PowerDNS y habilítalo al inicio:
sudo systemctl enable --now pdns
sudo systemctl status pdns --no-pager
La salida debe indicar active (running). Si no es así, revisa el log con sudo journalctl -u pdns -n 50: un error de conexión a MySQL suele deberse a una contraseña mal copiada en gmysql.conf.
Paso 5: Abrir el firewall
DNS usa UDP para la mayoría de consultas y TCP para respuestas grandes y transferencias de zona. Permite ambos en el puerto 53, además de SSH:
sudo ufw allow OpenSSH
sudo ufw allow 53
sudo ufw enable
sudo ufw status
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
53 ALLOW Anywhere
Paso 6: Crear una zona y sus registros
pdnsutil create-zone crea la zona con un registro SOA y el NS que le indiques:
sudo pdnsutil create-zone your_domain ns1.your_domain
Añade el resto de registros con pdnsutil add-record ZONA NOMBRE TIPO [TTL] CONTENIDO. Usa @ para el propio dominio:
sudo pdnsutil add-record your_domain ns1 A your_server_ip
sudo pdnsutil add-record your_domain @ A your_server_ip
sudo pdnsutil add-record your_domain www CNAME your_domain.
sudo pdnsutil add-record your_domain @ MX "10 mail.your_domain."
sudo pdnsutil add-record your_domain mail A your_server_ip
sudo pdnsutil add-record your_domain @ TXT '"v=spf1 mx -all"'
Revisa la zona y valida que no tenga errores:
sudo pdnsutil list-zone your_domain
sudo pdnsutil check-zone your_domain
Checked 8 records of 'your_domain', 0 errors, 0 warnings.
Consulta el servidor directamente para confirmar que responde con autoridad:
dig @127.0.0.1 your_domain A +norec
En la respuesta, la línea de flags debe incluir aa (authoritative answer) y la sección ANSWER debe mostrar your_server_ip.
Cuando edites registros con pdnsutil edit-zone o directamente en la base de datos, incrementa el número de serie del SOA para que los secundarios detecten el cambio:
sudo pdnsutil increase-serial your_domain
Paso 7: Activar la API REST
La API permite crear zonas y registros desde scripts, paneles o herramientas como Terraform, sin tocar la base de datos. Genera una clave aleatoria:
openssl rand -hex 32
Crea un fichero de configuración para la API y pega la clave en api-key:
sudo nano /etc/powerdns/pdns.d/api.conf
api=yes
api-key=your_api_key
webserver=yes
webserver-address=127.0.0.1
webserver-port=8081
webserver-allow-from=127.0.0.1,::1
La API solo escucha en localhost. Si necesitas usarla desde otra máquina, hazlo a través de un túnel SSH o una red privada, nunca abriendo el puerto 8081 a Internet. Protege el fichero y reinicia:
sudo chgrp pdns /etc/powerdns/pdns.d/api.conf
sudo chmod 0640 /etc/powerdns/pdns.d/api.conf
sudo systemctl restart pdns
Lista las zonas a través de la API:
curl -s -H "X-API-Key: your_api_key" http://127.0.0.1:8081/api/v1/servers/localhost/zones
Deberías ver un JSON con your_domain. en el campo name. Para añadir o sustituir un registro, envía un PATCH con un rrset. Los nombres van siempre con punto final:
curl -s -X PATCH -H "X-API-Key: your_api_key" \
-H "Content-Type: application/json" \
http://127.0.0.1:8081/api/v1/servers/localhost/zones/your_domain. \
-d '{"rrsets":[{"name":"api.your_domain.","type":"A","ttl":300,"changetype":"REPLACE","records":[{"content":"your_server_ip","disabled":false}]}]}'
Una respuesta vacía con código 204 indica éxito. Compruébalo:
dig @127.0.0.1 api.your_domain A +short
Para borrar ese registro, repite la petición con "changetype":"DELETE" y sin el campo records.
Paso 8: Firmar la zona con DNSSEC
DNSSEC añade firmas criptográficas a las respuestas para que los resolvedores puedan detectar respuestas falsificadas. PowerDNS firma las respuestas al vuelo, así que basta con generar las claves:
sudo pdnsutil secure-zone your_domain
sudo pdnsutil rectify-zone your_domain
Muestra las claves y los registros DS que debes publicar en el registrador:
sudo pdnsutil show-zone your_domain
La salida incluye varias líneas DS = your_domain. IN DS ... con distintos algoritmos de digest. La mayoría de registradores piden la de digest tipo 2 (SHA-256). Comprueba que el servidor ya devuelve firmas:
dig @127.0.0.1 your_domain A +dnssec +norec
La respuesta debe incluir un registro RRSIG junto al registro A.
Importantepublica el registro DS en el registrador solo cuando la delegación (paso siguiente) ya funcione. Si publicas un DS que no coincide con las claves del servidor, los resolvedores que validan DNSSEC devolverán SERVFAIL para todo tu dominio.
Paso 9: Delegar el dominio
Para que Internet use tu servidor, en el panel del registrador:
- Crea el registro glue
ns1.your_domainapuntando ayour_server_ip(yns2si tienes un segundo servidor). - Cambia los servidores de nombres del dominio a
ns1.your_domain(yns2.your_domain). - Añade el registro DS del paso anterior si activaste DNSSEC.
Los cambios en la zona padre pueden tardar horas en propagarse. Verifica la delegación desde fuera con un resolvedor público:
dig your_domain NS @1.1.1.1 +short
dig your_domain A @1.1.1.1 +dnssec
Cuando el DS esté publicado y sea correcto, la respuesta del segundo comando incluirá el flag ad.
Solución de problemas
pdnsno arranca con "Address already in use": algo sigue en el puerto 53. Identifícalo consudo ss -lntup 'sport = :53'y revisa el paso 1.- "Unable to launch gmysql" o errores de conexión: comprueba los datos de
gmysql.confprobando la conexión a mano conmysql -u pdns -p -h 127.0.0.1 pdns. - La zona responde REFUSED: la zona no existe con ese nombre exacto. Lista las zonas con
sudo pdnsutil list-all-zones. - Cambios que no aparecen: PowerDNS cachea las respuestas unos segundos. Espera o vacía la caché de una zona con
sudo pdns_control purge your_domain$. - Logs:
sudo journalctl -u pdns -fmuestra los errores en tiempo real.
Conclusión
Ya tienes PowerDNS funcionando como servidor autoritativo con backend MySQL, una zona firmada con DNSSEC y una API REST local para automatizar cambios. Como siguientes pasos, añade un segundo servidor (ns2) en otra ubicación, bien como secundario por AXFR o replicando la base de datos, y automatiza la creación de registros desde tu aplicación o tu herramienta de infraestructura como código usando la API.
