My First Docker Deployment

About two weeks ago I had to get a crash-course in Docker technology at work. I had no idea what I was doing (following a YouTube video and an accompanying PDF. Eventually I got it to work but no idea what I was doing. So I wanted to change that.

NOTE: I’m not gonna build/create new docker containers yet. Just learning on how they are used, configured, and interact. This is also no tutorial on how to install Docker itself. There are more than enough websites for that.

The problem with learning new things is that they have to be practically and/or useful (for me). After some thought I ended up with a combination of Transmission and OpenVPN.

This Docker image gives you a Torrent client with a webgui, and all (torrent) traffic is directed through the OpenVPN connection. Making it safe to download Linux distro’s. As a bonus, it has a generic web proxy function with you can use to handle your web traffic. The latter is especially useful in combination with e.g. the browser extension/plugin FoxyProxy.

Deploying the docker container is pretty straight-forward (you do need a supported VPN provider). It basically works out of the box, but molding it to my wishes involved a bit more digging around. There are some things I wanted to add, or change;

  • Customer paths for the download locations (default = /data).

  • Use a watchfolder for transmission where the .torrent files can be picked-up.

  • Use an additional reverse proxy for the Transmission webGui so that all my internal services are accessible from 1 IP address without having to remember al their TCP ports.
    More info on that can be found here.

  • Since the Docker container runs under a/the root account, I needed to change that behavior since I don’t want to do everything with root permissions (involving experimentation with umask and UID/GID’s).

This resulted in the following docker-compose file (docker-compose.yaml):

UPDATE: I’ve added the Portainer image to the compose file. This gives you a web gui to manage the containers. The gui is accessible on port 9000 on the same docker host.

version: '2'
services:
    transmission-openvpn:
        restart: unless-stopped
        volumes:
            - '/mnt/data:/data'
            - '/mnt/stack/Watchfolder:/home/Watchfolder'
            - '/etc/localtime:/etc/localtime:ro'
        environment:
            - TZ=Europe/Amsterdam
            - OPENVPN_OPTS=--inactive 3600 --ping 10 --ping-exit 60
            - CREATE_TUN_DEVICE=true
            - OPENVPN_PROVIDER=NORDVPN 
            - OPENVPN_USERNAME=<VPN-USERNAME>
            - OPENVPN_PASSWORD=<VPN-PASSWORD>
            - NORDVPN_COUNTRY=CH
            - HEALTH_CHECK_HOST=google.com
            - TRANSMISSION_INCOMPLETE_DIR_ENABLED=true
            - TRANSMISSION_INCOMPLETE_DIR=/data/downloads/incomplete
            - TRANSMISSION_DOWNLOAD_DIR_ENABLED=true
            - TRANSMISSION_DOWNLOAD_DIR=/data/downloads/complete
            - TRANSMISSION_WATCH_DIR_ENABLED=true
            - TRANSMISSION_WATCH_DIR=/home/Watchfolder
            - TRANSMISSION_TRASH_ORIGINAL_TORRENT_FILES=true
#            - TRANSMISSION_UMASK=222
            - TRANSMISSION_SPEED_LIMIT_DOWN=5000
            - TRANSMISSION_SPEED_LIMIT_DOWN_ENABLED=true
            - TRANSMISSION_SPEED_LIMIT_UP=1000
            - TRANSMISSION_SPEED_LIMIT_UP_ENABLED=true
            - WEBPROXY_ENABLED=true
            - WEBPROXY_PORT=8080
            - LOCAL_NETWORK=192.168.0.0/16
            - PUID=1000
            - PGID=1000
        cap_add:
            - NET_ADMIN
        logging:
            driver: json-file
            options:
                max-size: 10m
        ports:
                - '9091:9091'
                - '8888:8080'
        image: haugene/transmission-openvpn
        container_name: openvpn
    portainer:
        image: portainer/portainer-ce
        container_name: portainer
        restart: always
        ports:
          - "9000:9000"
        command: -H unix:///var/run/docker.sock
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock
          - portainer_data:/data

volumes:
  portainer_data:

The thing that took the most amount of time to figure out was the PUID/PGID part of the config. This basically are the user id and group id which are used to run the container and also when creating directories and files on the physical filesystem of the host. In my case, the PUID, and PGID are the id’s corresponding to my username on the Linux host.

The important part is that all the path references in the environment part of the yaml file are local to the container. These are mapped/related to the physical locations in the volumes part of the config file.

Deploying/creating the Docker container is done through the following command (I use docker-compose instead of docker run):

docker-compose up -d

Configuring a webproxy in my browser pointing to the Linux host IP with port 8888 allows me to surf the web through the OpenVPN provider. Pointing my browser to the Linux host IP address with port 9091 gives the Transmission webGui (http://IP-ADDRESS>:9091). But as I mentioned earlier, I want to access this through my internal reverse proxy (NGINX).

To do this I have to create an additional location within the NGINX config and enable that. This resulted in the following NGINX location config file:

location /transmission/ {
      proxy_pass http://192.168.##.1:9091;

      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_set_header X-NginX-Proxy true;
      proxy_http_version 1.1;
      proxy_set_header Connection "";
      proxy_pass_header X-Transmission-Session-Id;
      add_header   Front-End-Https   on;

      satisfy any;
      allow 192.168.0.0/16;
      allow 172.16.16.0/24;
      allow 10.200.200.200/32;
      deny all;
      auth_basic "Restricted Content";
      auth_basic_user_file /etc/nginx/auth.d/auth.pwd;
}

Note that the bottom part are some directoves to limit the IP’s that can access the page. These are related to your internal IP networks.

Now I can access the tranmission webGui over https through my NGINX reverse proxy via https://internalhost/transmission

A small note on the use of FoxyProxy; This extension allows you to selectively use the proxy based on (parts of ) URL. You can configure patterns using wildcards and regular expressions to direct traffic directly or through a proxy.

So if e.g. your OpenVPN terminates in the the US, you can create a pattern that certain entertainment sites are being accessed through your proxy, while other traffic uses your regular ISP. This is especially useful if you have a capped monthly VPN account.

Posted on July 29, 2020 and filed under Linux, Programming, Security, Software, Tips'n Tricks.