Ejecutar el relay detrás de un proxy inverso
Un proxy inverso es un servidor web propio que recibe la conexión del navegador
y se la pasa al relay. Lo necesitas cuando quieres HTTPS para un relay en tu LAN
o en un servidor, cuando el relay debe vivir bajo una subruta de un sitio que ya
tienes (https://), o cuando el edge de un túnel (por ejemplo,
Cloudflare) se sitúa entre el navegador y el relay. Un proxy en la propia
máquina del relay funciona sin ningún ajuste. Un proxy en otra máquina necesita
dos o tres, que se muestran más abajo. Cinco claves de
config. informan al relay sobre el proxy, y cada una resuelve algo
concreto; se explican después.
Qué debe hacer el proxy #
La página del relay, su API y su conexión en vivo usan un único puerto (3333
salvo que hayas cambiado port). El proxy debe:
- Dejar pasar los upgrades a WebSocket. La app mantiene abierta una
conexión Socket.IO con el relay, en la ruta
/(con un prefijo,socket. io/ <prefix>/). Si los upgrades no pasan, la página carga pero nunca muestra actualizaciones en vivo.socket. io/ - No almacenar en búfer ni cortar por tiempo las conexiones de larga duración. Ese socket permanece abierto mientras la página esté abierta, y los turns se transmiten por él a medida que ocurren. Usa tiempos de espera de lectura e inactividad largos, y no almacenes las respuestas en búfer.
- Dejar pasar la cabecera
Host, o enviarX-. El relay construye a partir de ella la dirección de un enlace compartido y Nuevo en 0.9.11 acepta la conexión en vivo solo desde una página en esa dirección (consultaForwarded- Host allowed).Origins X-yForwarded- Host X-solo cuentan si vienen de un proxy en el que el relay confía.Forwarded- Proto - Enviar
X-cuando el proxy termina TLS, para que el relay sepa que el navegador usó HTTPS (consulta Cookies y HTTPS), yForwarded- Proto X-, para que conozca la dirección del cliente.Forwarded- For - Mantener la ruta tal cual. No la reescribas. Si sirves el relay bajo un
prefijo, el relay quita el prefijo por sí mismo (consulta
remote).Path
No necesitas ninguna regla de caché. El relay envía Cache-
para su página, su service worker, su manifiesto y su API, y también
CDN- y Cloudflare-. No
añadas una regla que almacene en caché /: las vistas compartidas
consultan periódicamente si hay contenido nuevo, y una respuesta en caché
mostraría a los espectadores una instantánea antigua.
Un ejemplo mínimo de Caddy para un relay en la misma máquina. Caddy deja pasar
los upgrades a WebSocket por sí mismo y añade X-:
relay.example.com {
reverse_proxy 127.0.0.1:3333
}
Para nginx o cualquier otro proxy, consulta en su propia documentación cómo dejar pasar los upgrades y fijar los tiempos de espera, y compáralo con la lista de arriba. Para los túneles, consulta Túnel SSH y Cloudflare Tunnel; para el token de acceso, consulta Acceso.
Un proxy en otra máquina Nuevo en 0.9.11 #
Los túneles integrados y un proxy en la propia máquina del relay llegan al relay
por 127., y el trust predeterminado se fía de sus cabeceras
reenviadas. Un proxy en otro host, o en otro contenedor o máquina virtual, es un
interlocutor distinto. Hasta que confíes en él, el relay ignora sus
X-, X- y X-, así que:
- todos los visitantes tienen la dirección del proxy: un solo bloqueo de inicio de sesión para todos ellos, y una sola dirección en cada entrada del registro de accesos;
- los enlaces compartidos nuevos empiezan por
http://y el host que envió el proxy; - la cookie de inicio de sesión no se marca como
Secure.
Fija tres claves en el archivo de configuración y reinicia el relay:
{
"localhostOnly": false,
"trustProxy": "192.0.2.10",
"allowedOrigins": ["https://relay.example.com"]
}
localhostdeja que el relay escuche más allá de loopback. Mantén el puerto cerrado a todo salvo al proxy.Only: false trustes la dirección del proxy, su subred o el número de proxies delante del relay (Proxy 1para uno). Consulta más abajo.allowedsolo hace falta cuando el proxy reescribe la cabeceraOrigins Hosty no envíaX-. Consulta más abajo.Forwarded- Host
Un proxy en la propia máquina del relay no necesita ni trust ni
localhost, y allowed solo si reescribe Host. Bajo un
prefijo de URL, fija también remote.
Las claves que informan al relay sobre el proxy #
Las cinco están en la tabla de config.json. Reinicia el relay después de cambiarlas.
trustProxy #
Predeterminado "loopback". Decide de qué cabeceras X- se fía el
relay. Con el valor predeterminado, solo se fía de un proxy que se conecta desde
la misma máquina, lo cual es lo correcto para Caddy, nginx o cloudflared
ejecutándose junto al relay.
Lo que el relay toma de las cabeceras de un proxy de confianza:
- si la solicitud llegó por HTTPS, lo que decide si la cookie de inicio de
sesión lleva el indicador
Secure, y el esquema de un enlace compartido nuevo; - el host al que se dirigió el navegador (
X-), para los enlaces compartidos nuevos y para la comprobación del origen de la conexión en vivo;Forwarded- Host - la dirección del cliente, para el bloqueo de inicio de sesión, el límite de presencia de
las vistas compartidas y el registro de accesos de los enlaces compartidos. El país de ese
registro (
cf-) también se lee solo de un proxy de confianza.ipcountry
Si tu proxy se ejecuta en otra máquina, el relay ve un interlocutor no local e
ignora esas cabeceras. Dale a trust lo que acepta trust proxy de
Express: un número de saltos (1), una dirección o subred ("10.),
una lista de ellas o "loopback".
Solo con un proxy delante
Fija trust más amplio que "loopback" solo cuando todas las conexiones
al relay pasen de verdad por tu proxy. Si no, cualquiera que llegue al puerto
puede enviar un X- falsificado.
Nuevo en 0.9.11 Todo uso de una cabecera reenviada sigue a trust. En
0.9.10, el límite de presencia de las vistas compartidas y la dirección de un
enlace compartido nuevo las leían de cualquier cliente.
allowedOrigins Nuevo en 0.9.11 #
Predeterminado []. La conexión en vivo (Socket.IO) acepta el handshake de un
navegador solo desde el propio origen del relay: el Origin que envía el
navegador debe tener el host al que se dirigió el navegador, que es
X- cuando un proxy de confianza lo envía y Host en caso
contrario. Una página de otro sitio no puede usar tu cookie de inicio de sesión
para abrir una conexión en vivo. Los clientes que no envían Origin, como los
scripts, no se ven afectados.
Un proxy que reescribe la cabecera Host con la dirección interna del relay y
no envía X- rompe esa comparación. En ese caso, lista el origen
público exactamente como lo muestra el navegador, con esquema, host y cualquier
puerto distinto del predeterminado:
"allowedOrigins": ["https://relay.example.com"]
Sin él, la página carga y puedes iniciar sesión, pero nada se actualiza en vivo, y el relay registra una vez por origen:
[socket] Refused a handshake from origin https://relay.example.com (host 127.0.0.1:3333); list it in allowedOrigins if a proxy rewrites the Host header
remotePath #
Predeterminado "". Fíjalo al prefijo cuando el proxy sirve el relay bajo una
subruta, por ejemplo "/. Se añade una barra inicial y se quitan las barras
finales.
Con él fijado, el relay:
- quita el prefijo de cada solicitud entrante, así que el proxy pasa la ruta con el prefijo y no lo elimina;
- pone el prefijo en la ruta de la cookie de inicio de sesión, la ruta del
socket (
/) y las direcciones de archivos y enlaces compartidos.oar/ socket. io/
Sin él, un relay bajo un prefijo no encuentra sus propios archivos ni su
socket, porque la página pide / y / en la raíz del sitio.
Abre el relay con la barra final (https://).
Una app instalada pertenece a la dirección desde la que se instaló, así que un relay bajo un prefijo es una app propia. Consulta Instalar como app.
publicHostnames #
Predeterminado []. Lista los nombres de host que llegan al propio relay, por
ejemplo ["relay.. El relay los usa en un único sitio: la preview
lane rechaza un previews. en uno de esos nombres (o en
localhost o 127.), para que una app en vista previa nunca comparta una
cookie de inicio de sesión con el relay. Si pones el relay detrás de un proxy
con un nombre nuevo y usas vistas previas, añade ese
nombre aquí.
tunnelMarkerHeaders #
Predeterminado []. Los nombres de las cabeceras que tu proxy o el edge de tu
túnel añade a cada solicitud que reenvía. El relay los usa para la
protección de rutas del worker de sesión descrita abajo.
cf-, que añade Cloudflare, está siempre en la lista. El valor puede ser un
array o una cadena separada por comas. La variable de entorno
COPILOT_ (separada por comas) añade más nombres;
Nuevo en 0.9.11 las dos listas se combinan, así que tunnel ya
no desactiva la variable. Consulta
Variables de entorno.
El punto de estado
tunnel no vuelve ámbar el punto de estado. El punto está ámbar
mientras el túnel de Cloudflare gestionado por el propio relay está conectado
(consulta el menú de la conversación). Un proxy que
ejecutas tú nunca lo vuelve ámbar.
La protección de rutas del worker de sesión #
Cada sesión de agente se ejecuta en un worker en la máquina del relay, y el
worker habla con el relay por un WebSocket en / (con un
prefijo, <prefix>/). Un proxy o un túnel reenvía al relay
todas las rutas de su nombre de host, así que sin una protección esa ruta sería
accesible desde internet. Solo deben usarla los workers locales.
Nuevo en 0.9.11 La protección deja pasar una solicitud a esa ruta solo cuando viene de la propia máquina del relay y nada la ha reenviado:
- el interlocutor que se conecta es loopback (
127.o0. 0. 1 ::);1 - no lleva ninguna cabecera marcadora:
cf-, o una deray tunnel;Marker Headers - no lleva
X-,Forwarded- For ForwardedniX-.Real- IP
Todo lo demás se rechaza antes de comprobar el inicio de sesión:
- una solicitud normal recibe
403con{"error":"Session worker endpoints are reachable from this machine only"}; - un upgrade a WebSocket recibe
403 Forbiddeny la conexión se cierra.
Cada rechazo se registra como [tunnel-, indicando qué delató la solicitud. Los workers locales se conectan a
127. directamente, sin ninguna de esas cabeceras, y no se ven afectados.
Los enlaces compartidos siguen funcionando a través del túnel: la protección se
basa solo en la ruta del worker, no en que una solicitud sea anónima.
Cloudflare añade cf- y Caddy añade X- por sí mismo, así que
la protección funciona con ellos sin ningún ajuste; con nginx, envía
X- con proxy_. Un reenviador que no añade nada en
absoluto, como un túnel SSH inverso o un proxy TCP simple, parece un proceso
local; la ruta queda entonces protegida solo por el token de acceso. Con un
reenviador así, haz que añada una cabecera con un valor fijo no vacío, por
ejemplo X-, y lista su nombre:
"tunnel. O rechaza la ruta delante del relay.
Endpoints que solo puede usar la máquina del relay #
Nuevo en 0.9.11 Dos cosas solo responden a solicitudes de la propia máquina del relay que no haya reenviado ningún proxy, con la misma regla que la protección de rutas:
- el socket del worker de sesión, descrito arriba;
- la ejecución de una operación de imagen
(
POST /), a la que llaman los propios workers del relay. Todo lo demás recibeapi/ image- operations/ …/ execute 403Image operation execution is reachable from this machine only (La ejecución de operaciones de imagen solo es accesible desde esta máquina).
Todo lo demás solo necesita el token de acceso, venga de donde venga. Eso incluye 🌄 Restart web relay (Reiniciar el relay web), retirar un reinicio en cola con el botón Cancel (Cancelar) de su banner, y 🚮 Empty queue (Vaciar la cola): cualquier navegador con sesión iniciada puede usarlos, también por la LAN y a través de cualquier proxy o túnel.
Hasta 0.9.10 estas tres cosas estaban pensadas solo para la máquina del relay,
pero la comprobación dejaba pasar todo lo que llegaba por un túnel o un proxy en
la misma máquina, y rechazaba una conexión LAN directa mientras la página
informaba de éxito. Si los usuarios remotos no deben reiniciar el relay ni
vaciar su queue, haz que el proxy rechace POST /,
POST / y POST /.
oar restart en la máquina del relay siempre funciona.
Cookies y HTTPS #
La cookie de inicio de sesión es Http y Same, dura 30 días y
tiene la ruta / (o el prefijo de remote). Lleva Secure cuando el relay
considera que la solicitud es segura.
- El proxy termina TLS en la misma máquina. El proxy envía
X-, elForwarded- Proto: https trustpredeterminado se fía de él y la cookie esProxy Secure. - El proxy termina TLS en otra máquina. Fija
trustcomo se indica arriba. Hasta que lo hagas, la cookie no tiene el indicadorProxy Secure, aunque sigue funcionando. - Configuraciones mixtas. Si también abres el relay directamente por
httpsin cifrar en la LAN, esa solicitud no es segura, así que su cookie no tiene el indicadorSecure; las solicitudes HTTPS a través del proxy sí lo reciben. Los navegadores guardan las cookies por dirección.
Comprobar la configuración #
- Abre la dirección del proxy en un navegador. Aparece el inicio de sesión o la lista de conversaciones.
- Mira el punto de estado: se vuelve verde y la página muestra actualizaciones en vivo cuando inicias un turn. Un estado de reconexión sin fin significa que el WebSocket no pasa.
- Bajo un prefijo, abre la dirección con la barra final. Cargan la página, sus estilos y la conexión en vivo, y la ruta de la cookie es el prefijo (míralo en las herramientas de desarrollo del navegador).
- Crea un enlace compartido (Compartir). Su
dirección usa el nombre de host público y
https, y el prefijo si fijaste uno. - Prueba la protección desde fuera: pide
https://. Deberías verrelay. example. com/ api/ session- worker/ ws 403y una línea[tunnel-en el registro del relay. Si recibes otra respuesta, tu proxy no añade ni una cabecera marcadora niguard] X-.Forwarded- For - Detrás de un proxy en otra máquina: inicia sesión desde dos dispositivos y
comprueba en Settings → Sharing (Ajustes → Compartir) que el registro de accesos de un enlace compartido muestra las
direcciones de los espectadores, no la del proxy. Si muestra la del proxy,
trustno coincide con el proxy.Proxy
Si no funciona #
| Lo que ves | Causa probable |
|---|---|
| La página carga pero se reconecta sin fin, o nunca se actualiza | El proxy no deja pasar los upgrades a WebSocket en /, o cierra las conexiones inactivas. |
La página carga pero nada se actualiza en vivo, y el registro dice Refused a handshake from origin |
El proxy reescribe la cabecera Host. Lista el origen público en allowed, o haz que el proxy deje pasar Host. |
| El inicio de sesión dice Too many failed sign-in attempts (Demasiados intentos de inicio de sesión fallidos) a todo el mundo a la vez | El relay no confía en un proxy en otra máquina, así que todos los visitantes comparten su dirección y su bloqueo. Fija trust. |
| Bajo un prefijo, la página está en blanco o faltan archivos | remote no está fijado, o el proxy elimina el prefijo. El proxy debe pasarlo. |
| Bajo un prefijo, se te pide iniciar sesión una y otra vez | La ruta de la cookie es el prefijo de remote, así que el navegador solo la envía bajo ese prefijo. Abre el relay bajo ese prefijo y con la barra final. |
| Los enlaces compartidos o de archivos tienen una dirección incorrecta o no tienen prefijo | remote no está fijado, o el proxy no envía Host ni X- / X-, o el relay no confía en el proxy. |
Los enlaces compartidos empiezan por http://, o la cookie no tiene el indicador Secure, detrás de un proxy en otra máquina |
trust sigue en "loopback". |
La ruta del worker responde sin un 403 a través de tu proxy |
El proxy no añade ni una cabecera marcadora ni X-. Consulta la protección de rutas. |
| El punto nunca se vuelve ámbar | Es lo esperado: solo lo hace el túnel de Cloudflare gestionado por el propio relay. |
| Las vistas previas no arrancan con el nombre nuevo | Añade el nombre de host del relay a public. |
Para el primer inicio de sesión y el token de acceso, consulta Primer arranque.