Un certificado comodín (wildcard) cubre todos los subdominios de primer nivel de un dominio, como api.example.com o shop.example.com, con un único certificado. Let's Encrypt solo emite certificados comodín mediante el desafío DNS-01, que demuestra el control del dominio creando un registro TXT. En este tutorial obtendrás un certificado para your_domain y *.your_domain con Certbot y el plugin de Cloudflare en Ubuntu 24.04, lo usarás en Nginx y comprobarás que se renueva solo.

Requisitos previos

Para seguir esta guía necesitas:

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, y un usuario no root con privilegios sudo.
  • Un dominio cuya zona DNS esté gestionada en Cloudflare. Si usas otro proveedor, consulta la sección "Otros proveedores DNS".
  • Nginx instalado (sudo apt install nginx). El desafío DNS no necesita ningún puerto abierto; los puertos 80 y 443 solo hacen falta para servir la web.
  • Registros DNS A para your_domain y para los subdominios que vayas a servir apuntando a your_server_ip (puedes usar un registro * comodín).

A lo largo de la guía, sustituye your_domain por tu dominio real (por ejemplo example.com).

Qué cubre un certificado comodín

Conviene tener claro el alcance antes de pedirlo:

Nombre¿Lo cubre *.your_domain?
api.your_domainSí
www.your_domainSí
your_domain (dominio raíz)No, hay que añadirlo aparte
v1.api.your_domainNo, el comodín solo cubre un nivel

Por eso en esta guía pedirás un único certificado con dos nombres: your_domain y *.your_domain.

Paso 1: Instalar Certbot y el plugin de Cloudflare

El proyecto Certbot recomienda instalarlo con snap, que trae la versión más reciente y un temporizador de renovación ya configurado. Si tienes el paquete certbot de apt, elimínalo antes para no tener dos versiones:

sudo apt remove certbot
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/local/bin/certbot

Los plugins DNS se instalan como snaps independientes. Primero permite que Certbot cargue plugins con permisos de root y después instala y conecta el de Cloudflare:

sudo snap set certbot trust-plugin-with-root=ok
sudo snap install certbot-dns-cloudflare
sudo snap connect certbot:plugin certbot-dns-cloudflare

Comprueba que Certbot detecta el plugin:

sudo certbot plugins
* dns-cloudflare
Description: Obtain certificates using a DNS TXT record (if you are using
Cloudflare for DNS).
...

Paso 2: Crear un token de API de Cloudflare

Certbot necesita crear y borrar registros TXT en tu zona. Usa un token de API con permisos limitados, nunca la Global API Key de la cuenta.

En el panel de Cloudflare, ve a My Profile > API Tokens > Create Token, elige la plantilla Edit zone DNS y, en Zone Resources, selecciona solo la zona de your_domain. Copia el token generado, porque Cloudflare no vuelve a mostrarlo.

Guarda el token en un archivo que solo pueda leer root:

sudo mkdir -p /root/.secrets/certbot
sudo nano /root/.secrets/certbot/cloudflare.ini
dns_cloudflare_api_token = your_cloudflare_api_token

Restringe los permisos. Certbot muestra un aviso si el archivo lo pueden leer otros usuarios:

sudo chmod 600 /root/.secrets/certbot/cloudflare.ini

Paso 3: Solicitar el certificado comodín

Haz primero una prueba contra el entorno de staging de Let's Encrypt con --dry-run. Así compruebas el token y la propagación DNS sin consumir los límites de emisión de producción:

sudo certbot certonly --dry-run \
  --dns-cloudflare \
  --dns-cloudflare-credentials /root/.secrets/certbot/cloudflare.ini \
  --dns-cloudflare-propagation-seconds 30 \
  -d your_domain -d '*.your_domain'

Las comillas en '*.your_domain' evitan que la shell expanda el asterisco. La opción --dns-cloudflare-propagation-seconds indica cuánto espera Certbot tras crear el registro TXT antes de pedir la validación.

The dry run was successful.

Si la prueba funciona, repite el comando sin --dry-run para obtener el certificado real. La primera vez Certbot te pedirá un correo y que aceptes las condiciones de servicio:

sudo certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /root/.secrets/certbot/cloudflare.ini \
  --dns-cloudflare-propagation-seconds 30 \
  -d your_domain -d '*.your_domain'
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/your_domain/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/your_domain/privkey.pem
This certificate expires on 2026-12-24.

Comprueba los nombres incluidos en el certificado:

sudo certbot certificates
  Certificate Name: your_domain
    Domains: your_domain *.your_domain
    Expiry Date: 2026-12-24 10:12:45+00:00 (VALID: 89 days)
    Certificate Path: /etc/letsencrypt/live/your_domain/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/your_domain/privkey.pem

Paso 4: Usar el certificado en Nginx

Como el certificado cubre cualquier subdominio, puedes reutilizar las mismas rutas en todos los bloques server. Crea un archivo de configuración:

sudo nano /etc/nginx/sites-available/your_domain

Este ejemplo redirige HTTP a HTTPS, sirve el dominio raíz y www, y define un subdominio api que hace de proxy a una aplicación local en el puerto 3000 (ajústalo a tu caso):

server {
    listen 80;
    listen [::]:80;
    server_name your_domain *.your_domain;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name your_domain www.your_domain;

    ssl_certificate     /etc/letsencrypt/live/your_domain/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem;

    root /var/www/html;
    index index.html;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name api.your_domain;

    ssl_certificate     /etc/letsencrypt/live/your_domain/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Usa siempre fullchain.pem y no cert.pem: el primero incluye el certificado intermedio que los clientes necesitan para validar la cadena.

Activa el sitio, comprueba la sintaxis y recarga Nginx:

sudo ln -s /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Si usas UFW, permite el tráfico web:

sudo ufw allow 'Nginx Full'

Comprueba desde cualquier equipo que el subdominio sirve el certificado comodín:

openssl s_client -connect api.your_domain:443 -servername api.your_domain </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -ext subjectAltName
subject=CN = your_domain
X509v3 Subject Alternative Name:
    DNS:*.your_domain, DNS:your_domain

Paso 5: Verificar la renovación automática

Los certificados de Let's Encrypt caducan a los 90 días. El snap de Certbot instala un temporizador de systemd que ejecuta certbot renew dos veces al día y renueva los certificados a los que les quedan menos de 30 días. Comprueba que está activo:

systemctl list-timers snap.certbot.renew.timer
NEXT                        LEFT     LAST  PASSED  UNIT                     ACTIVATES
Fri 2026-09-25 21:48:00 UTC 9h left  -     -       snap.certbot.renew.timer snap.certbot.renew.service

Certbot guarda en /etc/letsencrypt/renewal/your_domain.conf el plugin y el archivo de credenciales que usaste, así que la renovación no necesita parámetros. Lo que no hace es recargar Nginx para que cargue el certificado nuevo. Para eso, crea un hook de despliegue, que solo se ejecuta cuando un certificado se renueva de verdad:

sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
#!/usr/bin/env bash
set -euo pipefail
systemctl reload nginx

Hazlo ejecutable y simula una renovación completa:

sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
sudo certbot renew --dry-run
Congratulations, all simulated renewals succeeded:
  /etc/letsencrypt/live/your_domain/fullchain.pem (success)

Otros proveedores DNS

El desafío DNS-01 funciona igual con cualquier proveedor que tenga plugin de Certbot; solo cambian el nombre del plugin y el archivo de credenciales. Algunos disponibles como snap son certbot-dns-route53, certbot-dns-digitalocean, certbot-dns-google, certbot-dns-ovh y certbot-dns-rfc2136 (para servidores DNS propios como BIND o PowerDNS). Consulta la documentación de cada plugin para el formato de credenciales.

Si tu proveedor no tiene plugin ni API, puedes usar --manual --preferred-challenges dns y crear el registro TXT a mano, pero ese certificado no se podrá renovar automáticamente y tendrás que repetir el proceso cada 90 días. En ese caso es mejor delegar el subdominio _acme-challenge a un proveedor con API.

Solución de problemas

Unable to determine zone_id o Error determining zone_id. El token no tiene acceso a la zona. Revisa en Cloudflare que el token incluye el permiso Zone > DNS > Edit y la zona correcta en Zone Resources.

Incorrect TXT record o No TXT record found. Let's Encrypt consultó el DNS antes de que el registro se propagara. Aumenta --dns-cloudflare-propagation-seconds a 60 y, mientras Certbot espera, comprueba el registro desde otra terminal:

dig +short TXT _acme-challenge.your_domain @1.1.1.1

CAA record for your_domain prevents issuance. Tu zona tiene registros CAA que no autorizan a Let's Encrypt. Para certificados comodín se aplica la etiqueta issuewild (o issue si no existe issuewild). Añade un registro CAA con 0 issuewild "letsencrypt.org" y revisa los existentes:

dig +short CAA your_domain

too many certificates already issued. Has alcanzado un límite de emisión de Let's Encrypt, normalmente por repetir pruebas en producción. Espera a que se libere el límite y usa --dry-run para las pruebas.

Conclusión

Tienes un certificado de Let's Encrypt válido para your_domain y todos sus subdominios de primer nivel, servido por Nginx y con renovación automática mediante DNS-01 y un hook que recarga el servidor. Como siguientes pasos, puedes reforzar la configuración TLS de Nginx (protocolos, cabecera HSTS), añadir nuevos subdominios con solo crear su bloque server, o revisar la guía de protocolo ACME para entender cómo funcionan los desafíos por debajo.