services: gluetun: image: qmcgaw/gluetun:latest container_name: gluetun cap_add: - NET_ADMIN devices: - /dev/net/tun:/dev/net/tun environment: - VPN_SERVICE_PROVIDER=protonvpn # Or mullvad, protonvpn, surfshark, etc. - VPN_TYPE=wireguard # WireGuard, openvpn - HTTP_CONTROL_SERVER=ON - HTTP_CONTROL_SERVER_AUTH_DEFAULT_ROLE='{"auth":"apikey","apikey":"${GLUETUN_KEY}"}' # generate by running `docker run --rm qmcgaw/gluetun genkey`, then adding this to your `.env` file - WIREGUARD_PRIVATE_KEY=${VPN_PRIVATE_KEY} - WIREGUARD_MTU=1280 - VPN_PORT_FORWARDING=on - VPN_PORT_FORWARDING_PROVIDER=protonvpn #- OPENVPN_USER=user #- OPENVPN_PASSWORD=password - SERVER_COUNTRIES=Netherlands # choose fast P2P friendly countries - NETWORK_LOCAL_ADDRESSES=192.168.50.0/24,172.16.0.0/12 - FIREWALL_OUTBOUND_SUBNETS=192.168.50.0/24 - TZ=${TIMEZONE} - DNS_UPSTREAM_RESOLVER_TYPE=doh # DNS over TLS is an extra layer of security so your isp can not look at what you're doing through your DNS requests, even if your using a vpn (very vague, I don't know how this syustem works with a vpn). ports: # YOU MUST SPECIFY A PORT PER SERVICE ROUTED THROUGH GLUETUN! - 8888:8000/tcp # gluetun control server, i dont think you should change this - 6881:6881 # Default port for qbit - 6881:6881/udp # Default port for qbit, if udp > tcp - ${QBITTORRENT_PORT}:${QBITTORRENT_PORT} # qBittorrent Web UI - ${PROWLARR_PORT}:${PROWLARR_PORT} # Prowlarr - ${SONARR_PORT}:${SONARR_PORT} # Sonarr - ${RADARR_PORT}:${RADARR_PORT} # Radarr - ${LIDARR_PORT}:${LIDARR_PORT} # Lidarr #- ${SEERR_PORT}:${SEERR_PORT}/tcp # Seerr # took this out of gluetun, as it could cause issues with starting the container, and it was unecessary healthcheck: test: wget --spider -q http://1.1.1.1 || exit 1 # ACTUALLY DUMB FUCK! gluetun itself DOES NOT NEED DNS! # the comment afterwards is stupid, if gluetun can't resolve some DNS name, then the other services can't either, they need to be able to look up databases # dont use google.com, since that requires DNS. if it fails to resolve, the container is forced to restart. This is bad, since we mostly don't need dns for things such as qbittorrent, or prowlarr itself interval: 30s timeout: 15s retries: 3 start_period: 1m volumes: - ./gluetun-data:/tmp/gluetun:rw extra_hosts: - "host.docker.internal:host-gateway" # host-gateway is a docker variable that automatically grabs the 172.XX.0.1 address, this is to be used by prowlarr to communicate with sonarr and radarr. restart: always qbittorrent: image: lscr.io/linuxserver/qbittorrent:latest container_name: qbittorrent network_mode: "container:gluetun" # vpn bunker environment: - PUID=1000 - PGID=1000 - TZ=${TIMEZONE} - WEBUI_PORT=${QBITTORRENT_PORT} volumes: - ./qbittorrent:/config - ${DISK1}:${DISK1}/downloads - ${DISK2}:${DISK2}/downloads - ./gluetun-data:/tmp/gluetun - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro labels: - "autoheal=true" depends_on: gluetun: condition: service_healthy healthcheck: # if gluetun is slow to start, it's over test: ["CMD-SHELL", wget --spider -q https://1.1.1.1 || exit 1] # use 1.1.1.1, we don't need dns around here interval: 1m timeout: 10s retries: 3 start_period: 30s restart: unless-stopped port-updater: # use an image that already has curl/wget to skip the 'apk add' step image: curlimages/curl:latest container_name: port-updater volumes: - ./gluetun-data:/tmp/gluetun:ro # using 'exec' format and 'trap' allows the container to stop instantly entrypoint: ["/bin/sh", "-c"] command: # loololloloolol gemini did this for me - | trap 'exit 0' SIGTERM; while true; do # 1. Wait for Gluetun to actually create the file with a number while [ ! -s /tmp/gluetun/forwarded_port ]; do echo "Waiting for Gluetun to provide a port..." sleep 5 done # 2. Read and clean the port read -r PORT_VAL < /tmp/gluetun/forwarded_port; CLEAN_PORT=$$(echo "$$PORT_VAL" | tr -d '\r\n '); # 3. Only update if the port isn't empty if [ -n "$$CLEAN_PORT" ]; then echo "Updating qBit to port: $$CLEAN_PORT"; sleep 10; echo "Updated to $$CLEAN_PORT" curl -s -X POST -d "json={\"listen_port\":$$CLEAN_PORT}" http://localhost:${QBITTORRENT_PORT}/api/v2/app/setPreferences; # 4. Success! Now sleep for a long time (e.g., 1 hour) sleep 3600 & wait $$!; else # If for some reason it's still blank, retry quickly sleep 10 fi done labels: - "autoheal=true" network_mode: "container:gluetun" depends_on: gluetun: condition: service_healthy healthcheck: test: ["CMD-SHELL", "curl -f https://1.1.1.1 || exit 1"] interval: 1m timeout: 10s retries: 3 start_period: 30s restart: always prowlarr: image: lscr.io/linuxserver/prowlarr:latest container_name: prowlarr environment: - PUID=1000 - PGID=1000 - TZ=${TIMEZONE} volumes: - ./prowlarr:/config - ./notify.sh:/notify.sh:ro - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro labels: - "autoheal=true" network_mode: "container:gluetun" depends_on: gluetun: condition: service_healthy healthcheck: test: ["CMD-SHELL", wget --spider -q https://google.com || exit 1] # needs DNS interval: 5m timeout: 60s retries: 3 start_period: 30s restart: always sonarr: image: lscr.io/linuxserver/sonarr:latest container_name: sonarr environment: - PUID=1000 - PGID=1000 - TZ=${TIMEZONE} volumes: - /var/lib/sonarr:/config # had migrated into docker compose - ${DISK1}:/media # too dangerous to change this - ${DISK2}:/11tb_ext # too dangerous to change this labels: - "autoheal=true" network_mode: "container:gluetun" depends_on: gluetun: condition: service_healthy healthcheck: test: ["CMD-SHELL", "curl -f http://1.1.1.1 || exit 1"] interval: 5m timeout: 60s retries: 3 start_period: 60s restart: always radarr: image: lscr.io/linuxserver/radarr:latest container_name: radarr environment: - PUID=1000 - PGID=1000 - TZ=${TIMEZONE} volumes: - /var/lib/radarr:/config # had migrated into docker compose - ${DISK1}:/media # too dangerous to change this - ${DISK2}:/11tb_ext # too dangerous to change this labels: - "autoheal=true" network_mode: "container:gluetun" depends_on: gluetun: condition: service_healthy healthcheck: test: ["CMD-SHELL", "curl -f http://1.1.1.1 || exit 1"] interval: 1m timeout: 10s retries: 3 start_period: 30s restart: always lidarr: image: lscr.io/linuxserver/lidarr:latest container_name: lidarr environment: - PUID=1000 - PGID=1000 - TZ=${TIMEZONE} volumes: - /home/shaan/torrent-stack/lidarr:/music - /var/lib/lidarr:/config - ${DISK1}:${DISK1} - ${DISK2}:${DISK2} labels: - "autoheal=true" network_mode: "container:gluetun" depends_on: gluetun: condition: service_healthy healthcheck: test: ["CMD-SHELL", "curl -f http://1.1.1.1 || exit 1"] interval: 1m timeout: 10s retries: 3 start_period: 30s restart: unless-stopped tautulli: # has no network bridge between containers. this is fine, as it only needs to get from plex, which is outside this container image: ghcr.io/tautulli/tautulli container_name: tautulli volumes: #- /mnt/media/media:/config - ./tautulli:/config environment: - PUID=1000 - PGID=1000 - TZ=${TIMEZONE} ports: - ${TAUTULLI_PORT}:${TAUTULLI_PORT} restart: always tdarr: container_name: tdarr image: haveagitgat/tdarr:latest networks: - tdarr-net ports: - ${TDARR_PORT}:${TDARR_PORT} # WebUI - ${TDARR_NODE_PORT}:${TDARR_NODE_PORT} # local tdarr-node environment: - TZ=${TIMEZONE} - PUID=1000 - PGID=1000 - UMASK_SET=002 - serverIP=0.0.0.0 volumes: - ./tdarr/server:/app/server - ./tdarr/configs:/app/configs - ./tdarr/temp:/temp - ${DISK1}:${DISK1} - ${DISK2}:${DISK2} # dont put temp files onto a HARD DISK DRIVE! > - ${DISK1}/tdarr-temp:/temp devices: - /dev/dri:/dev/dri # Intel UHD Graphics 710 restart: always tdarr-node: container_name: tdarr-node image: haveagitgat/tdarr_node:latest networks: - tdarr-net environment: - TZ=${TIMEZONE} - PUID=1000 - PGID=1000 - nodeID=${TDARR_NODE_ID} - nodeIP=0.0.0.0 - serverIP=tdarr # Points to the server container - serverPort=${TDARR_NODE_PORT} volumes: - ./tdarr/configs:/app/configs - ./tdarr/logs:/app/logs - /home/shaan/torrent-stack/tdarr/temp:/temp - ${DISK1}:${DISK1} - ${DISK2}:${DISK2} devices: - /dev/dri:/dev/dri # only works if user 'shaan' is a part of the 'video' or 'render' group. restart: always homepage: image: ghcr.io/gethomepage/homepage:latest container_name: homepage ports: - ${HOMEPAGE_PORT}:${HOMEPAGE_PORT} volumes: - ./homepage:/app/config - ./homepage/images:/app/public/images - /var/run/docker.sock:/var/run/docker.sock:ro # (optional) For docker integrations - ./gluetun-data:/tmp/gluetun:ro # get the port from port-updater environment: - "HOMEPAGE_ALLOWED_HOSTS=gethomepage.dev,192.168.50.2:3000,shaan-server:3000,100.76.249.110:3000,ss:3000,shaan-server.tail:${HOMEPAGE_PORT}" # required, may need port. See gethomepage.dev/installation/#homepage_allowed_hosts - "HOMEPAGE_VAR_DISK1=${DISK1}" - "HOMEPAGE_VAR_DISK2=${DISK2}" - "HOMEPAGE_VAR_DISK3=${DISK3}" - "HOMEPAGE_VAR_WEB_PROTOCOL=${WEB_PROTOCOL}" - "HOMEPAGE_VAR_LOCAL_IPV4=${LOCAL_IPV4}" - "HOMEPAGE_VAR_SERVER_NAME=${SERVER_NAME}" - "HOMEPAGE_VAR_PLEX_KEY=${PLEX_KEY}" - "HOMEPAGE_VAR_PROWLARR_KEY=${PROWLARR_KEY}" - "HOMEPAGE_VAR_RADARR_KEY=${RADARR_KEY}" - "HOMEPAGE_VAR_SONARR_KEY=${SONARR_KEY}" - "HOMEPAGE_VAR_LIDARR_KEY=${LIDARR_KEY}" - "HOMEPAGE_VAR_TAUTULLI_KEY=${TAUTULLI_KEY}" - "HOMEPAGE_VAR_SEERR_KEY=${SEERR_KEY}" - "HOMEPAGE_VAR_QBITTORRENT_KEY=${QBITTORRENT_KEY}" - "HOMEPAGE_VAR_TAILSCALE_KEY=${TAILSCALE_KEY}" - "HOMEPAGE_VAR_TAILSCALE_DEVICE_KEY=${TAILSCALE_DEVICE_KEY}" - "HOMEPAGE_VAR_PLEX_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${PLEX_PORT}" - "HOMEPAGE_VAR_QBITTORRENT_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${QBITTORRENT_PORT}" - "HOMEPAGE_VAR_PROWLARR_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${PROWLARR_PORT}" - "HOMEPAGE_VAR_SONARR_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${SONARR_PORT}" - "HOMEPAGE_VAR_RADARR_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${RADARR_PORT}" - "HOMEPAGE_VAR_LIDARR_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${LIDARR_PORT}" - "HOMEPAGE_VAR_TAUTULLI_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${TAUTULLI_PORT}" - "HOMEPAGE_VAR_TDARR_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${TDARR_PORT}" - "HOMEPAGE_VAR_HOMEPAGE_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${HOMEPAGE_PORT}" - "HOMEPAGE_VAR_GLANCES_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${GLANCES_PORT}" - "HOMEPAGE_VAR_SEERR_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${SEERR_PORT}" - "HOMEPAGE_VAR_MYSPEED_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${MYSPEED_PORT}" - "HOMEPAGE_VAR_TERMIX_ADDRESS=${WEB_PROTOCOL}://${LOCAL_IPV4}:${TERMIX_PORT}" - "HOMEPAGE_VAR_PLEX_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${PLEX_PORT}" - "HOMEPAGE_VAR_QBITTORRENT_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${QBITTORRENT_PORT}" - "HOMEPAGE_VAR_PROWLARR_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${PROWLARR_PORT}" - "HOMEPAGE_VAR_SONARR_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${SONARR_PORT}" - "HOMEPAGE_VAR_RADARR_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${RADARR_PORT}" - "HOMEPAGE_VAR_LIDARR_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${LIDARR_PORT}" - "HOMEPAGE_VAR_TAUTULLI_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${TAUTULLI_PORT}" - "HOMEPAGE_VAR_TDARR_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${TDARR_PORT}" - "HOMEPAGE_VAR_HOMEPAGE_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${HOMEPAGE_PORT}" - "HOMEPAGE_VAR_GLANCES_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${GLANCES_PORT}" - "HOMEPAGE_VAR_SEERR_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${SEERR_PORT}" - "HOMEPAGE_VAR_MYSPEED_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${MYSPEED_PORT}" - "HOMEPAGE_VAR_TERMIX_HOST=${WEB_PROTOCOL}://${SERVER_NAME}:${TERMIX_PORT}" extra_hosts: - "host.docker.internal:host-gateway" restart: always glances: image: nicolargo/glances:latest-full container_name: glances pid: host network_mode: host devices: - /dev/dri:/dev/dri volumes: - /var/run/docker.sock:/var/run/docker.sock - /etc/os-release:/etc/os-release:ro - /:/host:ro environment: - GLANCES_OPT=-w - PUID=1000 - PGID=1000 restart: unless-stopped autoheal: image: willfarrell/autoheal:latest container_name: autoheal environment: - AUTOHEAL_CONTAINER_LABEL=all - AUTOHEAL_INTERVAL=30 - AUTOHEAL_START_PERIOD=60 volumes: - /var/run/docker.sock:/var/run/docker.sock restart: always seerr: image: ghcr.io/seerr-team/seerr:latest init: true container_name: seerr ports: - ${SEERR_PORT}:${SEERR_PORT} environment: - LOG_LEVEL=debug - TZ=${TIMEZONE} - PUID=1000 - PGID=1000 volumes: - "./seerr:/app/config" working_dir: "/app" labels: - "autoheal=true" healthcheck: test: ["CMD-SHELL", "wget --spider -q http://1.1.1.1 || exit 1"] interval: 1m timeout: 10s retries: 3 start_period: 60s restart: unless-stopped MySpeed: command: - "node" - "server" container_name: "MySpeed" entrypoint: - "docker-entrypoint.sh" environment: - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - "NODE_VERSION=18.20.3" - "YARN_VERSION=1.22.19" - "NODE_ENV=production" - "TZ=Etc/UTC" hostname: "4b5e3178fcc4" image: "germannewsmaker/myspeed" ipc: "private" logging: driver: "json-file" options: {} mac_address: "02:42:ac:11:00:03" network_mode: "bridge" ports: - "${MYSPEED_PORT}:${MYSPEED_PORT}/tcp" volumes: - "myspeed:/myspeed/data" working_dir: "/myspeed" restart: unless-stopped termix: image: ghcr.io/lukegus/termix:latest container_name: termix cap_add: - NET_ADMIN - SYS_ADMIN ports: - "${TERMIX_PORT}:${TERMIX_PORT}" volumes: - termix-data:/app/data environment: PORT: "${TERMIX_PORT}" networks: - termix-net restart: unless-stopped networks: tdarr-net: driver: bridge termix-net: driver: bridge volumes: myspeed: external: true # docker compose will fail creating myspeed if the volume hasn't been manually created, which we have done. unless you deleted it... termix-data: driver: local