En corto

  1. Cloudflare → My Profile → API Tokens → Create Token → plantilla Edit zone DNS: permisos Zone → Zone → Read y Zone → DNS → Edit, Zone Resources limitado a tu zona. Copia el token; el Account ID y el Zone ID están en la página Overview de la zona.
  2. pfSense → System → Package Manager → instalar acme y haproxy.
  3. Services → ACME → Account keys → Add: ACME Server Let’s Encrypt Production ACME v2 (o Staging para probar) → Create new account key → Register → Save.
  4. Services → ACME → Certificates → Add: nombre, la cuenta, Domain SAN list: app.example.com (y *.example.com si quieres wildcard) con método DNS-Cloudflare, y en sus campos solo Token, Account ID y Zone ID. Actions list: Restart Local Service → haproxy. Save → Issue.
  5. Services → HAProxy → Frontend → editar → SSL Offloading ✔ en la dirección de escucha → Certificate: el que acaba de crear ACME → Save → Apply Changes.

Renovación automática (cron diario del paquete) y HAProxy reiniciado en cada renovación.

Cloudflare: el token

La Global API Key que piden las guías antiguas da acceso a toda la cuenta; un API token con permisos mínimos es lo correcto y es lo que el método DNS-Cloudflare del paquete usa cuando rellenas Token:

Campo del paqueteValorDónde
TokenEl API tokenMy Profile → API Tokens
Account IDID de la cuentaZona → Overview → API (columna derecha)
Zone IDID de la zonaMismo sitio
Key / EmailVacíosSolo para la Global API Key (no la uses)

Con Token basta uno de los dos IDs; poner ambos no molesta. Permisos del token: Zone:Read y DNS:Edit sobre la zona concreta (Include → Specific zone).

Si activas Client IP Address Filtering en el token, tiene que incluir la IP pública IPv4 y también IPv6 del firewall: pfSense sale por la que tenga a mano, y un token limitado a la v4 falla en cuanto la llamada a la API va por v6.

ACME: cuenta y certificado

Cuenta. Crea dos: una contra Staging para probar y otra contra Production. Staging no tiene límites de emisión pero sus certificados no son de confianza; cuando todo funcione, cambia la cuenta del certificado a la de producción y vuelve a emitir.

Certificado. En Services → ACME → Certificates → Add:

  • Domain SAN list: una entrada por nombre. Para un wildcard *.example.com la validación tiene que ser DNS-01 (HTTP-01 no lo permite). Un wildcard no cubre el apex: añade example.com como segunda entrada.
  • Method: DNS-Cloudflare en cada entrada, con los tres campos.
  • DNS Sleep: Cloudflare propaga en segundos; el valor por defecto sobra. Si la emisión falla por TXT not found, súbelo a 120.
  • Key: RSA 2048 o ECDSA 256; ambos van bien con HAProxy.
  • Actions list: Restart Local Service → haproxy. Sin esto, HAProxy sigue sirviendo el certificado viejo hasta que alguien lo reinicie, aunque ACME ya haya renovado.

Issue desde la lista de certificados. El resultado aparece en System → Certificates con el nombre que le diste; ahí lo verá HAProxy.

HAProxy: usar el certificado

Services → HAProxy:

  1. Settings: activar HAProxy, y en Max SSL Diffie-Hellman size deja 2048 o más.
  2. Frontend → tu frontend HTTPS → External address: puerto 443, SSL Offloading ✔ → sección SSL Offloading → Certificate: el de ACME. Para varios dominios en el mismo frontend, Additional certificates con los demás; HAProxy elige por SNI.
  3. Save → Apply Changes.

Prueba desde fuera:

1
2
openssl s_client -connect app.example.com:443 -servername app.example.com </dev/null 2>/dev/null \
  | openssl x509 -noout -issuer -dates

issuer=C = US, O = Let's Encrypt y notAfter a 90 días.

De regalo, la GUI de pfSense con el mismo certificado: System → Advanced → Admin Access → SSL/TLS Certificate, y una segunda acción en el certificado ACME: Shell Command /etc/rc.restart_webgui.

Trampas

  • Cloudflare en modo proxy (nube naranja) no afecta a DNS-01, pero sí a cómo llega el tráfico: si el registro A está proxificado, HAProxy ve la IP de Cloudflare como origen. Para un servicio interno detrás de pfSense, nube gris.
  • Issue falla con Invalid request headers o Authentication error: token sin permiso sobre esa zona, filtro de IP del token, o Zone ID de otra zona.
  • Rate limits de producción: cinco certificados por conjunto de nombres a la semana. Prueba en staging.
  • El certificado se renueva; HAProxy no lo recarga solo. La acción de reinicio es obligatoria. Comprueba en Services → ACME que la última renovación tiene fecha y en openssl s_client que notAfter avanzó.
  • Los ACME se renuevan a los 2/3 de vida (unos 60 días). Si ves el cron ejecutándose y nada cambia antes de eso, es normal.

Referencia: ACME package en la documentación de Netgate y la lista de proveedores DNS de acme.sh (sección dns_cf).