May 31, 2018

Docker-based HTPC set-up

This is a quick run through for setting up a HTPC (Home Theatre PC). It requires a docker installation, which is available for most modern Operating systems (official installation instructions). These instructions were completed with linux so it may not work 100% "as-is" for other operating systems. It will use the following components:


One thing to note is that I use a separate docker network to isolate all my services from the default bridge network. You can create your own using: docker network create traefik



No-IP for Dynamic DNS

If you have a simple home router with a dynamic IP but still want to access your content from the internet, you need to set-up a Dynamic DNS. There are paid services out there, but No-IP provides you with a free hostname (it does use ads, and hostnames expire every month). You will need to create an account with your VPN provider and then run the following:


docker run --name=noip -d \
  -v /etc/localtime:/etc/localtime:ro\
  -v [PATH_TO_CONFIG]:/config\
  coppit/no-ip


Note that [PATH_TO_CONFIG] must exist on your local hard-drive.

On your initial run, the container will create a file in the configuration directory. Open up that file, enter in your username, password and domain names. Then re-run your container and your dynamic DNS will be set-up!

NOTE: The rest of this guide will assume you have ports 443 and 80 forwarded on your modem to your Media PC. You may also need to poke a hole in any firewall you have for these ports. Without this completed then Traefik will not work.


Traefik for Reverse Proxy

Traefik will be used to take all traffic from your No-IP hostname and direct them to the desired services. Before you start:
  1. Create a folder to store your configuration data
  2. Create two empty files: traefik.toml and acme.json
  3. Make sure that acme.json has only 600 privileges (user read/write only, no execute, no permissions for group or other). I am unsure how to do this for Windows.
  4. Use htpassword or similar tool to encode a basic password auth string. In Linux, you would download it using sudo apt-get install apache2-utils and then run htpasswd -nb admin secure_password
  5. Put the following into traefik.toml (fill in your own variables for {!!EMAIL!!}, {!!DOMAIN!!}, and {!!HTPASSWORD_OUTPUT!!}):
################################################################
# Web configuration backend
################################################################
defaultEntryPoints = ["http","https"]
[entryPoints]
[entryPoints.http]
address = ":80"
#[entryPoints.http.redirect]
#entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]

[web]
address = ":8080"
[web.auth.basic]
users = ["admin:$apr1$62BTL9Hv$DvZO5S4l6FClkYbuxn4ag/"]

[accessLog]

################################################################
# Docker configuration backend
################################################################
[docker]
domain = "zeitoune.hopto.org"
watch = true
exposedbydefault = false

[acme]
email = "nassar.z@slair.com.au"
storage = "acme.json"
entryPoint = "https"
OnHostRule = true



Then run the following command to create your docker container:


docker run -d --name=traefik --restart always \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v [PATH_TO_TRAEFIK]/traefik.toml:/traefik.toml \
  -v [PATH_TO_TRAEFIK]/acme.json:/acme.json \
  -l 'traefik.backend=traefik' \
  -l 'traefik.frontend.rule=PathPrefixStrip:/traefik' \
  -l 'traefik.enable=true' \
  -l 'traefik.docker.network=[DOCKER_NETWORK]' \
  -l 'traefik.port=8080' \
  --net=traefik \
  -p 80:80 -p 443:443 \
  --expose 8080 \
  traefik:latest


Note that [PATH_TO_TRAEFIK] must exist on your local hard-drive, and [DOCKER_NETWORK] is the network created using the command given at the start of this guide.

Once completed, you should be able to view traefik at https://[HOSTNAME]/traefik


Portainer for Docker Management

Portainer is a useful GUI tool for managing your docker containers (official installation instructions). Just run the following:

docker run -d --restart always \
  --name=portainer -p 9000:9000 --net=traefik \
  -v /etc/localtime:/etc/localtime:ro \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v [PATH_TO_DATA]:/data \
  -l 'traefik.backend=portainer' \
  -l 'traefik.frontend.rule=PathPrefixStrip:/portainer' \
  -l 'traefik.enable=true' \
  -l 'traefik.docker.network=[DOCKER_NETWORK]' \
  -l 'traefik.port=9000' \
portainer/portainer

Note that [PATH_TO_DATA] must exist on your local hard-drive. This is where all the Portainer configuration data will be stored, and is necessary in case you ever wish to update the container.

The portainer instance can now be viewed at https://[HOSTNAME]/portainer/ OR http://[IP_ADDRESS]:9000


Heimdall for Dashboard

Heimdall can be configured as a one-stop shop for accessing all of your configured microservices.


docker run -d --restart always \
  --name=heimdall \
  -v [PATH_TO_DATA]:/config \
  -e PGID=1000 \
  -e PUID=1000 \
  --net=traefik \
  -l 'traefik.backend=heimdall' \
  -l 'traefik.enable=true' \
  -l 'traefik.docker.network=traefik' \
  -l 'traefik.frontend.rule=Host:zeitoune.hopto.org' \
  -l 'traefik.frontend.priority=1'
  -l 'traefik.port=80' \
  linuxserver/heimdall

Note that [PATH_TO_DATA] must exist on your local hard-drive. This is where all the Heimdall configuration data will be stored, and is necessary in case you ever wish to update the container.

The heimdall instance can now be viewed at https://[HOSTNAME]/


Calibre for E-Books

Calibre is a management service for E-Books.

docker run -d --restart always \
  --name=calibre \
  -v [PATH_TO_BOOKS]:/books \
  -v [PATH_TO_APP]:/calibre-web/app \
  -v [PATH_TO_CONFIG]:/calibre-web/config \
  -v [PATH_TO_KINDLEGEN]:/calibre-web/kindlegen \
  -v /etc/localtime:/etc/localtime:ro \
  -e PGID=1000 \
  -e PUID=1000 \
  --net=traefik \
  -l 'traefik.backend=calibre' \
  -l 'traefik.enable=true' \
  -l 'traefik.docker.network=traefik' \
  -l 'traefik.frontend.rule=PathPrefixStrip:/calibre' \
  -l 'traefik.frontend.headers.customRequestHeaders=X-Script-Name:/calibre' \
  -l 'traefik.port=8083' \
  technosoft2000/calibre-web


Note that [PATH_TO_*] must exist on your local hard-drive. This is where all the Calibre data will be stored, and is necessary in case you ever wish to update the container.

The calibre instance can now be viewed at https://[HOSTNAME]/calibre


Ombi for requests

Use Ombi for making media requests.

docker run -d --restart always \
  --name=ombi \
  -v [PATH_TO_CONFIG]:/config \
  -e PGID=1000 \
  -e PUID=1000 \
  -e TZ=Australia/Sydney \
  --net=traefik \
  -l 'traefik.backend=ombi' \
  -l 'traefik.enable=true' \
  -l 'traefik.docker.network=traefik' \
  -l 'traefik.frontend.rule=PathPrefix:/ombi' \
  -l 'traefik.port=3579' \
  -p 3579:3579 \
  linuxserver/ombi

Note that [PATH_TO_CONFIG] must exist on your local hard-drive. This is where all the Ombi data will be stored, and is necessary in case you ever wish to update the container.

Note also that in this case I could only get Ombi to work by opening port 3576, navigating to the URL directly and editing the configuration so that the Base URL is '/ombi' instead of '/'. Once you have that configuration, you can close port 3579 again.

The ombi instance can now be viewed at https://[HOSTNAME]/ombi


Emby for Media

docker run -d --restart always \
  --name=emby \
  -v [PATH_TO_CONFIG]:/config \
  -v /etc/localtime:/etc/localtime:ro \
  -v [PATH_TO_MEDIA]:/media
  -e GID=1000 \
  -e UID=1000 \
  --net=traefik \
  -l 'traefik.backend=emby' \
  -l 'traefik.enable=true' \
  -l 'traefik.docker.network=traefik' \
  -l 'traefik.frontend.rule=PathPrefixStrip:/emby' \
  -l 'traefik.port=8096' \
  emby/embyserver

Note that [PATH_TO_*] must exist on your local hard-drive. This is where all the Emby data (and Media) will be stored, and is necessary in case you ever wish to update the container.

The Emby instance can now be viewed at https://[HOSTNAME]/emby/


Sonarr for TV shows

docker run -d --restart always \
  --name=sonarr \
  -v [PATH_TO_CONFIG]:/config \
  -v [PATH_TO_TV]:/tv \
  -v [PATH_TO_DOWNLOADS]:/downloads \
  -v /etc/localtime:/etc/localtime:ro \
  -e PGID=1000 \
  -e PUID=1000 \
  -e TZ=Australia/Sydney \
  --net=traefik \
  -l 'traefik.backend=sonarr' \
  -l 'traefik.enable=true' \
  -l 'traefik.docker.network=traefik' \
  -l 'traefik.frontend.headers.customRequestHeaders=X-Script-Name:/sonarr/' \
  -l 'traefik.frontend.rule=PathPrefix:/sonarr/' \
  -l 'traefik.port=8989' \
  --dns 8.8.8.8 --dns 8.8.4.4 \
linuxserver/sonarr

Note that [PATH_TO_*] must exist on your local hard-drive. This is where all the Sonarr data (and Media) will be stored, and is necessary in case you ever wish to update the container.

Note also that in this case I could only get Sonarr to work by opening port 8989, navigating to the URL directly and editing the configuration so that the Base URL is '/sonarr/' instead of '/'. Once you have that configuration, you can close port 3579 again.

The Sonarr instance can now be viewed at https://[HOSTNAME]/sonarr/


Radarr for Movies

docker run -d --restart always \
  --name=radarr \
  -v [PATH_TO_CONFIG]:/config \
  -v [PATH_TO_MOVIES]:/movies \
  -v [PATH_TO_DOWNLOADS]:/downloads \
  -v /etc/localtime:/etc/localtime:ro \
  -e PGID=1000 \
  -e PUID=1000 \
  -e TZ=Australia/Sydney \
  --net=traefik \
  -l 'traefik.backend=radarr' \
  -l 'traefik.enable=true' \
  -l 'traefik.docker.network=traefik' \
  -l 'traefik.frontend.headers.customRequestHeaders=X-Script-Name:/radarr/' \
  -l 'traefik.frontend.rule=PathPrefix:/radarr/' \
  -l 'traefik.port=7878' \
  --dns 8.8.8.8 --dns 8.8.4.4 \
  linuxserver/radarr

Note that [PATH_TO_*] must exist on your local hard-drive. This is where all the Radarr data (and Media) will be stored, and is necessary in case you ever wish to update the container.

Note also that in this case I could only get Radarr to work by opening port 7878, navigating to the URL directly and editing the configuration so that the Base URL is '/radarr/' instead of '/'. Once you have that configuration, you can close port 3579 again.

The Radarr instance can now be viewed at https://[HOSTNAME]/radarr/


Jackett for Indexers

docker run -d --restart always \
  --name=jackett \
  -v [PATH_TO_CONFIG]:/config \
  -v [PATH_TO_DOWNLOAD]:/downloads \
  -v /etc/localtime:/etc/localtime:ro \
  -p 9117:9117 \
  -e PUID=1000 -e PGID=1000 \
  -e TZ=Australia/Sydney \
  --net=traefik \
  -l 'traefik.enable=true' \
  -l 'traefik.backend=jackett' \
  -l 'traefik.frontend.rule=PathPrefix:/jackett' \
  -l 'traefik.port=9117' \
  -l 'traefik.docker.network=traefik' \
  --dns 8.8.8.8 --dns 8.8.4.4 \
  linuxserver/jackett

Note that [PATH_TO_*] must exist on your local hard-drive. This is where all the data (and Media) will be stored, and is necessary in case you ever wish to update the container.


Tranmission for Torrents

This is being run with an inbuilt VPN:

docker run -d --restart always \
  --name=transmission \
  --cap-add=NET_ADMIN --device=/dev/net/tun \
  -v /[PATH_TO_CONFIG]:/config \
  -v /[PATH_TO_DOWNLOADS]:/data \
  -v /etc/localtime:/etc/localtime:ro \
  -e OPENVPN_PROVIDER=PIA \
  -e OPENVPN_CONFIG=Netherlands \
  -e OPENVPN_USERNAME=user \
  -e OPENVPN_PASSWORD=pass \
  -e WEBPROXY_ENABLED=false \
  -e LOCAL_NETWORK=192.168.0.0/16 \
  -e TRANSMISSION_RPC_AUTHENTICATION_REQUIRED=true \
  -e TRANSMISSION_RPC_PASSWORD=[PASSWORD] \
  -e TRANSMISSION_RPC_USERNAME=admin \
  -e TRANSMISSION_RPC_HOST_WHITELIST="127.0.0.1,192.168.0.*" \
  --log-driver json-file \
  --log-opt max-size=10m \
  --net=traefik \
  --dns 8.8.8.8 --dns 8.8.4.4 \
  -p 9091:9091 \
  -l 'traefik.backend=transmission' \
  -l 'traefik.enable=true' \
  -l 'traefik.docker.network=traefik' \
  -l 'traefik.frontend.rule=PathPrefix:/transmission' \
  -l 'traefik.port=9091' \
haugene/transmission-openvpn

Note that [PATH_TO_*] must exist on your local hard-drive. This is where all the data (and Media) will be stored, and is necessary in case you ever wish to update the container.


Inspirations

This post was inspired by the following:

Mar 2, 2018

Automatically make web apps use HTTPS with Let's Encrypt, Nginx, and Docker

  1. Make sure you have docker already installed.
  2. Install the Nginx proxy with docker-gen
    
    sudo docker run --name=Nginx -d \
    --restart=always \
    -p 80:80 -p 443:443 \
    -v /data/certs:/etc/nginx/certs:ro \
    -v /var/run/docker.sock:/tmp/docker.sock:ro \
    -v /data/Nginx/vhost.d:/etc/nginx/vhost.d \
    -v /data/Nginx/html:/usr/share/nginx/html \
    --label com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy \
    jwilder/nginx-proxy
    

  3. Since I run portainer, start it up with the VIRTUAL_HOST and VIRTUAL_PORT environment variables so that docker-gen can pick it up. You can do this with any app you desire.
    
    sudo docker run --name Portainer -d \
    --restart=always \
    -p 9000:9000 \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v portainer_data:/data \
    -e VIRTUAL_HOST=portainer.local.network \
    -e VIRTUAL_PORT=9000 \
    portainer/portainer
    

  4. Now to use the Let's encrypt container to make certificates for our docker containers:
    
    sudo docker run --name=Letsencrypt -d \
    --restart=always \
    -v /data/certs:/etc/nginx/certs:rw \
    -v /var/run/docker.sock:/var/run/docker.sock:ro \
    --volumes-from Nginx \
    jrcs/letsencrypt-nginx-proxy-companion
    

  5. To enable SSL for your site, set the environment variables VIRTUAL_PROTO=https, VIRTUAL_PORT=433 environment as well as the LETSENCRYPT_HOST and LETSENCRYPT_EMAIL variables so that docker-gen can pick it up. You can do this with any app you desire. You will also need to mount the certificates and keys within the SSL folder of the container for the container to use the LetsEncrypt keys.

Mar 1, 2018

Making Docker Daemon listen on network port during start-up

Took a bit of time to find the relevant documentation piece, so I thought I would outline it here for easy reference.

Option 1:

This should work for some systems, although distributions that use systemctl may have their docker.service entry overwrite this setting, so you will need to use option 2.
  1. If not already created, create the file /etc/docker/daemon.json
  2. Add in the following:
    
    {
      "hosts": ["fd://", "tcp://0.0.0.0:2375"]
    }
    
  3. Restart docker and check the docker daemon process. It should have the additional -H flag like so:
    
    $ sudo ps aux | grep dockerd
    root     31239  0.7  0.2 1007880 72816 ?       Ssl  15:03   0:00 /usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375
    

Option 2:

  1. Edit the service by running:
    
    sudo systemctl edit docker.service
    

  2. Add the following lines:
    
    [Service]
    ExecStart=
    ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375
    
  3. Reload the service configuration:
    
    sudo systemctl daemon-reload
  4. Restart the daemon:
    
    sudo systemctl restart docker.service
  5. Use the last step of the previous option to test whether docker is listening on the network port

Feb 20, 2018

Fail2Ban unbanning process

  1. Log into the target machine with Fail2Ban installed
  2. Look at the list of banned IPs and identify the IP you wish to unban:
    sudo iptables -L -n
  3. Discover the names of the jails:
    sudo fail2ban-client status
  4. Unban the IP:
    sudo fail2ban-client set ssh-iptables unbanip 123.123.123.123

Running a new GitLab Runner for private GitLab server

This guide was created in conjunction with the official tutorial.
  1. On your Docker installation, download the Gitlab Runner container. When it is eventually run, there are two volumes that are automatically created: /etc/gitlab-runner and /home/gitlab-runner. You may choose to mount these locally on your host instead.
  2. During the run step, make sure you mount your host's docker socket, either using the -v parameter (-v /var/run/docker.sock:/var/run/docker.sock) or your tool of preference.
  3. Open up a shell console on the Runner container.
  4. Run the registration process (gitlab-runner register) and follow the prompts (the details are listed in the Admin Area under Overview -> Runners)

Feb 19, 2018

Exposing your docker daemon API via network port (and getting it into Portainer)

These instructions will be targeted to Linux installations with systemd installed. In particular, I have used an Ubuntu-flavoured distro (ElementaryOS). I presume you have already installed docker onto your machine.

  1. Stop the Docker daemon if is is already running
    sudo systemctl stop docker.service

  2. You can check the status of the service (including if it is even installed)
    sudo systemctl status docker.service

  3. Open the service configuration file
    sudo nano /lib/systemd/system/docker.service

  4. Find the line with 'ExecStart' and modify it as follows (saving it once complete):
    ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H fd://

  5. Reload all of the daemons:
    sudo systemctl daemon-reload

  6. Start the service
    sudo systemctl start docker.service

  7. Open up your portainer installation, navigate to the 'Endpoints' menu item and then enter in the IP and port for your target computer.

Feb 14, 2018

Navigating a private Docker Repository

All this content can be gained by reading the Registry HTTP API v2 specification.

All URLs are assumed to by appended to https://[hostname|ip]:[port]/

Listing Images

/v2/_catalog

This will output a JSON object in the format of:


{
    "repositories": [
        "image1",
        "image2"
    ]
}

List Tags for Image

/v2/[name]/tags/list

This will output a JSON object in the format of:

{
    "name": "image1",
    "tags": [
        "1.0",
        "latest"
    ]
}

Manifest for an Image

/v2/[name]/manifests/[tag]

This will output a JSON object with the manifest information.