Tienes un sitio web. Algo de HTML, una hoja de estilos, quizá un poco de JavaScript. Funciona cuando lo abres en tu laptop, y ahora necesita una dirección que otras personas puedan escribir, sin alquilar un servidor, mantenerlo parcheado ni aprender qué es un proxy inverso.
Meterlo en un container resuelve eso. Describes el servidor web una vez en un archivo pequeño, lo subes a un repositorio y un host lo construye y lo ejecuta por ti. Después no hay nada que mantener, porque no hay ninguna máquina tuya en la ecuación.
Esta guía lo hace de principio a fin: el sitio, el archivo del container, el deploy y una dirección en vivo. Tardó 9 segundos desde el push hasta estar en línea, y la última sección explica por qué la mayoría de los ejemplos que encontrarás en internet tardan bastante más.
Míralo en acción
El recorrido original lleva una página desde un repositorio de GitHub hasta un container en ejecución, de principio a fin.
¿Qué necesitas realmente?
Tus archivos, y un archivo más junto a ellos. Esa es la lista completa: sin servidor, sin cuenta de hosting que configurar, sin servidor web que instalar en nada tuyo.
El archivo extra es un Dockerfile. Nombra un servidor web, dice dónde van tus páginas, y eso es todo lo que tiene que hacer. Un host lo lee, construye el resultado una vez y lo ejecuta.
El ejemplo de aquí es un sitio de cuatro archivos: una página HTML, una hoja de estilos, unas líneas de JavaScript y el Dockerfile. El tuyo puede tener mil páginas; nada de lo que sigue cambia.
¿Cómo se escribe el archivo del container?
Tres líneas. Parte de la imagen oficial de nginx, copia tu sitio en la carpeta que sirve y declara el puerto.
FROM nginx:1.27-alpine
COPY site/ /usr/share/nginx/html
EXPOSE 80
Ese es el archivo completo. No hay paso de instalación, porque la imagen ya contiene nginx, ni comando de arranque, porque la imagen ya sabe cómo arrancarlo.
El único valor que conviene conocer es /usr/share/nginx/html, el directorio desde el que sirve esta imagen. Pon tu index.html ahí y el sitio funciona; ponlo en cualquier otro lugar y recibes un 404.
Fija la versión en el tag, como hace aquí 1.27-alpine. Significa que la imagen que construyas el mes que viene es la que construiste hoy, y no la que resulte estar vigente en ese momento.
¿Cómo lo pones en línea?
Sube el repositorio y después apunta una app de container a él. En la dashboard, Web Deployment → elige el repositorio de GitHub → rama y directorio raíz → Create app.
No hay nada que rellenar por el camino. La plataforma encuentra el Dockerfile y marca el build como detectado: sin comando de build, sin comando de arranque, sin puerto, porque las tres cosas ya las responde el archivo que escribiste.

El deploy volvió marcado como Ready in 9 seconds: listo en 9 segundos. Esa es la cifra de la propia plataforma, desde el push hasta una dirección HTTPS en vivo, y es el número que explica la última sección de este post.
¿Funcionó de verdad?
Sí: la dirección sirve el sitio real, no un marcador de posición. Cada archivo volvió con el tamaño exacto en bytes que guarda el repositorio, y el header del servidor indica la versión fijada en el tag.
/ HTTP 200 text/html 2083 B
/style.css HTTP 200 text/css 2218 B
/app.js HTTP 200 application/javascript 204 B
Server: nginx/1.27.5
El JavaScript se ejecuta, la hoja de estilos se aplica y la página se ve como se ve en una laptop. El container no está haciendo nada ingenioso aquí; esa es justamente la gracia de usar uno.
¿Por qué la mayoría de los ejemplos construyen algo mucho más grande?
Porque instalan el servidor web en lugar de partir de uno. Casi todos los tutoriales que encontrarás, incluida la grabación de arriba, empiezan desde una imagen de Linux de propósito general y usan el gestor de paquetes.
FROM ubuntu:latest
RUN apt-get update
RUN apt-get -y install nginx
COPY index.html /var/www/html/index.html
EXPOSE 80
CMD nginx -g "daemon off;"
Funciona, y la página que sirve es idéntica. Lo que cambia es lo que se construye, se sube y se descarga cada vez que despliegas, y el desglose por capas muestra de dónde sale ese peso.
Capa, tal como la reporta docker history | Tamaño |
|---|---|
| Base Ubuntu 26.04 | 135 MB |
apt-get update | 43,1 MB |
apt-get -y install nginx | 3,62 MB |
COPY index.html | 20,5 kB |
Lo que querías, un servidor web y tu página, son 3,64 MB, dentro de una imagen que docker images reporta como 254 MB. El paso apt-get update, que existe solo para que la línea siguiente pueda ejecutarse, es más de diez veces mayor que el software que descargó.
El índice de paquetes es la lista de la compra. No hay ninguna razón para enviarla junto con lo comprado.
¿Puedes quedarte con la distribución y seguir siendo pequeño?
En gran parte, sí, y conviene saberlo si necesitas una distribución para otra cosa. El peso extra de arriba no es realmente de Ubuntu; es que apt-get update escribe su catálogo en una capa, y las capas son inmutables, así que borrarlo después no recupera nada.
Haz la instalación y la limpieza en una sola instrucción y nunca llega a quedar confirmado en una capa.
FROM ubuntu:26.04
RUN apt-get update \
&& apt-get install -y --no-install-recommends nginx \
&& rm -rf /var/lib/apt/lists/*
COPY site/ /var/www/html/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Eso mide 181 MB: 73 MB menos, misma distribución, mismo nginx. Además fija la base en lugar de seguir latest, omite los paquetes recomendados y escribe CMD en forma exec para que nginx reciba las señales directamente.
| Tamaño de imagen | Build en frío | Versión de nginx | |
|---|---|---|---|
| Distribución, como se suele escribir | 254 MB | 12 s | 1.28.3, la que tenga apt |
| Distribución, con limpieza | 181 MB | 9 s | 1.28.3, la que tenga apt |
| nginx Alpine oficial | 75,9 MB | 1 s | 1.27.5, fijada por tag |
De aquí salen los nueve segundos. Un archivo de tres líneas no tiene paso de instalación que ejecutar, así que desplegar es un pull y una copia; un archivo que instala paquetes repite ese trabajo en cada release.
¿Qué te da el plan Free?
Lo suficiente para poner algo delante de alguien, y no lo suficiente para dejarlo en marcha. El container recibe 0,25 vCPU, 256 MB de memoria y 100 GB de transferencia, que es de sobra para un sitio estático.
El límite que importa es la dirección: en el plan Free es temporal y caduca 60 minutos después del deploy. Eso lo convierte en una ventana para compartir más que en un alojamiento: vale para enseñárselo a un cliente, no para un sitio que la gente guarde en favoritos. Un subdominio permanente o tu propio dominio necesitan un plan de pago.
¿Qué deberías hacer ahora?
Pon tus propios archivos en site/, no cambies nada más y despliega. Al archivo del container le da igual si lleva una página o un sitio de documentación generado, así que las mismas tres líneas cubren casi cualquier cosa estática que construyas.
Quédate con la imagen oficial del servidor que necesites y fija su tag. Recurre a una distribución solo cuando algo lo requiera de verdad (un módulo poco habitual, un paso de build) y, cuando lo hagas, mantén la instalación y su limpieza en una sola instrucción.
