Ir al contenido

Proxies, HTTPS y conexiones persistentes

El proxy recibe HTTPS y reenvía HTTP a Granian por una conexión privada. Solo el proxy debe alcanzar el puerto del backend. Las guías de Windows, Linux y Docker incluyen su configuración completa; esta página explica el contrato que deben respetar.

Orionis ejecuta ProxiesMiddleware antes de resolver rutas. Solo acepta encabezados reenviados cuando la IP del par que se conecta al backend pertenece a http.proxies.trusted_proxies, configurado en config/http.py. El valor predeterminado contiene 127.0.0.1.

# Proxy en el mismo servidor, conectado por IPv4 loopback.
TRUSTED_PROXIES=list:["127.0.0.1"]
ALLOWED_HOSTS=list:["app.example.com"]
DatoComportamiento real
X-Forwarded-ForReúne los encabezados y recorre la cadena de derecha a izquierda hasta el primer salto no confiable. Omite valores que no sean IP válidas.
X-Forwarded-ProtoAcepta el primer encabezado si su valor completo es http o https. No acepta una lista como https,http.
HostDebe conservar el dominio público; la seguridad HTTP y la construcción de URLs lo utilizan.
Forwarded, X-Forwarded-Host, X-Forwarded-PrefixNo sustituyen a los datos anteriores en este middleware. No habilitan automáticamente un despliegue bajo un subdirectorio.

La confianza admite IP y CIDR. Usa las direcciones precisas de tu proxy, incluyendo ::1 solo si realmente conecta por IPv6. No copies rangos amplios por comodidad. En Docker, 127.0.0.1 identifica el propio contenedor: la guía asigna una IP privada estable a Caddy y confía únicamente en ella.

Con varios proxies, protege también el primer salto público y configura allí qué encabezados puede aceptar de su propio upstream. Estas guías suponen un único proxy público y no una CDN adicional. El proxy de borde reemplaza los valores suministrados por clientes; el backend no debe quedar accesible por otra ruta que permita hacerse pasar por ese proxy.

sequenceDiagram
    accTitle: Normalización de una petición detrás del proxy
    participant C as Cliente
    participant P as Proxy confiable
    participant O as Orionis
    C->>P: HTTPS app.example.com/ruta
    P->>O: HTTP privado + Host público + X-Forwarded-For + X-Forwarded-Proto=https
    O->>O: Validar IP del proxy y normalizar cliente/esquema
    O->>O: Seguridad, ruta, middleware y controlador
    O-->>P: Respuesta HTTP
    P-->>C: Respuesta por HTTPS

Preserva la ruta completa, query string, método y Origin. El origen de WebSocket debe coincidir con la política de http.websocket.allow_origins; su configuración predeterminada permite el mismo origen. No añadas * para compensar un Host o esquema incorrecto. Consulta WebSocket.

Nginx necesita reenviar explícitamente Upgrade y Connection para WebSocket; la guía usa un map, HTTP/1.1 hacia Granian y tiempos de inactividad ampliados. Para SSE utiliza proxy_buffering off; proxy_request_buffering off permite reenviar progresivamente cuerpos de petición. Ajusta además el límite de uploads del proxy y el de Orionis según los payloads reales. WebSocket en Nginx y directivas de proxy.

Caddy gestiona el upgrade WebSocket y descarga inmediatamente respuestas text/event-stream. Los ejemplos conservan ese comportamiento; no fuerzan flush_interval -1 globalmente, porque también cambia la cancelación del backend al desconectar el cliente. Proxy de Caddy.

No caches ni transformes respuestas SSE, tokens o sesiones en el proxy. Para SSE y MCP por HTTP, comprueba recepción incremental y desconexión. Los timeouts entre lecturas no hacen infinita una conexión ni sustituyen los heartbeats de la aplicación. Reiniciar un proceso cierra sus conexiones; los clientes deben poder reconectar.

En routes/api.py, registra esta ruta sin middleware de autenticación propio, solo durante una comprobación controlada. El contexto API no añade automáticamente un prefijo /api:

from orionis.http import JSONResponse, Request
from orionis.support.facades import Route
async def deployment_check(request: Request) -> JSONResponse:
return JSONResponse({
"client": request.ip,
"scheme": request.scheme,
"url": request.url,
})
Route.get("/_deployment/check", deployment_check)

Reinicia la aplicación tras añadirla. Desde otro equipo:

Ventana de terminal
curl -fsS https://app.example.com/_deployment/check
curl -fsS -H "X-Forwarded-For: 192.0.2.123" https://app.example.com/_deployment/check

Ambas respuestas deben mostrar la IP observada por el proxy —puede ser la de tu NAT—, scheme: "https" y el dominio público en url. El segundo comando no debe imponer la IP ficticia. Un resultado HTTP 400 puede indicar ALLOWED_HOSTS incorrecto; un esquema http suele indicar que no coincide la IP confiable o el encabezado.

Comprueba luego /up por HTTPS. Para probar el backend local con una lista de hosts restringida, proporciona el mismo Host:

Ventana de terminal
curl -fsS -H "Host: app.example.com" -H "Accept: application/json" http://127.0.0.1:8000/up

En Windows utiliza curl.exe; en Docker ejecuta la comprobación dentro de la red privada como indica su guía. Una respuesta 200 del backend no verifica el certificado, DNS o proxy: realiza ambas pruebas. Elimina la ruta temporal y reinicia al terminar.

SíntomaComprobación concreta
502 o conexión rechazadaServicio iniciado, puerto y upstream coincidentes, directorio correcto y errores del proceso Granian.
400 por dominioHost recibido y lista ALLOWED_HOSTS; no cambies el host público por 127.0.0.1.
IP de proxy o esquema incorrectoIP real del par del backend, TRUSTED_PROXIES, configuración efectiva y caché de bootstrap anterior.
Cookies o WebSocket fallan con HTTPSEsquema y dominio públicos, SESSION_SECURE, política de origen y encabezados de upgrade.
Eventos llegan juntos o se cortanBuffering, timeouts/heartbeats y reinicios del proxy o aplicación.
/static devuelve 404Archivo en el disco público y argumentos de montaje; la ejecución directa de Granian no lee config/filesystems.py.

Los fallos antes de completar el arranque pertenecen a los logs del supervisor. Los errores dentro de la aplicación se investigan con Logs y Exceptions, con APP_DEBUG=bool:false en producción.