Instalación y configuración de un servidor VSCode y expuesto con Traefik en docker-compose en una Raspberry Pi

En esta entrada se instalará y se configurará Code Server en una Raspberry Pi. Se utilizará la versión dockerizada linuxserver/code-server, se instalará mediante docker-compose y el balanceo de carga se realizará con traefik.

¿Qué es Code Server?

Code-server es VS Code corriendo en un servidor remoto, accesible a través del navegador.

Requisitos

Instalar:

Redomendaciones

Actualizar el sistema

Lo primero siempre es actualizar el sistema con:

sudo apt update -y && sudp apt upgrade -y

Configurar cortafuegos ufw

Para instalar el cortafuegos ufw ejecutar:

sudo apt-get install ufw

Permitimos las conexiones por el puerto 80 (HTTP), 443(HTTPS) y 2251(SSH configurado).

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 4443/tcp
sudo ufw allow 2251/tcp

Para activarlo:

sudo ufw enable

Para ver las reglas por defecto:

sudo ufw show raw

También se puede ver con un formato más legible:

sudo ufw status verbose

Apagar la Raspberry Pi de forma correcta

Para apagar la Raspberry Pi evitando que se corrompa la tarjeta SD se ejecuta el siguiente comando:

sudo shutdown -h now

Esperar a que la luz verde deje de parpadear para desenchufar el cable de alimentación.

Obtener dominio (Opcional)

Se requiere un dominio en caso de querer acceder desde el exterior de la red local, en otras palabras, desde Internet. Para ello existen varias páginas donde obtener dominios gratuitos o por menos de 1€ al año. Lo más importante es que el resgistrador de nombres de dominio tenga protección de Whois (WhoisGuard) para prevenir ataques de spam o de suplantación de indentidad a través de los datos personales que tienen que ser públicos al registrar un dominio en el ICANN.

En caso de usar un dominio de freenom, es necesario cambiar el DNS a un de Cloudflare siguiendo los pasos de este tutorial.

Desplegar VSCode Server con Docker

Para levantar el contenedor docker de code-server, simplemente se necesitan los siguientes pasos:

  • Añadir la variable de entorno con el nombre del dominio:
export $DOMINIO=dominioejemplo.org
  • Levantar el contenedor desde el repositorio de Docker Hub:
docker run -d \
  --name=code-server \
  -e PUID=1000 \
  -e PGID=1000 \
  -e TZ=Europe/London \
  -e PASSWORD=password `#optional` \
  -e HASHED_PASSWORD= `#optional` \
  -e SUDO_PASSWORD=password `#optional` \
  -e SUDO_PASSWORD_HASH= `#optional` \
  -e PROXY_DOMAIN=code-server.my.domain `#optional` \
  -e DEFAULT_WORKSPACE=/config/workspace `#optional` \
  -p 8443:8443 \
  -v /path/to/appdata/config:/config \
  --restart unless-stopped \
  lscr.io/linuxserver/code-server:latest

Escribir en el navegador la dirección http://<IP-Raspberry-Pi>:8443 y escribir la contraseña elegida.

Configuración en producción de code-server en una Raspberry Pi

Nota importante: no funciona sin un dominio.

Creamos una carpeta raiz que contendrá una carpeta con el nombre de cada autoalojemos, por ejemplo la llamaremos servicios-autoalojados:

mkdir servicios-autoalojados

Variables de entorno de Traefik

Una vez creado nos dirigidos al directorio y creamos otra carpeta llamada traefik. Además, añadimos un nuevo archivo .env en la carpeta traefik con el siguiente contenido. Es la variable de entorno necesaria para traefik. También se pueden incluir en cada carpeta raiz y tenerlas centralizadas en dicha carpeta, el inconveniene es que todos los contenedores tendrían acceso a todas las variables de entorno y eso podría dar lugar a problemas de seguridad. Por esa razón, recomendamos tener un archivo de variables de entorno separado por cada servicio que despleguemos.Para que funcione correctamente, es importante borrar el comentario que se ha añadido en el siguiente ejemplo.

DOMAIN=dominioejemplo.org # Cambiar por un dominio propio

Docker-compose de producción de Traefik

Después, creamos un archivo docker-compose.yml con la siguiente configuración:

version: "3.3"

services:

  traefik:
    image: "traefik:v2.6"
    container_name: "traefik"
    command:
      - "--log.level=DEBUG"
      # - "--api.insecure=false"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.web.http.redirections.entryPoint.to=websecure"
      - "--entrypoints.web.http.redirections.entryPoint.scheme=https"
      - "--entrypoints.web.http.redirections.entrypoint.permanent=true"
      - "--certificatesresolvers.myresolver.acme.tlschallenge=true"
      - "--certificatesresolvers.myresolver.acme.caserver=https://acme-v02.api.letsencrypt.org/directory"
      - "--certificatesresolvers.myresolver.acme.email=admin@${DOMAIN}" # Email de ejemplo, cambiarlo para recibir correos de la renovación de los certificados
      - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
    ports:
      - "443:443"
      - "8080:8080"
    volumes:
      - "./letsencrypt:/letsencrypt"
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
    env_file:
      - .env
    networks:
      - traefik-external-network
      - vscode-network
    restart: unless-stopped 

networks:
  traefik-external-network:
    driver: bridge
    external: true
  vscode-network:
    driver: bridge

En el hemos creado una red de docker llamada traefik-external-network donde se expodrán los servicios al exterior y es obligatorio que sea de tipo external, mientras que code-server-network servirá para conectar la base de datos postgres con netxcloud.

Desplegamos el docker-compose con:

docker-compose up --build --force-recreate

Variables de entorno de Code Server

A continuación, creamos una carpeta llamada code-server. Una vez creada nos dirigidos al directorio y añadimos un nuevo archivo .env en la carpeta code-server con el siguiente contenido. Son las variables de entorno necesarias para el servidor de código.

Primero, creamos un archivo .env donde guardaremos las variables de entorno. Es importante borrar los comentarios que se han añadido en el siguiente ejemplo para que funcione correctamente.

DOMAIN=dominioejemplo.org
SUBDOMAIN_CODE_SERVER=code-server
PUID=1000
PGID=1000
TZ=Europe/London
PASSWORD= #optional
HASHED_PASSWORD= #optional
SUDO_PASSWORD= #optional
SUDO_PASSWORD_HASH= #optional
PROXY_DOMAIN=code-server.dominioejemplo.org #optional
DEFAULT_WORKSPACE=/config/workspace #optional

En segundo lugar, creamos un archivo docker-compose.yml con el siguiente contenido:

version: "3.3"

services:
  # Visual Studio code server
  code-server:
    image: lscr.io/linuxserver/code-server:latest
    container_name: code-server
    env_file:
      - .env
    volumes:
      - ./code-server-config:/home/coder/.config
      - ./code-server-data:/home/coder/projects
    # command: code-server --auth password --disable-telemetry /home/coder/project
    ports:
      - 8443:8443
    networks:
      - traefik-external-network
    restart: unless-stopped
    labels:
      - "traefik.enable=true"
      # Code-server URL
      - "traefik.http.routers.code-server.rule=Host(`${SUBDOMAIN_CODE_SERVER}.${DOMAIN}`)"
      - "traefik.http.routers.code-server.service=code-server"
      - "traefik.http.routers.code-server.entrypoints=websecure"
      - "traefik.http.services.code-server.loadbalancer.server.port=8443"
      - "traefik.http.routers.code-server.tls=true"
      - "traefik.http.routers.code-server.tls.certresolver=myresolver"
      - "traefik.http.services.code-server.loadbalancer.passhostheader=true"

volumes:
  code-server-config:
  code-server-data:

networks:
  traefik-external-network:
    driver: bridge
    external: true

Desplegamos el docker-compose con:

docker-compose up --build --force-recreate

El certificado de Let’s Encrypt puede tardar unos minutos en obtenerse, por lo tanto, espere y si obtiene algún warning en los logs de Traefik, no es preocupante. Una forma para probar si se ha generado correctamente es leer el archivo acme.json de la carpeta letsencrypt creada en el directorio code-server. También se pueden recrear los servicios hasta que funcione todo correctamente.

Por último, ya podemos buscar en el navegador nuestro dominio https://code-server.dominiodeejemplo.org