Cómo desplegar Docker sin administrar un servidor
Sigue esto en tu propio servidor. Empieza gratis, sin tarjeta
docker build funciona. docker run -p 3000:3000 myapp funciona en tu computadora. Lo que todavía no existe es todo lo que hay entre “este contenedor corre” y “esto es un servicio en producción”: un proxy inverso al frente, un certificado que se renueva solo, un proceso que reinicia tras un fallo, un servidor cuyo sistema operativo recibe parches, y alguien o algo vigilando si de verdad está arriba. Nada de esto es específico de tu app. Todo es específico de operar un servidor, que es la parte que mucha gente con un Dockerfile que funciona preferiría no aprender desde cero.
Esta guía es para esa situación: tienes un Dockerfile, construye, y quieres que corra en producción sin convertirte en la persona que mantiene una máquina Linux. Cubre qué implica realmente “administrar un servidor”, la versión manual de hacerlo tú mismo (en breve, porque no es el punto), y luego el camino que lo elimina.
Qué significa realmente “administrar un servidor”
Cada uno de estos puntos es un problema pequeño y bien entendido por separado. Juntos, para un solo contenedor, representan una cantidad desproporcionada de trabajo continuo:
- Actualizaciones del sistema operativo. Los parches de seguridad para la instalación de Ubuntu o Debian en sí, independientemente de lo que haya en tu Dockerfile, hay que aplicarlos con cierta cadencia, y algunos necesitan un reinicio para tener efecto.
- Instalar y mantener Docker. El motor de Docker en el host es un software aparte con su propio camino de actualización, separado de cualquier imagen que corras encima.
- Un proxy inverso. Algo tiene que terminar el HTTPS y reenviar las solicitudes al puerto de tu contenedor; eso es configuración de nginx o Caddy, escrita y mantenida sincronizada con tu app a mano.
- Renovación de certificados. Los certificados de Let’s Encrypt expiran cada 90 días. Algo tiene que pedir el primero, probar la propiedad del dominio, y renovarlo antes de que venza, indefinidamente, sin que nadie tenga que acordarse de hacerlo.
- Monitoreo. Saber que el contenedor realmente está sirviendo tráfico, no solo que
docker pslo muestra corriendo, requiere algo que lo verifique desde fuera de la máquina. - Política de reinicio y reglas de firewall. Un fallo tiene que traer de vuelta el proceso sin que un humano entre por SSH, y la máquina solo debe tener abiertos a internet los puertos que realmente sirve.
Nada de esto es difícil por separado. Es el tipo de trabajo que es invisible hasta la semana en que deja de serlo: un certificado expira en silencio, un CVE sin parchar queda abierto por meses, o un fallo a las 2 a.m. simplemente se queda caído.
La versión manual, en breve
En un VPS con Ubuntu 24.04, esto es Docker más Caddy como proxy inverso:
curl -fsSL https://get.docker.com | sh
Un Caddyfile al frente del contenedor:
myapp.example.com {
reverse_proxy localhost:3000
}
docker run -d --name myapp --restart unless-stopped -p 3000:3000 --env-file .env myapp:latest
caddy run --config Caddyfile
Caddy solicita y renueva su propio certificado de Let’s Encrypt automáticamente una vez que el DNS apunta al servidor y los puertos 80/443 son alcanzables, lo cual cubre la renovación del certificado. --restart unless-stopped cubre la parte de recuperación tras un fallo. Lo que queda, y que esta versión corta no resuelve, es todo lo de la lista de arriba que no es el contenedor en sí: parches del sistema según un calendario, las propias actualizaciones de Docker, reglas de ufw mantenidas sincronizadas con lo que realmente corre, y algo externo verificando que el sitio realmente es alcanzable, nada de lo cual viene de correr Caddy y Docker correctamente.
El camino que se encarga del resto
Apunta Railyard al mismo repositorio, o a una imagen ya existente. La detección de build de Railyard elige un Dockerfile automáticamente cuando el repositorio tiene uno que realmente construye la app; una imagen de desarrollo que solo espera un bind mount se omite en vez de desplegarse; consulta los métodos de build. Para una imagen que ya está en un registro en vez de en un repositorio, image://ghcr.io/you/myapp:latest como fuente funciona igual, y el puerto que tu Dockerfile expone con EXPOSE se lee directo del registro, sin configuración manual de puerto; consulta desplegar una imagen Docker.
Lo que ese único paso realmente reemplaza, frente a la lista manual de arriba:
- El proxy inverso y el certificado TLS no son algo que escribas. Cada app recibe de inmediato
https://<name>.<server-ip>.sslip.iocon un certificado; apuntar tu propio dominio agrega un registro DNS y una verificación de propiedad (un registro TXT que Railyard verifica antes de emitir nada, para que nadie pueda apuntar un dominio que no controla hacia tu app), y el certificado a partir de ahí es automático. Consulta dominios y HTTPS. - Las actualizaciones del sistema aparecen en la propia página del servidor, con un conteo de actualizaciones pendientes y cuántas son específicamente de seguridad; las actualizaciones de seguridad nocturnas se aplican sin intervención, y nada reinicia la máquina sin que tú lo elijas. Consulta mantenimiento del servidor.
- La política de reinicio no es una bandera que tengas que acordarte de agregar. Es simplemente cómo corre el contenedor de cada app.
- Los despliegues en sí no causan caídas: se descarga o construye una imagen nueva, corre el comando de release (si configuraste uno), y el tráfico solo cambia hacia ella una vez que el nuevo contenedor realmente responde, la misma forma sin downtime sea que cambió la imagen o el código.
- Una imagen basada en registro que se actualiza sola puede redesplegarse automáticamente: activa Deploy when the tag changes en Settings → Source, y Railyard revisa el registro cada cinco minutos (o al instante, vía un webhook que agregas al registro) y redespliega cuando el digest cambia, así que un
docker pushde unlatestnuevo se convierte en todo el proceso de release. Consulta desplegar una imagen Docker.
Algo que vale la pena precisar: Railyard no es una plataforma de contenedores serverless que posee el hardware por ti. Igual agregas un servidor, ya sea uno que Railyard crea en tu cuenta de DigitalOcean, Hetzner, Vultr, AWS u OVH, o cualquier máquina Ubuntu 22.04/24.04 a la que ya tengas acceso por SSH, y tu proveedor de nube te cobra directamente por la máquina en sí. Consulta agregar un servidor. Lo que desaparece es todo lo que está por encima de poseer esa máquina: instalar Docker en ella, escribir y mantener la configuración del proxy inverso, pedir y renovar certificados, y parchar el sistema operativo a mano.
Variables y secretos
Lo que sea que tu contenedor lea de su entorno, configúralo en la pestaña Variables de la app; los valores se cifran y se aplican en el siguiente despliegue. Si tu imagen necesita una credencial que de verdad tiene que ser un archivo en vez de una variable (un JSON de cuenta de servicio, un certificado de cliente), Variables → File secrets lo monta de solo lectura dentro del contenedor y expone su ruta como variable de entorno, así que GOOGLE_APPLICATION_CREDENTIALS=${RAILYARD_SECRET_FILE_GCP_KEY_JSON} se resuelve sin copiar el archivo manualmente al servidor. Consulta variables y secretos.
Solución de problemas
El despliegue tiene éxito pero la app nunca aparece en el dominio. Revisa el estado del dominio en la pestaña Domains de la app: unverified significa que el registro TXT de propiedad todavía no se encuentra (propagación de DNS, o un error de tipeo en el registro), misconfigured significa que falló la emisión del certificado y la tarjeta explica por qué, y unrouted significa que el dominio se verificó pero la app no ha redesplegado desde entonces, lo cual un redespliegue soluciona.
Un Dockerfile que funciona en local falla al construirse. La brecha más común entre un build local y uno de Railyard es una imagen que asume un directorio fuente montado con bind mount en vez de copiar la app dentro de la imagen con COPY; ese patrón es exactamente lo que la detección de build de Railyard trata como una imagen de desarrollo y omite. Confirma que el Dockerfile construye una imagen autocontenida con docker build . y sin banderas -v antes de seguir investigando.
El build se queda sin memoria. Los builds grandes se ajustan automáticamente a un servidor de build temporal y más grande cuando el proveedor lo permite, así que esto es poco común, pero cuando pasa, la página de despliegue lo dice directamente y sugiere el siguiente paso en vez de fallar en silencio.
Preguntas frecuentes
¿Igual necesito saber Docker? Sí, en el sentido de que igual escribes el Dockerfile; lo que esto elimina es todo lo que viene después de una imagen que funciona, no la imagen en sí. Si tu Dockerfile ya construye y corre en local, esa parte del trabajo ya está hecha.
¿Es lo mismo que una plataforma de contenedores serverless como Cloud Run? No. Esas plataformas corren tu contenedor en infraestructura que ellas poseen y te cobran por solicitud o por segundo de cómputo. Railyard lo corre en un servidor que agregas a tu propia cuenta de nube (o una máquina que ya tienes), facturado por tu proveedor, y automatiza lo que implica administrar un servidor por encima de esa máquina.
¿Y si mi imagen necesita más de un puerto, como un endpoint de métricas junto a la app principal? Settings → General → More public ports acepta pares adicionales nombre:puerto, cada uno con su propia dirección HTTPS y certificado de la misma forma que la dirección principal. Consulta redes.
¿Mi contenedor tiene que correr como root? No, y es mejor que no lo haga; eso es una propiedad de tu propio Dockerfile, no algo que Railyard exija de una forma u otra. Un ajuste aparte y opcional, Hardened isolation, en Settings → General, restringe aún más lo que un contenedor puede alcanzar en un servidor compartido con otras apps, vale la pena probarlo con una imagen que no asuma root.
¿Qué pasa exactamente en cada despliegue, paso a paso? Se descarga o construye la imagen, corre cualquier comando de release que hayas configurado contra ella, y solo una vez que el nuevo contenedor responde el tráfico cambia hacia él; el contenedor anterior sigue activo hasta que ese cambio tiene éxito, así que un mal despliegue no se lleva por delante la versión anterior que funcionaba.
El Dockerfile nunca fue la parte difícil. Todo lo que viene después, que la máquina donde corre siga parchada, que el certificado siga válido, y que el proceso vuelva tras un fallo, es lo que “administrar un servidor” significa en la práctica, y también es la parte que no tiene nada que ver con lo que realmente hace tu contenedor.
Por qué eligen Railyard para esto
- Tu propia cuenta en la nube. Despliega en DigitalOcean, Hetzner, Vultr, AWS, OVHcloud, o cualquier servidor Linux por SSH, facturado directamente por tu proveedor, sin márgenes adicionales.
- Un precio fijo por equipo. El plan Free es gratis para siempre: un servidor más un servidor de base de datos, tres apps, sin tarjeta. Pro cuesta $19 al mes por hasta cinco servidores y apps ilimitadas. Team cuesta $49 al mes con servidores ilimitados. Sin cargos por app, por despliegue, por asiento ni por gigabyte.
- Plantillas de un clic. Despliega apps de código abierto, como bases de datos, analítica y herramientas de desarrollo, en tu propio servidor con un clic.
- Bases de datos administradas. Postgres, MySQL y Redis, con copias de seguridad programadas y verificadas por restauración, y recuperación a un punto en el tiempo.
- Despliegue con git push. Despliega desde GitHub, GitLab o la CLI, con HTTPS automático y lanzamientos sin tiempo de inactividad.