What I’m using#

After starting with my first containers and exploring a little bit more, I ended up with a nice setup and a few containers that I’m happy with.

All these containers are hosted on a Raspberry Pi 4 and consume almost no resource at all.

Traefik#

Originally, I decided to use nginx as my reverse proxy, since I found it really easy to use and configure. However there was a small hurdle: generating and automatically renewing Let’s Encrypt certificates. My original solution was to have a cron task to handle it, but I was having difficulties with certbot and the automatic renewal of the certificates.

Then I found out about traefik. After diving a bit into how it works, I tried it and found it really easy to configure, especially since it can handle Let’s Encrypt certificates renewals automatically. Also, it’s written in Go, a language that I really appreciated.

version: '3.3'
services:
  traefik:
    image: traefik:v2.2
    container_name: traefik
    command:
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --certificatesresolvers.myresolver.acme.dnschallenge=true
      - --certificatesresolvers.myresolver.acme.dnschallenge.provider=ovh
      - --certificatesresolvers.myresolver.acme.email=
      - --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json
    ports:
      - 80:80
      - 443:443
    networks:
      - servers
    depends_on:
      - sonarr
      - radarr
      - jackett
      - transmission
      - shaarli
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./letsencrypt:/letsencrypt
networks:
  servers:

Transmission with OpenVPN#

This container contains both the Transmission torrent client and an OpenVPN client. All internet traffic from/to this container go through the VPN so that everything is secured. The torrent client is then accessible from a web page.

The configuration is really simple and the documentation available is complete: https://haugene.github.io/docker-transmission-openvpn/. Torrent files are directly downloaded on my NAS, as you can see in the docker-compose below (volumes linked to /data/completed and /data/incomplete). However, I had to link the volume /data/transmission-home to a local directory on my Raspberry Pi because there are lots of read/write operations made in this directory and I wanted to spare these operations from my HDDs.

version: '3.3'
services:
  transmission:
    container_name: transmission
    image: haugene/transmission-openvpn:latest-armhf
    ports:
      - 9091:9091
    cap_add:
      - NET_ADMIN
    devices:
      - /dev/net/tun
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - ./config/transmission-home:/data/transmission-home
      - /path/to/nas/transmission/completed:/data/completed
      - /path/to/nas/transmission/incomplete:/data/incomplete
    env_file:
      - ./environment/transmission.env
    networks:
      - servers
    restart: unless-stopped
    labels:
      - traefik.enable=true
      - traefik.http.routers.transmission.rule=Host(`transmission.example.com`)
      - traefik.http.routers.transmission.entrypoints=websecure
      - traefik.http.routers.transmission.tls.certresolver=myresolver
      - traefik.http.services.transmission.loadbalancer.server.port=9091
networks:
  servers:

The configuration for transmission is read from environment variables passed to the container. The full list is available here.

Radarr, Sonarr and Jackett#

I also added the now famous containers Radarr and Sonarr, for movies and TV series. As they do not have access to every torrent tracker, I also added Jackett to help me with that. Since french ISPs can “block” websites in their DNS servers, I changed the default DNS server for these 3 containers.

The configuration for Radarr and Sonarr are almost the same since Radarr is a fork of Sonarr. Both of them integrate well with my Transmission client as they can directly add torrents to it.

version: '3.3'
services:
  radarr:
    image: linuxserver/radarr:latest
    container_name: radarr
    ports:
      - 7878:7878
    environment:
      - TZ=Europe/Paris
      - UMASK_SET=022
    volumes:
      - /path/to/nas/radarr/config:/config
      - /path/to/nas/video/movies:/movies
      - /path/to/nas/transmission:/downloads
      - ./config/resolv.conf:/etc/resolv.conf
    networks:
      - servers
    restart: unless-stopped
    labels:
      - traefik.enable=true
      - traefik.http.routers.radarr.rule=Host(`radarr.example.com`)
      - traefik.http.routers.radarr.entrypoints=websecure
      - traefik.http.routers.radarr.tls.certresolver=myresolver
      - traefik.http.services.radarr.loadbalancer.server.port=7878
  jackett:
    image: linuxserver/jackett:latest
    container_name: jackett
    ports:
      - 9117:9117
    environment:
      - TZ=Europe/Paris
    volumes:
      - /path/to/nas/jackett/config:/config
      - /path/to/nas/jackett/downloads:/downloads
      - ./config/resolv.conf:/etc/resolv.conf
    networks:
      - servers
    restart: unless-stopped
    labels:
      - traefik.enable=true
      - traefik.http.routers.jackett.rule=Host(`jackett.local`)
      - traefik.http.routers.jackett.entrypoints=web
networks:
  servers:

Docker-stats#

Docker-stats is a small server that I made to display the equivalent of the docker stats command inside a web page. All the code is open source and available in Github. You can see the result at https://stats.vmonot.dev/.

The docker-compose configuration is below. Since it uses websockets to refresh every second, I added a few labels for the integration with Traefik.

version: '3.3'
services:
  docker-stats:
    container_name: docker-stats
    image: agurato/docker-stats:latest
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - BASEURL=stats.vmonot.dev
    networks:
      - servers
    restart: unless-stopped
    labels:
      - traefik.enable=true
      - traefik.http.routers.stats_html.rule=Host(`stats.vmonot.dev`)
      - traefik.http.routers.stats_html.entrypoints=websecure
      - traefik.http.routers.stats_html.tls.certresolver=myresolver
      - traefik.http.routers.stats_ws.rule=Host(`stats.vmonot.dev`) && Path(`/ws`)
      - traefik.http.routers.stats_ws.entrypoints=websecure
      - traefik.http.routers.stats_ws.tls.certresolver=myresolver
      - traefik.http.services.stats.loadbalancer.server.port=11235
networks:
  servers: