User Tools

Site Tools


linux:gluetun-docker-stack

Gluetun Docker Stack

Gluetun is a docker image for several VPN providers. It can be used to route specific other docker services through the configured VPN while the main system remains unaffected.

The following is a docker compose file using gluetun as VPN and http proxy and several additional services with auto heal capability to restart the services if they stop responding.

This stack includes:

  • autoheal
  • qbittorrent
  • prowlarr
  • transmission
  • flaresolverr
  • stash
  • radarr
  • sonarr
  • jdownloader2
  • socks5

The whole stack uses the network of the gluetun service and all other services can interact with each other through localhost:port. The external ports are all configured in the gluetun service.

sonarr and radarr are dependent on prowlarr, all services (except for autoheal) are dependent on gluetun to ensure the VPN is started first.

Note that volume paths need to be adjusted and services can be removed as required.

The http or socks5 proxies can be used by other devices in the network (browser settings / command line settings etc) as necessary. If only specific domains should be routed through the VPN but all others should bypass it a custom proxy auto configuration could be used like Firefox/Chrome Proxy

docker-gluetun.yml
name: gluetun
services:
  gluetun:
    container_name: gluetun
    hostname: gluetun
    image: qmcgaw/gluetun
    # container_name: gluetun
    # line above must be uncommented to allow external containers to connect.
    # See https://github.com/qdm12/gluetun-wiki/blob/main/setup/connect-a-container-to-gluetun.md#external-container-to-gluetun
    cap_add:
      - NET_ADMIN
    devices:
      - /dev/net/tun:/dev/net/tun
    ports:
      - 8888:8888/tcp   # HTTP proxy
        #- 8388:8388/tcp   # Shadowsocks
        #- 8388:8388/udp   # Shadowsocks
      - 9092:9092       # qBittorrent web
      - 6881:6881       # qBittorrent bt data
      - 6881:6881/udp   # qBittorrent bt data
      - 9696:9696       # Prowlarr
      - 9091:9091       # Transmission web
      - 51413:51413     # Transmission bt data
      - 51413:51413/udp # Transmission bt data
      - 8191:8191       # Flaresolverr
      - 8488:1080       # socks5 proxy
      - 9998:9998       # Stash3D
      - 8310:8310       # Radarr
      - 8989:8989       # Sonarr
      - 5800:5800       # JDownloader2 web interface port
      - 5900:5900       # JDownloader2 vnc port
      - 3129:3129       # JDownloader2 myjdownloader port see https://github.com/jlesage/docker-jdownloader-2#direct-connection

    volumes:
      - /opt/gluetun/config:/gluetun
        #- /opt/gluetun/wg0.conf:/gluetun/wireguard/wg0.conf
    environment:
      - FIREWALL_OUTBOUND_SUBNETS=192.168.1.0/24
      - VPN_SERVICE_PROVIDER=mullvad
      - VPN_TYPE=wireguard
      - WIREGUARD_PRIVATE_KEY=xxxxxxxxPrivateKeyxxxxxxxx
      - WIREGUARD_ADDRESSES=10.70.149.4/32
      - SERVER_COUNTRIES=Sweden,USA,Germany,Canada
        #- SERVER_CITIES=got,lax,atl,sto,fra,dus,ber,tor,mtr
      # See https://github.com/qdm12/gluetun-wiki/tree/main/setup#setup
      # Timezone for accurate log times
      - TZ=Europe/London
      # Server list updater
      # See https://github.com/qdm12/gluetun-wiki/blob/main/setup/servers.md#update-the-vpn-servers-list
      - UPDATER_PERIOD=24h
      - HTTPPROXY=on
      - HTTPPROXY_LISTENING_ADDRESS=:8888
      - HTTPPROXY_STEALTH=on
        #- HTTPPROXY_USER=proxy
        #- HTTPPROXY_PASSWORD=server123
        #- SHADOWSOCKS=on
        #- SHADOWSOCKS_LISTENING_ADDRESS=:8388
    restart: unless-stopped
    labels:
      autoheal-app: true

  autoheal:
    container_name: autoheal
    deploy:
      replicas: 1
    environment:
      AUTOHEAL_CONTAINER_LABEL: autoheal-app
    image: willfarrell/autoheal:latest
    network_mode: none
    restart: always
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock

  socks5:
    image: serjs/go-socks5-proxy
    container_name: socks5
    depends_on:
      gluetun:
        condition: service_healthy
    network_mode: "service:gluetun"
    restart: always
    labels:
      autoheal-app: true

  qbittorrent:
    image: lscr.io/linuxserver/qbittorrent:latest
    container_name: qbittorrent
    environment:
      - PUID=1004
      - PGID=1001
      - TZ=Europe/London
      - WEBUI_PORT=9092
      - TORRENTING_PORT=6881
    volumes:
      - /opt/qbittorrent:/config
      - /mnt/download:/downloads
      - /media:/media
        #ports:
        #- 9092:9092
        #- 6881:6881
        #- 6881:6881/udp
    depends_on:
      gluetun:
        condition: service_healthy
    network_mode: service:gluetun
    restart: unless-stopped
    labels:
      autoheal-app: true
    healthcheck:
      interval: 5m
      retries: 5
      start_period: 2m
      test: curl -f http://localhost:9092 || exit 1
      timeout: 20s

  flaresolverr:
    image: ghcr.io/flaresolverr/flaresolverr:latest
     # DockerHub mirror flaresolverr/flaresolverr:latest
     #image: 21hsmw/flaresolverr:fixlooping
     #image: docker.io/library/oui:oui
     #image: ghcr.io/flaresolverr/flaresolverr:latest
     #image: ghcr.io/flaresolverr/flaresolverr:pr-1282
     #jcolfej/flaresolverr:pr-1272
     #image: alexfozor/flaresolverr:pr-1300
     #image: alexfozor/flaresolverr:pr-1300-experimental
    container_name: flaresolverr
    environment:
      - LOG_LEVEL=debug
      - LOG_HTML=false
      - CAPTCHA_SOLVER=none
      - TZ=Europe/London
      - LANG=en_GB
        #ports:
        #      - "8191:8191"
    network_mode: service:gluetun
    depends_on:
      gluetun:
        condition: service_healthy
    restart: unless-stopped
    labels:
      autoheal-app: true
    healthcheck:
      interval: 5m
      retries: 5
      start_period: 2m
      test: curl -f http://localhost:8191/health || exit 1
      timeout: 20s
      
  transmission:
    image: lscr.io/linuxserver/transmission:latest
    container_name: transmission
    environment:
      - PUID=1004
      - PGID=1001
      - TZ=Europe/London
        #      - TRANSMISSION_WEB_HOME= #optional
        #      - USER= #optional
        #      - PASS= #optional
        #      - WHITELIST= #optional
        #      - PEERPORT= #optional
        #      - HOST_WHITELIST= #optional
    volumes:
      - /opt/transmission:/config
      - /mnt/download:/downloads
      - /mnt/download/watch:/watch
      - /media:/media
        #ports:
        #      - 9091:9091
        #      - 51413:51413
        #      - 51413:51413/udp
    network_mode: service:gluetun
    depends_on:
      gluetun:
        condition: service_healthy
    restart: unless-stopped
    labels:
      autoheal-app: true
    healthcheck:
      interval: 5m
      retries: 5
      start_period: 2m
      test: curl -f http://localhost:9091 || exit 1
      timeout: 20s

  prowlarr:
    image: lscr.io/linuxserver/prowlarr:develop #or latest
    container_name: prowlarr
    environment:
      - PUID=1001
      - PGID=1001
      - TZ=Europe/London
    volumes:
      - /opt/prowlarr:/config
        #ports:
        #      - 9696:9696
    network_mode: service:gluetun
    depends_on:
      gluetun:
        condition: service_healthy
    restart: unless-stopped
    labels:
      autoheal-app: true
    healthcheck:
      interval: 5m
      retries: 5
      start_period: 2m
      test: wget --no-verbose --tries=1 --spider http://localhost:9696 || exit 1
      timeout: 20s

  stash3d:
    image: stashapp/stash:development #alt: latest
    #image: cr.hotio.dev/hotio/stash:nightly #alt release
    container_name: stash3d
    ## the container's port must be the same with the STASH_PORT in the environment section
    #ports:
    #  - "9998:9998"
    ## If you intend to use stash's DLNA functionality uncomment the below network mode and comment out the above ports section
    # network_mode: host
    logging:
      driver: "json-file"
      options:
        max-file: "10"
        max-size: "2m"
    environment:
      - STASH_STASH=/data/
      - STASH_GENERATED=/generated/
      - STASH_METADATA=/metadata/
      - STASH_CACHE=/cache/
      ## Adjust below to change default port (9999)
      - STASH_PORT=9998
      - PUID=1006
      - PGID=1001
      - UMASK=002
      - TZ=Europe/London
    volumes:
      - /etc/localtime:/etc/localtime:ro
      ## Adjust below paths (the left part) to your liking.
      ## E.g. you can change ./config:/root/.stash to ./stash:/root/.stash
 
      ## Keep configs, scrapers, and plugins here.
      - /opt/stash3d-storage/config:/root/.stash
      ## Point this at your collection.
      - /media/stash3d:/data
      ## This is where your stash's metadata lives
      - /opt/stash3d-storage/metadata:/metadata
      ## Any other cache content.
      - /opt/stash3d-storage/cache:/cache
      ## Where to store binary blob data (scene covers, images)
      - /opt/stash3d-storage/blobs:/blobs
      ## Where to store generated content (screenshots,previews,transcodes,sprites)
      - /opt/stash3d-storage/generated:/generated
    devices:
      - /dev/dri:/dev/dri
    # use if not using the update bash script intel-media-driver for newer, libva-intel-driver for older
    #command: /bin/sh -c 'apk --no-cache add libva-intel-driver && stash'
    post_start:
      - command: /usr/bin/pip install pystashlib stashapp-tools --break-system-packages
        user: root
      # for 13th gen Iris Xe GPUs use intel-media-driver for older gens libva-intel-driver
      - command: apk add libva-intel-driver intel-media-driver
        user: root
    restart: unless-stopped
    network_mode: service:gluetun
    depends_on:
      gluetun:
        condition: service_healthy
    labels:
        autoheal-app: true
    healthcheck:
      interval: 5m
      retries: 5
      start_period: 2m
      test: wget --no-verbose --tries=1 --spider http://localhost:9998 || exit 1
      timeout: 20s

  radarr:
    image: lscr.io/linuxserver/radarr:develop
    container_name: radarr
    environment:
      - UMASK_SET=022
      - PUID=1003
      - PGID=1001
      - TZ=Europe/London
    volumes:
      - /media/movies:/movies
      - /mnt/download/complete:/downloads
      - /opt/radarr:/config
        #ports:
        #- 8310:8310
    network_mode: service:gluetun
    depends_on:
      gluetun:
        condition: service_healthy
      prowlarr:
        condition: service_started
    restart: unless-stopped
    labels:
      autoheal-app: true
    healthcheck: 
      interval: 5m 
      retries: 5 
      start_period: 2m 
      test: curl -f http://localhost:8310/ping || exit 1
      timeout: 20s

  sonarr:
    image: lscr.io/linuxserver/sonarr:latest
    container_name: sonarr
    environment:
      - PUID=1002
      - PGID=1001
      - TZ=Europe/London
    volumes:
      - /media/tv:/data
      - /opt/sonarr:/config
      - /mnt/download/complete:/downloads
        #ports:
        #- 8989:8989
    network_mode: service:gluetun
    depends_on:
      gluetun:
        condition: service_healthy
      prowlarr:
        condition: service_started
    restart: unless-stopped
    labels:
      autoheal-app: true
    healthcheck:
      interval: 5m
      retries: 5
      start_period: 2m
      test: curl -f http://localhost:8989/ping || exit 1
      timeout: 20s

  jdownloader2:
    image: jlesage/jdownloader-2
    container_name: jdownloader2
    #ports:
      #- "5800:5800" #web interface port
      #- "5900:5900" #vnc port
      #- "3129:3129" #myjdownloader port see https://github.com/jlesage/docker-jdownloader-2#direct-connection
    volumes:
      - "/opt/jdownloader2:/config:rw"
      - "/media/downloads:/output:rw"
    network_mode: service:gluetun
    depends_on:
      gluetun:
        condition: service_healthy
      socks5:
        condition: service_started
    restart: unless-stopped
    labels:
      autoheal-app: true
    healthcheck:
      interval: 5m     
      retries: 5
      start_period: 2m
      test: curl -f http://localhost:5800 || exit 1
      timeout: 20s

Starting the whole stack:

docker compose -f docker-gluetun.yml up -d

Updating individual services (e.g. autohealth):

docker compose -f docker-gluetun.yml pull autohealth
docker compose -f docker-gluetun.yml up autohealth -d

As a restart/rebuild of the gluetun container prevents the other services from connecting, forcing gluetun to only connect to a different VPN endpoint can be done using the following 'hack':

docker exec -ti gluetun 'wget' '-qO-' '--method=PUT' '--body-data={"status":"stopped"}' 'http://127.0.0.1:8000/v1/openvpn/status'
linux/gluetun-docker-stack.txt · Last modified: by Wulf Rajek