certificados: emitidos, y las dos trampas del camino
www.feadulta.com, feadulta.com y wp-nuevo.feadulta.com, de Let's Encrypt y validos hasta el 1-nov. Ya se puede subir la zona a Full (strict). Lo que funciono es el plan B de Inma, porque la Configuration Rule que propuse primero no se puede montar en su plan de Cloudflare: custom rule del WAF con accion Skip para la ruta del reto, mas apagar Always Use HTTPS a nivel de zona unos minutos. Dos cosas que costaron tiempo y quedan anotadas: acme.json escribe "main": "dominio" CON espacio. Un grep sin espacio da vacio siempre y parece que no hay certificados. Los de hoy llevaban casi una hora emitidos mientras mi bucle de vigilancia informaba de "sin novedad", y por eso lanzamos un reintento que no hacia falta. Va el snippet que parsea el JSON. Y se retira un riesgo que yo mismo habia documentado: el modo Full NO impide el reto. Se temia que Cloudflare mandara la validacion al 443, donde el handler de ACME no existe. Es falso y se midio: con Always Use HTTPS apagado, una peticion HTTP a la ruta del reto a traves de Cloudflare devuelve 404 con 0 bytes y server: cloudflare, o sea que reenvia al puerto 80 y responde Traefik. Mejor quitarlo que dejar una advertencia falsa en un documento que va a leer otra gente. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,17 +1,59 @@
|
||||
# Los certificados de Let's Encrypt de `www` y el apex no se emiten
|
||||
# Los certificados de Let's Encrypt de `www` y el apex
|
||||
|
||||
**Estado: abierto.** Bloqueado a la espera de una regla en Cloudflare, que gestiona Inma.
|
||||
Fecha: 3-ago-2026, después del cutover. Plan maestro: `rafa/feadulta`#180.
|
||||
## ✅ RESUELTO — 3-ago-2026, 12:03 UTC
|
||||
|
||||
## Resumen para quien tenga prisa
|
||||
```
|
||||
www.feadulta.com Let's Encrypt YR2 3-ago-2026 -> 1-nov-2026
|
||||
feadulta.com Let's Encrypt YR2 3-ago-2026 -> 1-nov-2026
|
||||
wp-nuevo.feadulta.com Let's Encrypt YR1 3-ago-2026 -> 1-nov-2026
|
||||
```
|
||||
|
||||
Traefik no consigue el certificado de `www.feadulta.com` ni de `feadulta.com`. **No hay nada roto
|
||||
para los visitantes**: Cloudflare presenta su propio certificado, y hacia el origen —con el modo SSL
|
||||
de la zona en `Full`— acepta el certificado por defecto de Traefik. El único coste es que **la zona
|
||||
no puede subir a `Full (strict)`** hasta que se resuelva.
|
||||
**Lo que funcionó** (el "plan B" de Inma, porque la Configuration Rule que se propuso primero **no
|
||||
se puede montar en este plan de Cloudflare**):
|
||||
|
||||
La causa es que el reto HTTP-01 de Let's Encrypt acaba llegando por HTTPS y Cloudflare lo bloquea
|
||||
con un 403. Se arregla con una **Configuration Rule** en Cloudflare acotada a la ruta del reto.
|
||||
1. **Custom rule del WAF con acción *Skip*** para `/.well-known/acme-challenge/`.
|
||||
2. **Apagar "Always Use HTTPS" a nivel de zona** durante unos minutos, y volver a encenderlo después.
|
||||
|
||||
Con eso el reto se completa por el puerto 80, donde lo atiende Traefik. **Ya se puede subir la zona
|
||||
a `Full (strict)`.**
|
||||
|
||||
### ⚠️ Dos avisos para la próxima, que costaron tiempo
|
||||
|
||||
**1. `acme.json` escribe `"main": "dominio"` CON espacio.** Un `grep '"main":"'` da vacío siempre y
|
||||
parece que no hay certificados. Los certificados de hoy llevaban **casi una hora emitidos** mientras
|
||||
un bucle de vigilancia mal escrito informaba de "sin novedad". **Parsear el JSON, no grepear:**
|
||||
|
||||
```bash
|
||||
docker exec coolify-proxy cat /traefik/acme.json > /tmp/a.json
|
||||
python3 -c "
|
||||
import json
|
||||
d=json.load(open('/tmp/a.json'))
|
||||
for r,v in d.items():
|
||||
if isinstance(v,dict):
|
||||
for c in (v.get('Certificates') or []): print(c.get('domain',{}).get('main'))
|
||||
"
|
||||
```
|
||||
|
||||
**2. Se descartó un riesgo que se había anotado aquí: el modo `Full` NO impide el reto.** Se temía
|
||||
que Cloudflare, al hablar con el origen por HTTPS, mandara la validación al 443 —donde el handler de
|
||||
ACME no existe— y que HTTP-01 fuera imposible con la zona en `Full`. **Es falso**, y se midió:
|
||||
con "Always Use HTTPS" apagado, una petición HTTP a la ruta del reto a través de Cloudflare devuelve
|
||||
**404 con 0 bytes y `server: cloudflare`**, es decir, Cloudflare **sí reenvía al puerto 80** y
|
||||
responde el handler de Traefik.
|
||||
|
||||
---
|
||||
|
||||
*Lo que sigue es el diagnóstico, que se conserva porque explica cómo se llegó hasta aquí y contiene
|
||||
un par de trampas que conviene no repetir.*
|
||||
|
||||
## Resumen del problema (histórico)
|
||||
|
||||
Traefik no conseguía el certificado de `www.feadulta.com` ni de `feadulta.com`. **No había nada roto
|
||||
para los visitantes**: Cloudflare presentaba su propio certificado, y hacia el origen —con el modo
|
||||
SSL de la zona en `Full`— aceptaba el certificado por defecto de Traefik. El único coste era que la
|
||||
zona no podía subir a `Full (strict)`.
|
||||
|
||||
La causa: el reto HTTP-01 acababa llegando por HTTPS y Cloudflare lo bloqueaba con un 403.
|
||||
|
||||
## Lo que dice Let's Encrypt, que es el único testigo que vale
|
||||
|
||||
@@ -79,33 +121,11 @@ SSL. **La regla no se puede montar así.**
|
||||
Es una excepción mínima y acotada: esa ruta no sirve contenido, solo tokens de un solo uso que el
|
||||
propio Traefik genera y valida.
|
||||
|
||||
### ⚠️ Puede que aun así no salga, y conviene saber por qué antes de intentarlo
|
||||
|
||||
Con el modo SSL de la zona en **`Full`, Cloudflare habla con el origen por HTTPS**. Si eso se aplica
|
||||
también a las peticiones que le entran por HTTP, entonces al apagar "Always Use HTTPS" la petición
|
||||
de Let's Encrypt llegará igualmente al **443** de Traefik, donde **el handler de ACME no existe** —y
|
||||
volverá a fallar, ahora con un 404 en vez de un 403.
|
||||
|
||||
No se puede determinar desde aquí sin apagar el ajuste: mientras "Always Use HTTPS" esté encendido,
|
||||
Cloudflare redirige en su borde y **nunca llega a contactar con el origen por el puerto 80**, así que
|
||||
no hay forma de observar qué puerto usaría.
|
||||
|
||||
**Cómo distinguir los dos casos en el siguiente intento**, mirando el error de Traefik:
|
||||
|
||||
| lo que reporte Let's Encrypt | qué significa | qué hacer |
|
||||
|---|---|---|
|
||||
| sale el certificado | Cloudflare reenvía por el 80 y Traefik atiende | nada más |
|
||||
| `403` | el *Skip* del WAF no está cogiendo esa ruta | revisar el ámbito de la regla |
|
||||
| **`404`** | **Cloudflare va al 443 del origen**: HTTP-01 no puede funcionar con la zona en `Full` | **pasar a DNS-01, dejar de quemar validaciones** |
|
||||
|
||||
### Sobre los visitantes durante la ventana
|
||||
|
||||
Apagar "Always Use HTTPS" unos minutos es inocuo, pero **no exactamente por el motivo que parece**.
|
||||
Si Cloudflare reenviara por el 80, Traefik devuelve un 302 a HTTPS por su cuenta (medido) y el
|
||||
visitante acaba igual. Si Cloudflare va al 443, ese 302 no llega a dispararse y **un visitante que
|
||||
entre por `http://` se quedará en `http://`** — con el contenido correcto y cifrado hasta Cloudflare,
|
||||
pero sin subir a HTTPS. Para una ventana de minutos no tiene consecuencias, pero que nadie se
|
||||
extrañe si lo ve.
|
||||
Apagar "Always Use HTTPS" unos minutos resultó inocuo: Cloudflare reenvía al puerto 80 del origen y
|
||||
**Traefik devuelve su propio 302 a HTTPS**, así que el visitante acaba en HTTPS igual. Medido antes
|
||||
y durante.
|
||||
|
||||
### Alternativa de fondo, para más adelante
|
||||
|
||||
@@ -148,11 +168,8 @@ Cuesta **unos 7 segundos** de corte: se ha medido dos veces, un único 500 y vue
|
||||
|
||||
### Comprobar si ya salió
|
||||
|
||||
```bash
|
||||
docker exec coolify-proxy cat /traefik/acme.json | grep -oE '"main":"[^"]*feadulta[^"]*"'
|
||||
```
|
||||
|
||||
Hoy sólo aparecen `antiguo.feadulta.com`, `nuevo.feadulta.com` y `gitea.feadulta.com`.
|
||||
⚠️ **No con `grep`** — ver el aviso del principio: el fichero escribe `"main": "dominio"` con
|
||||
espacio y un patrón sin espacio da vacío siempre. Parsear el JSON.
|
||||
|
||||
## Cabo suelto ya cerrado por el camino
|
||||
|
||||
@@ -161,7 +178,7 @@ cualquier 404. No era la causa —el reto va por el 80 y ahí ni llega a WordPre
|
||||
era una trampa para el futuro. Arreglado y desplegado: las rutas de protocolo quedan exentas y el
|
||||
resto del redirect sigue igual. Lo encontró el Claude de Inma.
|
||||
|
||||
## Cuando el certificado salga
|
||||
## `Full (strict)`
|
||||
|
||||
Entonces —y sólo entonces— se puede subir la zona a **`Full (strict)`**, que valida además el
|
||||
certificado del origen. Hacerlo antes rompe el sitio.
|
||||
Ya se puede: los tres certificados están emitidos. Sube la seguridad porque valida además el
|
||||
certificado del origen. **Comprobar el sitio justo después de cambiarlo.**
|
||||
|
||||
Reference in New Issue
Block a user