Puertos y el botón Abrir
Cómo se publica un puerto
Un puerto dentro de su contenedor no es accesible desde internet hasta que el host lo publica. En el lanzamiento, cada puerto de contenedor declarado se asigna a un puerto libre de la máquina host, tomado del rango que ese host tiene disponible. El puerto del host es al que usted se conecta, y casi nunca coincide con el número del puerto del contenedor, por la misma razón por la que su puerto SSH no es el 22.
Al contenedor se le informa en qué puerto del host quedó cada uno de sus puertos, mediante una variable de entorno por cada puerto TCP publicado:
# inside the instance
env | grep SUPERHEAT_TCP_PORT_
# SUPERHEAT_TCP_PORT_22=40123
# SUPERHEAT_TCP_PORT_8080=41007
SUPERHEAT_TCP_PORT_<n> contiene el puerto del host publicado para el puerto de contenedor <n>. Esto es informativo: está ahí para que un proceso en la instancia pueda anunciar correctamente su propia dirección pública. Los puertos UDP no reciben una variable así.
Qué publica cada modo de lanzamiento
Los puertos vienen de la plantilla, más lo que exija el modo de lanzamiento:
| Modo de lanzamiento | Se publica automáticamente | Además |
|---|---|---|
ssh | puerto de contenedor 22 | más todos los puertos declarados en la plantilla |
jupyter | puertos de contenedor 22 y 8080 | más todos los puertos declarados en la plantilla |
args | nada automático | solo los puertos declarados en la plantilla |
vm | puerto de contenedor 22 | más todos los puertos declarados en la plantilla |
Un puerto declarado puede llevar una etiqueta. Una etiqueta open, open_button u open-button marca ese puerto como destino del botón Abrir. Cualquier otra etiqueta es solo descriptiva, y el puerto se trata como un puerto de aplicación común.
El botón Abrir
Cuando una plantilla declara un puerto de botón Abrir, la pestaña Conectar de la instancia muestra un botón Abrir encima del comando SSH, apuntando a ese puerto en el host. Es un atajo para una interfaz web que sirve su imagen — un front end de inferencia, un panel, un visor — para que no tenga que buscar el puerto publicado.
El número de puerto también se le entrega al contenedor como OPEN_BUTTON_PORT, por si el proceso necesita saber cuál de sus puertos está anunciando la consola.
Cualquier modo de lanzamiento puede tener uno, args incluido. Una plantilla en modo args ejecuta el entrypoint propio de la imagen, pero aun así recibe OPEN_BUTTON_PORT y aun así obtiene un botón Abrir — sin eso, una imagen que sirve una interfaz web nunca podría abrirse desde la consola, que es para lo que más se usa el modo args.
Una instancia en modo jupyter obtiene además su propio botón Abrir JupyterLab. Consulte Abrir JupyterLab.
El token de acceso de la instancia
Cada instancia cuya plantilla lo necesita recibe su propio secreto al desplegarla: el token de acceso. Es el mismo valor que el token de JupyterLab. La pestaña Conectar de la instancia lo muestra bajo Token de acceso, enmascarado, con botones para mostrarlo y copiarlo, y la API se lo devuelve a su organización como access_token de la instancia. Desaparece una vez que la instancia se destruye.
Toda plantilla curada que puede lanzar y que sirve una interfaz web o una API en un puerto publicado exige el token en ese puerto:
| Plantilla | Puerto | Cómo presenta el token |
|---|---|---|
| ComfyUI, Stable Diffusion WebUI (A1111), Fooocus, Kohya_ss, Faster-Whisper (su API de reconocimiento de voz) | el puerto de la aplicación | Un proxy de acceso se sitúa delante de la aplicación. El botón Abrir le inicia sesión; los scripts envían Authorization: Bearer <token> |
| Text Embeddings Inference | 80 | El servidor lo comprueba como su clave de API: Authorization: Bearer <token> en cada solicitud |
| Triton Inference Server | 8000 (HTTP), 8001 (gRPC) | Todas las API excepto la de estado: por HTTP Authorization: Bearer <token>, por gRPC los metadatos triton-grpc-protocol-authorization: Bearer <token> |
| Open WebUI | 8080 | Inicie sesión como admin@superheat.local con el token como contraseña. El registro está desactivado, así que nadie más puede crear una cuenta |
El token cubre las instancias desplegadas después de que su plantilla empezara a exigirlo. Una instancia anterior conserva sus puertos como estaban —abiertos a cualquiera que los encuentre— hasta que la destruya; vuelva a desplegar para obtener el token.
Ollama, InvokeAI, LLaMA-Factory y vLLM están marcadas como Próximamente por ahora. Sus servidores no pueden exigir el token en todas las rutas —la clave de API de vLLM deja abierta una ruta de inferencia—, así que quedan fuera del catálogo hasta que puedan. Las instancias que ya se ejecutan a partir de ellas no se ven afectadas.
# Un puerto de API detrás del token; aquí, Text Embeddings Inference
curl -H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"inputs": "hello"}' \
http://203.0.113.14:41007/embed
Cómo le inicia sesión el botón Abrir
En las plantillas detrás del proxy de acceso, el enlace Abrir lleva el token como ?token=. La primera vez que lo abre, el proxy cambia el token por una cookie en ese navegador y lo lleva a la misma dirección sin él, de modo que el token sale de la barra de direcciones de inmediato. Las visitas posteriores desde el mismo navegador no necesitan el token. Una solicitud sin el token ni esa cookie recibe 401.
La cookie solo sirve para las páginas propias de la aplicación y para abrir la aplicación directamente. Una solicitud que una página de otro origen hace enviar a su navegador —incluido otro puerto de la misma máquina— se rechaza con 403, así que la aplicación de otro inquilino en el host no puede manejar la suya con su cookie.
Una conexión directa —la dirección IP de la máquina y un puerto publicado— es HTTP sin cifrar. El token del enlace Abrir, la cookie y todo lo demás en esa conexión viajan sin cifrar, así que trate el enlace Abrir como una contraseña: no lo pegue en ningún sitio donde no pegaría el token.
Los navegadores envían una cookie a todos los puertos de la misma dirección, no solo al que la fijó. En una conexión directa, abrir una aplicación que otro inquilino ejecuta en la misma máquina —cualquier enlace a la dirección de esa máquina con otro puerto— pone su cookie, y con ella su aplicación, en manos de ese inquilino mientras la instancia exista. Abra los enlaces de otros a esa dirección en otro navegador o en una ventana privada, o llegue a su propia aplicación mediante reenvío SSH.
Reenviar el puerto por SSH llega a la aplicación sin pasar por el proxy, porque SSH ya lo ha autenticado. Detrás del proxy la aplicación escucha en 127.0.0.1, así que reenvíe a esa dirección:
ssh -N -L 8188:127.0.0.1:8188 -p 40123 root@203.0.113.14
Sus propias plantillas
Una plantilla propia exige el token solo en un puerto que declare cómo: el ajuste de acceso del puerto en el editor de plantillas (Proxy de acceso o La app verifica el token), o auth a través de la API. Un puerto sin él se publica exactamente como antes: abierto a cualquiera que encuentre la dirección y el puerto de la máquina. Ponga delante algo que autentique, o llegue a él mediante reenvío SSH. Consulte Puertos.
Llegar a un servicio que usted mismo inició
Los puertos se publican cuando la instancia se lanza. Iniciar un servidor dentro de una instancia en ejecución no publica nada, así que un python -m http.server 8000 recién iniciado no es accesible desde fuera, haga lo que haga el firewall de su equipo.
Tiene dos opciones.
Declarar el puerto en una plantilla y desplegar de nuevo. Esta es la respuesta duradera para cualquier cosa que vaya a ejecutar más de una vez. Agregue el puerto en los puertos de la plantilla, asígnele una etiqueta y vuelva a desplegar. Consulte Puertos.
Reenviarlo por SSH. Esto no requiere volver a desplegar y funciona de inmediato para un puerto que no había previsto:
ssh -N -L 8000:localhost:8000 -p 40123 root@203.0.113.14
Deje eso en ejecución y abra http://localhost:8000 en su navegador. El tráfico pasa por la conexión SSH que ya tiene, así que no se expone nada nuevo a internet.
Sea cual sea la vía que elija, enlace su servicio a 0.0.0.0 en lugar de a 127.0.0.1 si quiere que el puerto publicado funcione. Un proceso que escucha solo en loopback es accesible mediante reenvío SSH, pero no a través de un puerto publicado del host. La única excepción es una aplicación detrás del proxy de acceso: ahí la aplicación escucha en loopback y el proxy es el dueño del puerto publicado.
Protocolos
Un puerto declarado indica un protocolo: tcp, udp, http o https. Los dos primeros son lo que realmente se reserva en el host. Los dos últimos son una pista sobre lo que sirve el puerto, y viajan sobre TCP.
Relacionado
- Puertos — declararlos en una plantilla
- Conectarse por SSH
- Abrir JupyterLab