Traefik, mi nuevo mejor amigo

Saca provecho de tu servidor enrutando las peticiones de distintos servicios a través de un proxy inverso

Traefik, mi nuevo mejor amigo

Hace tiempo que contraté un VPS baratito y sencillo a más no poder, con la intención de tener una VPN a la que acceder desde una red pública cuando no me quedara otra opción, con el fin de minimizar riesgos (ya sabéis, mi "paranoia" de la seguridad). Todo iba bien, hasta que mi proveedor decidió que el plan que tenía contratado estaba "obsoleto" y debía migrar a otro superior... Le estaba dando uso a mi VPN, por lo que decidí hacerlo y, entonces, me encontré con que disponía de una máquina que podía hacer más por prácticamente lo mismo. Pero... ¿cómo podía sacarle partido y a la vez aprender algo nuevo?

Tras darle muchas vueltas al tema, llegué a la conclusión de que sería genial tener alojado en el VPS el blog, además de poder alojar copias de seguridad, trasteos varios, etc. Estaba empezando a meterme en el mundo de los contenedores y Docker, y prácticamente veía todas mis posibilidades ahí agrupadas.

Ahora bien, para ello tendría que exponer un sinfín de puertos al exterior y aunque tenía mi fiel fail2ban y mi firewall protegiendo el sistema, no me parecía lo más acertado... Y entonces descubrí Traefik.

Traefik es una especie de enrutador y proxy inverso que se encarga de redirigir las peticiones recibidas por un puerto a los servicios que tiene registrados, donde cada uno está escuchando en su respectivo puerto. Esto cobra más sentido si encima dichos servicios corren en contenedores Docker, los cuales tienen cada uno su IP y pueden compartir el mismo "puerto" (por decirlo de alguna manera). De esta forma, podía exponer cualquier servicio que necesitara abriendo únicamente un puerto al exterior en mi VPS. Pero, ¿cómo hacer eso?

Primer paso: Instalar traefik

Para todo esto, doy por sentado que tenemos Docker en nuestro sistema ya instalado y configurado para poder ejecutar contenedores, así como docker compose para lanzar los mismos de una manera más sencilla. Así pues, el primer paso para correr Traefik fue crear mi fichero docker-compose.yml con el siguiente contenido:

version: '3.2'

services:
  traefik:
    # The official v2 Traefik docker image
    image: traefik:latest # v2.1
    container_name: "traefik"
    restart: always
    # Enables the web UI and tells Traefik to listen to docker
    command:
      #- --log.level=DEBUG
      - --api.dashboard=true
      - --api.insecure=true
      - --providers.docker=true
      - "--entrypoints.https.address=:443"
      - "--entrypoints.lan.address=:888"
      - "--certificatesResolvers.leresolver.acme.email=demo@parravidales.es"
      - "--certificatesResolvers.leresolver.acme.storage=acme.json"
      - "--certificatesResolvers.leresolver.acme.tlschallenge=true"
    ports:
      # The HTTPS port
      - "443:443"
      - "8008:888"
      - "8080:8080"
    volumes:
      # So that Traefik can listen to the Docker events
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./acme.json:/acme.json
    networks:
      - traefiknet

networks:
  default:
  traefiknet:
    external: 
      name: traefiknet
docker-compose.yml de Traefik

Y diréis "vale, muy bien, ¿pero qué es todo eso?...". Y tendréis razón 😂. Pero paciencia... que lo vamos a desgranar poco a poco:

El campo image nos define la imagen de Docker que vamos a usar, en este caso la de Traefik 2.1, que a fecha de este artículo es la última.

Mediante container_name le damos un nombre al contenedor, y con restart: always le indicamos que queremos que se reinicie siempre en caso de problema.

En la parte de command tenemos listadas varias órdenes, cada una de las cuales hace lo siguiente:

  • log.level=DEBUG: Está comentada, pero si la descomentamos podremos ver el log de Traefik en ese nivel de traza (útil cuando nos dé problemas y no sepamos por qué).
  • api.dashboard=true: Con esto activamos el dashboard de Traefik, donde veremos todo lo que registra y el estado en el que está.
  • api.insecure=true: Al menos por ahora, nuestro dashboard no va a tener autenticación alguna, por lo que lo marcamos como tal.
  • providers.docker=true: Le indicamos el provider que va a usar, en nuestro caso, Docker.
  • entrypoints.https.address=:443: Definimos un punto de entrada, que se llamará https y que estará escuchando en el puerto 443.
  • entrypoints.lan.address=:888: Definimos otro punto de entrada, llamado lan y que escuchará en el puerto 888. Ya veremos para qué usamos 2 puntos de entrada.
  • certificatesResolver.leresolver.acme.email: Definimos un "resolvedor" de certificados para poder exponer nuestros servicios bajo HTTPS y que nos los firmará la autoridad Let's Encrypt. En dicho "resolvedor" especificamos nuestro correo electrónico (ha de ser un correo válido).
  • certificatesResolver.leresolver.acme.storage=acme.json: Le indicamos a Traefik que nos almacene la información del certificado en el fichero acme.json.
  • certificatesResolver.leresolver.acme.tlschallenge=true: Le indicamos a Traefik que el certificado se obtendrá a través de tlschallenge, esto es, hará una llamada a Let's Encrypt y éste comprobará nuestro dominio a través del puerto 443 (con lo que dicho puerto deberá estar abierto a Internet y accesible).

Tras exponer los comandos, definimos los puertos que queremos exponer a nuestro sistema, en nuestro caso los puertos 443 para atender las peticiones HTTPS y el 8008 para las HTTP. La idea es que este último puerto no esté accesible desde Internet, pues aunque podría redirigir las conexiones HTTP a HTTPS, prefiero caparlo directamente, y usar ese puerto para las que no precisen de HTTPS dentro de mi red local. El puerto 8080 es en el que Traefik expone su dashboard, por lo que de momento lo exponemos para poder acceder a él.

A continuación, en volumes cargamos el localtime y el docker.sock para que Traefik tenga acceso tanto a la hora local de sistema como a los cambios que se produzcan en Docker, y así detectar cuándo nuevos contenedores se crean o destruyen y ver si tiene que hacer algo al respecto (o no).

Por último, definimos una red que llamaremos, para este caso, traefiknet y le indicamos al servicio que la use, así como en networks la declaramos y la marcamos como externa.

Para crear dicha red, bastará con ejecutar el comando:

docker network create traefiknet

A continuación, en el mismo directorio donde tenemos nuestro fichero docker-compose.yml crearemos un fichero vacío acme.json que será donde se almacenen los certificados. Dicho fichero ha de pertenecer al usuario root y ha de ser accesible sólo por él, por lo que ejecutamos lo siguiente:

touch acme.json
sudo chown root:root acme.json
sudo chmod 600 acme.json

¡Con esto, ya tendremos nuestro Traefik levantado y listo para registrar lo que sea! Bastará con ejecutar la orden docker-compose up -d y podremos acceder a http://localhost:8080 para ver nuestro dashboard listo para registrar todo.

En posteriores entradas iré detallando cómo hacer que Traefik nos enrute las peticiones a otros servicios y contenedores 😊.