Montando tu propio servidor: La tríada perfecta

Si alguna vez has querido tomar el control de tus propios servicios en la nube (self-hosting), tener una base sólida es fundamental. Hoy te traigo una guía completa para configurar un Ubuntu Server 24.04 LTS desde cero con Docker, Portainer y Traefik.

Docker - Portainer - Traefik

Esta configuración te permitirá desplegar aplicaciones en segundos, gestionarlas con una interfaz gráfica amigable (Portainer) y exponerlas a Internet de forma segura con certificados SSL automáticos gracias al router dinámico (Traefik).

Además, definiremos una estructura de directorios optimizada para mantener el orden, separando la configuración de los datos persistentes.


1. Instalación de Docker y Docker Compose

Ubuntu 24.04 facilita enormemente la vida, pero siempre es mejor usar el repositorio oficial de Docker para tener las últimas versiones.

Agrega la clave GPG y el repositorio oficial:

# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Instala Docker y el plugin de Compose:

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

(Opcional pero recomendado) Añade tu usuario al grupo docker para no usar sudo constantemente:

sudo usermod -aG docker $USER

Tendrás que cerrar sesión y volver a entrar para que se apliquen los cambios.


2. Nuestra Estructura de Trabajo: /opt/stacks

Para evitar el caos, crearemos una estructura de carpetas unificada. Todos nuestros docker-compose.yml vivirán en /opt/stacks, y cada servicio tendrá su propia carpeta. Además, mapearemos los volúmenes de datos dentro de esas mismas carpetas (por ejemplo en una subcarpeta llamada data).

Creamos el directorio base y la red externa que usará Traefik:

sudo mkdir -p /opt/stacks
sudo chown $USER:$USER /opt/stacks
docker network create web

(Asumimos en adelante que ya tienes permisos en /opt/stacks)


3. Desplegando Portainer

Portainer es nuestra interfaz gráfica. Nos facilita la gestión de contenedores, volúmenes y redes. Lo desplegaremos usando un compose básico, sin enrutarlo aún por Traefik (para usarlo como salvavidas si Traefik falla).

mkdir -p /opt/stacks/portainer/data
cd /opt/stacks/portainer
nano docker-compose.yml

Añade este contenido:

services:
  portainer:
    image: portainer/portainer-ce:latest
    container_name: portainer
    restart: always
    security_opt:
      - no-new-privileges:true
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./data:/data
    ports:
      - 9000:9000
      - 8000:8000

Levanta el servicio: docker compose up -d (Accede a http://IP_DE_TU_SERVER:9000 para configurar la clave inicial).


4. El Router Maestro: Desplegando Traefik

Traefik es la joya de la corona. Actuará como router o proxy inverso. Leerá las etiquetas ("labels") que pongamos en nuestros otros contenedores y creará las reglas de enrutamiento y certificados LetsEncrypt mágicamente.

mkdir -p /opt/stacks/traefik/data
cd /opt/stacks/traefik
nano docker-compose.yml

Añade este docker-compose.yml. OJO: Cambia tucorreo@dominio.com:

services:
  traefik:
    image: traefik:v3.0
    container_name: traefik
    restart: always
    security_opt:
      - no-new-privileges:true
    ports:
      - 80:80
      - 443:443
    environment:
      - CF_API_EMAIL=tucorreo@dominio.com # Si luego usas dns challenge
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./data/traefik.yml:/traefik.yml:ro
      - ./data/acme.json:/acme.json
    networks:
      - web

networks:
  web:
    external: true

Antes de levantarlo, necesitamos crear los archivos que mapeamos:

touch data/acme.json
chmod 600 data/acme.json
nano data/traefik.yml

Configuración básica de traefik.yml para resolución por HTTP (Let's encrypt):

api:
  dashboard: true
  insecure: true

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
  websecure:
    address: ":443"

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
    network: web

certificatesResolvers:
  letsencrypt:
    acme:
      email: tucorreo@dominio.com
      storage: acme.json
      httpChallenge:
        entryPoint: web

Levanta Traefik: docker compose up -d


5. El Flujo de Trabajo Consolidado

A partir de ahora, cuando quieras levantar un nuevo servicio (por ejemplo, whoami para probar), el flujo es siempre este:

  1. Creas el directorio en /opt/stacks: mkdir -p /opt/stacks/whoami
  2. Creas el docker-compose.yml en su directorio, mapeando sus datos en ./data, uniéndolo a la red web y añadiendo los labels para Traefik. Ejemplo:
services:
  whoami:
    image: traefik/whoami
    container_name: whoami
    restart: always
    networks:
      - web
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`whoami.tudominio.com`)"
      - "traefik.http.routers.whoami.entrypoints=websecure"
      - "traefik.http.routers.whoami.tls.certresolver=letsencrypt"

networks:
  web:
    external: true

¡Y eso es todo! Levantando este contenedor, Traefik detectará las etiquetas, pedirá el certificado a Let's Encrypt, y enrutará el tráfico del subdominio hacia el contenedor. Todo de forma transparente y manteniendo tus datos ordenador en /opt/stacks.

Entrada Anterior Siguiente Entrada