En corto
- 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.
- pfSense → System → Package Manager → instalar acme y haproxy.
- Services → ACME → Account keys → Add: ACME Server Let’s Encrypt Production ACME v2 (o Staging para probar) → Create new account key → Register → Save.
- Services → ACME → Certificates → Add: nombre, la cuenta, Domain SAN list:
app.example.com(y*.example.comsi 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. - 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 paquete | Valor | Dónde |
|---|---|---|
| Token | El API token | My Profile → API Tokens |
| Account ID | ID de la cuenta | Zona → Overview → API (columna derecha) |
| Zone ID | ID de la zona | Mismo sitio |
| Key / Email | Vacíos | Solo 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.comla validación tiene que ser DNS-01 (HTTP-01 no lo permite). Un wildcard no cubre el apex: añadeexample.comcomo 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 a120. - 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:
- Settings: activar HAProxy, y en Max SSL Diffie-Hellman size deja 2048 o más.
- 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. - Save → Apply Changes.
Prueba desde fuera:
| |
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
Aestá proxificado, HAProxy ve la IP de Cloudflare como origen. Para un servicio interno detrás de pfSense, nube gris. Issuefalla conInvalid request headersoAuthentication 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_clientquenotAfteravanzó. - 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).