Israel Casado

Como desplegar tus propias aplicaciones en una VPS usando Docker y Traefik

En esta guía se muestra el paso a paso sobre cómo instalar y configurar un servidor web en una VPS desde cero. Ahorrandote todos los costes de herramientas de hosting tradicionales y obteniendo un control total sobre tu entorno de despliegue.

Pasos para la instalación

  1. 1

    Elección de la VPS y configuración base

    Para montar toda la infraestructura necesitaba una base sólida, flexible y, sobre todo, con buena relación calidad‑precio. Después de comparar varias opciones, me decanté por Hetzner, un proveedor que destaca por ofrecer recursos potentes a un coste muy ajustado.

    La VPS que elegí tiene la siguiente configuración:
    • 2 vCPU
    • 4 GB de RAM
    • 40 GB de disco local

    Puede parecer una configuración modesta, pero es más que suficiente para el objetivo que tenía en mente: ejecutar varias aplicaciones web y APIs de forma simultánea utilizando contenedores Docker.

    ¿Por qué Hetzner?
    • Excelente relación calidad‑precio
    • Buen rendimiento de CPU y disco
    • Centros de datos en Europa con baja latencia
    • Panel de control sencillo y eficaz
    • Ideal para proyectos personales, side projects y entornos productivos pequeños/medianos
    ¿Por qué esta configuración es suficiente?

    Gracias al uso de Docker y Docker Compose, cada aplicación se ejecuta en su propio contenedor, lo que permite:

    • Aislar servicios
    • Optimizar el uso de recursos
    • Escalar o añadir nuevas aplicaciones fácilmente

    Además, con Traefik como reverse proxy, puedo exponer múltiples aplicaciones y APIs bajo diferentes dominios o subdominios sin necesidad de aumentar la complejidad del servidor.

  2. 2

    Accede a tu VPS mediante SSH.

    Antes de empezar a desplegar contenedores y servicios, es fundamental preparar correctamente el servidor. Una buena base evita problemas de seguridad, rendimiento y mantenimiento en el futuro.

    Sistema operativo

    En mi caso opté por Ubuntu Server LTS, una elección bastante común en servidores por varios motivos:

    • Estabilidad y soporte a largo plazo
    • Gran comunidad
    • Excelente compatibilidad con Docker y herramientas modernas

    Nada más crear la VPS, lo primero fue acceder por SSH como usuario root para realizar la configuración inicial.

    Actualización del sistema

    El primer paso siempre es asegurarse de que el sistema está completamente actualizado:

    apt update && apt upgrade -y

    Con esto nos aseguramos de tener los últimos parches de seguridad y versiones estables de los paquetes instalados.

    Creación de un usuario no root

    Por seguridad, es buena práctica no trabajar directamente con el usuario root. Así que creé un usuario nuevo y le asigné permisos de sudo:

    adduser deploy
    Configuración de acceso SSH

    Para mejorar la seguridad del servidor, realicé varios ajustes en el acceso SSH:

    • Acceso mediante clave pública/privada
    • Desactivar el login directo de root
    • Opcionalmente puedes cambiar el puerto SSH para mayor seguridad

    Después de cualquier cambio, es necesario reiniciar el servicio:

    systemctl restart ssh
    Firewall (UFW)

    Para limitar el acceso únicamente a los servicios necesarios, configuré el firewall con UFW (Uncomplicated Firewall).

    Primero permití los puertos básicos:

    ufw allow OpenSSH

    Y después activé el firewall:

    ufw enable

    Con esto el servidor solo acepta tráfico por SSH y por los puertos HTTP/HTTPS, que más adelante usará Traefik.

    Estado final del servidor
    • Actualizado y seguro
    • Sin acceso root por SSH
    • Protegido por firewall
    • Listo para instalar Docker y empezar a desplegar aplicaciones
  3. 3

    Instalacion Docker y Docker Compose.

    Con el servidor ya preparado y asegurado, el siguiente paso es instalar Docker y Docker Compose, que serán la base para ejecutar todas las aplicaciones y servicios de forma aislada y ordenada.

    Instalación de Docker

    Aunque Ubuntu incluye Docker en sus repositorios, preferí instalarlo desde el repositorio oficial de Docker para asegurarme de tener una versión más actualizada y estable.

    1. Instalar paquetes necesarios:
    apt install -y ca-certificates curl gnupg
    2. Añadir la clave GPG oficial de Docker:
    install -m 0755 -d /etc/apt/keyrings
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
    chmod a+r /etc/apt/keyrings/docker.gpg
    3. Configurar el repositorio:
    echo \
    	"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
    	$(. /etc/os-release && echo \"$VERSION_CODENAME\") stable" | \
    	tee /etc/apt/sources.list.d/docker.list > /dev/null
    4. Instalar Docker Engine:
    apt update
    apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
    5. Comprobar la instalación:
    docker --version
    docker compose version
    Ejecutar Docker sin sudo

    Para evitar tener que usar sudo en cada comando de Docker, añadí mi usuario al grupo docker:

    usermod -aG docker deploy

    Tras cerrar sesión y volver a entrar, ya es posible ejecutar Docker directamente con el usuario normal.

    Instalación de Docker Compose

    En este caso utilicé Docker Compose V2, que viene integrado como plugin oficial de Docker. Esto permite usar el comando:

    docker compose

    sin necesidad de instalar binarios adicionales ni depender de versiones antiguas.

    Verificación final

    Para validar que todo estaba correctamente instalado, lancé un contenedor de prueba:

    docker run hello-world

    Si todo va bien, Docker descarga la imagen y muestra un mensaje de confirmación.

    Base lista para Traefik y las aplicaciones
    • Ejecutar múltiples aplicaciones web
    • Levantar APIs independientes
    • Gestionar redes internas entre contenedores
    • Integrar un reverse proxy como Traefik
  4. 4

    Configuración de Traefik como reverse proxy

    Con Docker funcionando correctamente, el siguiente paso clave es introducir Traefik como reverse proxy. Traefik se convierte en el punto único de entrada a todas las aplicaciones web y APIs que se ejecutan en el servidor.

    Su gran ventaja frente a otras soluciones es que está pensado para entornos con contenedores, detectando automáticamente los servicios a través de Docker.

    ¿Por qué Traefik?

    Elegí Traefik principalmente por:

    • Integración nativa con Docker
    • Configuración dinámica basada en labels
    • Soporte automático de HTTPS con Let’s Encrypt
    • Gestión sencilla de múltiples dominios y subdominios
    • Dashboard para monitorizar el estado del proxy
    Red Docker compartida

    Antes de levantar Traefik, creé una red Docker externa que será compartida por Traefik y todas las aplicaciones que quiera exponer públicamente:

    docker network create traefik

    Esta red permite que Traefik enrute tráfico hacia contenedores definidos en distintos docker-compose.

    Docker Compose de Traefik

    Traefik se ejecuta como un contenedor más, normalmente en su propio stack. Un docker-compose.yml simplificado sería:

    services:
      traefik:
        image: traefik:v3.0
        container_name: traefik
        restart: unless-stopped
        command:
          - "--providers.docker=true"
          - "--providers.docker.exposedbydefault=false"
          - "--entrypoints.web.address=:80"
          - "--entrypoints.websecure.address=:443"
          - "--api.dashboard=true"
        ports:
          - "80:80"
          - "443:443"
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock:ro
        networks:
          - traefik
    
    networks:
      traefik:
        external: true

    Con esta configuración básica, Traefik ya es capaz de detectar contenedores Docker y enrutar tráfico HTTP y HTTPS.

    Providers: Docker como fuente de verdad

    Traefik utiliza providers para descubrir servicios. En este caso, el provider principal es Docker:

    • Traefik escucha los eventos de Docker
    • Detecta contenedores con labels específicas
    • Crea rutas dinámicamente sin reinicios

    Esto elimina la necesidad de editar archivos de configuración cada vez que se añade una nueva aplicación.

    Preparación para HTTPS automático

    Traefik permite gestionar certificados SSL automáticamente usando Let’s Encrypt. Para ello, solo es necesario:

    • Definir un resolver ACME
    • Configurar un email de contacto
    • Persistir los certificados en un volumen

    Esto permite que, al levantar una nueva aplicación con su dominio, Traefik genere y renueve automáticamente los certificados sin intervención manual.

  5. 5

    Exponer una aplicación real con Traefik

    Una vez Traefik está funcionando como reverse proxy, el siguiente paso es ponerlo a trabajar de verdad: exponer una aplicación web real utilizando Docker Compose y las labels de Traefik.

    En este punto es donde todo empieza a encajar y se aprecia la potencia de esta arquitectura.

    Estructura básica del proyecto

    Cada aplicación vive en su propio directorio y tiene su propio docker-compose.yml. Por ejemplo:

    /var/www/ └── mi-app-web/ └── docker-compose.yml

    Esto permite desplegar, actualizar o eliminar aplicaciones de forma totalmente independiente.

    Docker Compose de una aplicación web

    Supongamos una aplicación web sencilla (por ejemplo una API o un frontend). El docker-compose.yml podría ser algo como esto:

    services:
      app:
        image: nginx:alpine
        container_name: mi_app_web
        restart: unless-stopped
        labels:
          - "traefik.enable=true"
          - "traefik.http.routers.miapp.rule=Host(`miapp.midominio.com`)"
          - "traefik.http.routers.miapp.entrypoints=websecure"
          - "traefik.http.routers.miapp.tls.certresolver=letsencrypt"
        networks:
          - traefik
    
    networks:
      traefik:
        external: true

    Con solo estas labels, Traefik:

    • Detecta automáticamente el contenedor
    • Asocia el dominio indicado
    • Expone la aplicación por HTTPS
    • Genera y renueva el certificado SSL
    Labels: la clave de todo

    Las labels son el corazón de la configuración con Traefik. En ellas se define:

    • Qué contenedores se exponen (traefik.enable=true)
    • Qué dominio o regla de acceso se utiliza
    • Por qué entrypoint entra el tráfico
    • Qué resolver de certificados usar

    Todo esto se hace sin tocar Traefik, simplemente declarando comportamiento desde la propia aplicación.

    Despliegue de la aplicación

    Levantar la aplicación es tan simple como ejecutar:

    docker compose up -d

    En cuestión de segundos:

    • Traefik detecta el nuevo servicio
    • Se crea el router dinámicamente
    • Let’s Encrypt emite el certificado
    • La aplicación queda accesible públicamente
    Escalabilidad y mantenimiento

    Este enfoque permite:

    • Añadir nuevas aplicaciones sin modificar las existentes
    • Usar distintos dominios y subdominios
    • Reiniciar o actualizar servicios de forma aislada
    • Mantener una arquitectura limpia y ordenada

    Cada nuevo proyecto sigue exactamente el mismo patrón, lo que simplifica enormemente el mantenimiento a largo plazo.

  6. 6

    Buenas prácticas y errores comunes

    Después de montar la infraestructura y desplegar varias aplicaciones, hay una serie de buenas prácticas que marcan la diferencia entre un sistema que simplemente funciona y uno que es mantenible, seguro y escalable en el tiempo.

    Buenas prácticas
    Separar responsabilidades
    • Traefik debe vivir en su propio stack
    • Cada aplicación debe tener su propio docker-compose.yml
    • Evitar mezclar bases de datos, proxies y aplicaciones en el mismo stack

    Esto facilita actualizaciones, reinicios y depuración.

    Usar redes Docker externas

    Centralizar la exposición pública a través de una red externa (como traefik) permite:

    • Mantener aisladas las redes internas
    • Reducir la superficie de ataque
    • Controlar exactamente qué servicios son accesibles desde fuera
    No exponer contenedores innecesarios

    Por defecto, Traefik no expone ningún contenedor (exposedbydefault=false). Solo aquellos servicios que realmente necesitan acceso público deben llevar labels de Traefik.

    Versionar los docker-compose

    Guardar los docker-compose.yml en un repositorio (Git) permite:

    • Reproducir el entorno fácilmente
    • Tener histórico de cambios
    • Desplegar el servidor desde cero en minutos
    Persistencia de datos
    • Bases de datos siempre con volúmenes
    • Certificados de Traefik persistidos

    Evitar perder información al recrear contenedores.

    Errores comunes
    Ejecutar todo como root

    Aunque Docker lo permita, no es buena idea trabajar siempre como root. Usar un usuario dedicado reduce riesgos y errores accidentales.

    Exponer el dashboard sin protección

    El dashboard de Traefik es muy útil, pero no debe quedar expuesto públicamente sin autenticación o restricciones de red.

    No controlar logs

    Sin una mínima estrategia de logs:

    • Los errores pasan desapercibidos
    • Es difícil depurar problemas
    • Se pierde visibilidad del sistema

    Al menos conviene revisar periódicamente los logs de Traefik y de las aplicaciones.

    No planificar el crecimiento

    Aunque la VPS sea suficiente al inicio, es importante:

    • Vigilar consumo de CPU y RAM
    • Saber cuándo escalar verticalmente
    • Optimizar imágenes y servicios
  7. 7

    Uso real en producción

    Toda esta infraestructura no es solo un experimento o un laboratorio. La propia web que estás leyendo ahora mismo está desplegada exactamente de esta forma:

    • Astro en el frontend
    • .NET en el backend
    • Contenedores Docker independientes
    • Traefik gestionando dominios y certificados HTTPS

    Cada parte vive en su propio stack, pero todas conviven en la misma VPS de forma ordenada, segura y eficiente.

    Ventajas clave del enfoque

    Después de usar esta arquitectura de forma continuada, las principales ventajas son claras:

    • Despliegues rápidos y reproducibles
    • Aislamiento total entre aplicaciones
    • Configuración mínima para nuevos proyectos
    • HTTPS automático sin complicaciones
    • Escalabilidad clara cuando sea necesaria
    Conclusión final

    Montar un servidor web moderno hoy en día no requiere infraestructuras complejas ni grandes inversiones. Con una VPS bien elegida, Docker, Traefik y una buena organización, es posible construir una plataforma sólida, flexible y preparada para crecer.

    Esta arquitectura me permite centrarme en lo importante: desarrollar aplicaciones, sabiendo que la base sobre la que corren es estable, mantenible y fácil de evolucionar.

    Si estás pensando en montar tu propio servidor para alojar varias aplicaciones y APIs, este enfoque es una opción más que recomendable.

Final de la guía

Si te quedan dudas o quieres compartir tu experiencia, no dudes en dejar un comentario o contactarme directamente. ¡Feliz despliegue!