Desarrollo remoto: Code-Server, Coolify y Hetzner - las trampas de arquitectura más peligrosas
Como desarrollador de software autónomo y consultor de TI, la flexibilidad lo es todo. Ya esté trabajando en backends complejos con Java Spring Boot, creando frontends con JavaScript o renderizando visualizaciones con Three.js, el entorno de desarrollo debe ser ágil, reproducible y accesible desde cualquier lugar.
Por eso dejé atrás el enfoque clásico de alojamiento y trasladé mi infraestructura a un servidor propio de Hetzner, completamente orquestado por Coolify. En el centro se encuentra una instancia remota de VS Code (Code-Server).
En teoría, es una configuración de ensueño. En la práctica, caí en trampas de arquitectura que casi me vuelven loco. Estos son los mayores obstáculos y cómo evitarlos de forma elegante.
Trampa 1: la ilusión del proxy de puertos (o la pantalla negra de la muerte)
VS Code en el navegador ofrece una función aparentemente genial: el reenvío de puertos integrado. Cuando inicias un servidor de pruebas local, por ejemplo en el puerto 4096, el IDE crea automáticamente un túnel hacia una URL como https://tu-ide.es/proxy/4096/.
Para el desarrollo puramente backend, como una API REST con Spring Boot que solo devuelve JSON, es fantástico. No hacen falta reglas de firewall y el acceso es directo.
Sin embargo, en cuanto inicias un frontend moderno con Vue, React o Vite, o una herramienta con interfaz gráfica, aparece una pantalla negra acompañada de interminables errores 404 en la consola.
El motivo: Los frameworks modernos compilan con rutas absolutas, por ejemplo <script src="/main.js">. El navegador ignora por completo el subdirectorio /proxy/4096/, busca los archivos en la raíz del servidor y falla.
La solución: Traefik y subdominios
La única arquitectura limpia consiste en ignorar por completo el túnel integrado de VS Code. En su lugar, utilizamos el proxy inverso Traefik de Coolify:
- Crea en tu proveedor de dominio un registro comodín (
*.tudominio.es) que apunte a tu servidor de Hetzner. - En Coolify, añade a los dominios del contenedor un nuevo subdominio con el puerto interno:
https://dev.tudominio.es:4096. - Traefik gestiona automáticamente el certificado SSL y dirige la URL pública limpia, sin un puerto añadido, directamente al contenedor. El frontend se carga correctamente.
Trampa 2: el engaño de localhost (502 Bad Gateway)
Has configurado el subdominio en Coolify y esperas con ilusión la vista previa, pero recibes un frío 502 Bad Gateway. Traefik funciona, pero el contenedor bloquea la conexión.
Esto sucede cuando tu servidor interno, como Five Server o una herramienta propia, escucha por defecto en 127.0.0.1. En el mundo de Docker, esto significa que el servicio se comunica solo consigo mismo dentro del contenedor. Cuando el proxy Traefik llama desde fuera, la puerta permanece cerrada.
La solución: Obliga a tu servidor de pruebas a escuchar en todas las interfaces de red. Si lo inicias desde el terminal, utiliza --hostname=0.0.0.0 o define la variable de entorno HOST="0.0.0.0". Si usas una extensión de VS Code como Five Server, modifica settings.json:
{
"fiveServer.host": "0.0.0.0",
"fiveServer.port": 5500
}
Trampa 3: la amnesia de Docker («Restart» hoy, desaparecido mañana)
Configuras cuidadosamente tu .bashrc con alias útiles, generas una clave SSH para GitHub, detienes el contenedor desde Coolify y al día siguiente haces clic en «Deploy». De repente, todo ha desaparecido. Tus alias se han borrado y Git vuelve a pedir contraseñas.
No es un error, sino una función. Un contenedor detenido aparece brevemente con la opción «Restart». Durante la noche, la recolección de basura de Coolify limpia el servidor y elimina por completo el contenedor inactivo. Al pulsar «Deploy», el contenedor se crea de nuevo a partir de la imagen base y todo lo que no era persistente se pierde.
La estructura correcta
Nunca confíes en el almacenamiento efímero del contenedor. Utiliza montajes bind o volúmenes de Docker para todo lo que deba conservarse.
volumes:
- type: bind
source: /opt/appdata/workspace # Tu código
target: /workspace
- type: bind
source: /opt/appdata/config # Ajustes de VS Code, claves SSH y .bashrc
target: /config
Trampa 4: configuración de CORS detrás del proxy inverso
La última trampa suele aparecer durante el desarrollo full stack. Tu frontend está en https://dev.tudominio.es y envía solicitudes al backend de Spring. Por costumbre, incluyes el puerto en tu CorsConfiguration:
// ¡INCORRECTO si hay un proxy inverso delante!
configuration.setAllowedOriginPatterns(
Arrays.asList("https://dev.tudominio.es:5500")
);
El backend vuelve a bloquear la solicitud. ¿Por qué? Porque el puerto 5500 es solo una instrucción de enrutamiento interna de Coolify. Hacia el exterior, el navegador se comunica de forma transparente con el proxy Traefik mediante el puerto HTTPS estándar 443. Por tanto, establece el encabezado Origin simplemente en https://dev.tudominio.es.
Elimina el puerto de la configuración del backend y los errores de CORS desaparecerán.
Conclusión: Un entorno propio con Coolify y Code-Server en Hetzner requiere al principio algo de paciencia y un conocimiento sólido de Docker. Sin embargo, cuando el enrutamiento está bien configurado, los volúmenes están montados y los puertos son correctos, dispones de un IDE privado en la nube de alto rendimiento que no tiene nada que envidiar a las soluciones SaaS tradicionales.