From 2045f4ae58628e200f9db5c85067ddade3a92a64 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Mon, 14 Jul 2025 10:01:19 +0200 Subject: [PATCH] Make arrstack docker compose ansible ready Move sonarr to new system Move sabnzbd to new system Move radarr Move lidarr !unsafe directive makes ansible ignore potential template vars in the string https://github.com/ansible/ansible/issues/16443 Move readarr Move prowlarr Move homarr Move beets Move jellyseerr Move audiobookshelf Move jellyfin Move gonic Migrate torrent setup --- ansible/roles/arr/defaults/main.yml | 9 +- ansible/roles/arr/tasks/main.yml | 12 +- .../arr/templates/docker-compose.yaml.j2 | 362 ++++++++++++------ 3 files changed, 254 insertions(+), 129 deletions(-) diff --git a/ansible/roles/arr/defaults/main.yml b/ansible/roles/arr/defaults/main.yml index 5506ed5..47ea10a 100644 --- a/ansible/roles/arr/defaults/main.yml +++ b/ansible/roles/arr/defaults/main.yml @@ -4,6 +4,11 @@ arrstack_env_dir: /opt/arrstack arrstack_data_dir: /srv arrstack_data_dir_create: true -arrstack_data_dir_owner: 1000 -arrstack_data_dir_group: 1000 +arrstack_puid: 1000 +arrstack_pgid: 100 +arrstack_tz: Europe/Berlin +arrstack_umask_set: 022 + +# arrstack_mb_user: Musicbrainz-user +# arrstack_mb_pass: Musicbrainz-password diff --git a/ansible/roles/arr/tasks/main.yml b/ansible/roles/arr/tasks/main.yml index f446a30..f2710ef 100644 --- a/ansible/roles/arr/tasks/main.yml +++ b/ansible/roles/arr/tasks/main.yml @@ -11,8 +11,8 @@ ansible.builtin.file: state: directory path: "{{ arrstack_data_dir }}/{{ item }}" - owner: "{{ arrstack_data_dir_owner }}" - group: "{{ arrstack_data_dir_group }}" + owner: "{{ arrstack_puid }}" + group: "{{ arrstack_pgid }}" mode: 0770 when: arrstack_data_dir_create loop: @@ -26,14 +26,6 @@ - media/music - media/audiobooks -# - name: Create Docker Compose environment file -# ansible.builtin.template: -# src: docker-compose.yml.j2 -# dest: "{{ arrstack_env_dir }}/docker-compose.yml" -# owner: root -# group: root -# mode: 0600 - - name: Start the compose stack community.docker.docker_compose_v2: project_name: arrstack diff --git a/ansible/roles/arr/templates/docker-compose.yaml.j2 b/ansible/roles/arr/templates/docker-compose.yaml.j2 index ec65b35..00f0252 100644 --- a/ansible/roles/arr/templates/docker-compose.yaml.j2 +++ b/ansible/roles/arr/templates/docker-compose.yaml.j2 @@ -1,117 +1,191 @@ services: - whoami: - container_name: whoami - image: traefik/whoami - ports: - - 80:80 - sonarr: container_name: sonarr image: lscr.io/linuxserver/sonarr:latest - ports: - - 8989:8989 - env_file: - - arr.env + networks: + - caddy + environment: + - PUID={{ arrstack_puid }} + - PGID={{ arrstack_pgid }} + - TZ={{ arrstack_tz }} + - UMASK_SET={{ arrstack_umask_set }} volumes: - - "./config/sonarr:/config" + - "{{ arrstack_env_dir }}/config/sonarr:/config" - "{{ arrstack_data_dir }}/media/tv:/data/media/tv" - "{{ arrstack_data_dir }}/files/usenet:/data/usenet" - "{{ arrstack_data_dir }}/files/torrent:/data/torrent" restart: unless-stopped + labels: + caddy: "http://sonarr.pichi.berlin" + caddy.reverse_proxy: "{{ '{{' }}upstreams 8989{{ '}}'}}" + radarr: container_name: radarr image: lscr.io/linuxserver/radarr:latest - ports: - - 7878:7878 - env_file: - - arr.env + networks: + - caddy + environment: + - PUID={{ arrstack_puid }} + - PGID={{ arrstack_pgid }} + - TZ={{ arrstack_tz }} + - UMASK_SET={{ arrstack_umask_set }} volumes: - - "./config/radarr:/config" + - "{{ arrstack_env_dir }}/config/radarr:/config" - "/mnt/ext/data/media/movies:/data/media/movies" # FIXME: Find solution - "{{ arrstack_data_dir }}/files/usenet:/data/usenet" - "{{ arrstack_data_dir }}/files/torrent:/data/torrent" restart: unless-stopped + labels: + caddy: "http://radarr.pichi.berlin" + caddy.reverse_proxy: "{{ '{{' }}upstreams 7878{{ '}}'}}" + lidarr: container_name: lidarr image: lscr.io/linuxserver/lidarr:latest - ports: - - 8686:8686 - env_file: - - arr.env - - mb.env + networks: + - caddy + environment: + - PUID={{ arrstack_puid }} + - PGID={{ arrstack_pgid }} + - TZ={{ arrstack_tz }} + - UMASK_SET={{ arrstack_umask_set }} + - MB_USER={{ arrstack_mb_user }} + - MB_PASS={{ arrstack_mb_pass }} environment: - DOCKER_MODS=linuxserver/mods:universal-docker volumes: - - "./config/lidarr:/config" + - "{{ arrstack_env_dir }}/config/lidarr:/config" - "/var/run/docker.sock:/var/run/docker.sock:ro" - "{{ arrstack_data_dir }}/media/music:/data/media/music" - "{{ arrstack_data_dir }}/files/usenet:/data/usenet" - "{{ arrstack_data_dir }}/files/torrent:/data/torrent" restart: unless-stopped + labels: + caddy: "http://lidarr.pichi.berlin" + caddy.reverse_proxy: "{{ '{{' }}upstreams 8686{{ '}}'}}" + readarr: container_name: readarr image: lscr.io/linuxserver/readarr:develop - ports: - - 8787:8787 - env_file: - - arr.env + networks: + - caddy + environment: + - PUID={{ arrstack_puid }} + - PGID={{ arrstack_pgid }} + - TZ={{ arrstack_tz }} + - UMASK_SET={{ arrstack_umask_set }} volumes: - - "./config/readarr:/config" + - "{{ arrstack_env_dir }}/config/readarr:/config" - "{{ arrstack_data_dir }}/media/audiobooks:/data/media/audiobooks" - "{{ arrstack_data_dir }}/files/usenet:/data/usenet" - "{{ arrstack_data_dir }}/files/torrent:/data/torrent" restart: unless-stopped + labels: + caddy: "http://readarr.pichi.berlin" + caddy.reverse_proxy: "{{ '{{' }}upstreams 8787{{ '}}'}}" + prowlarr: container_name: prowlarr image: lscr.io/linuxserver/prowlarr:develop - env_file: - - arr.env + networks: + - caddy + environment: + - PUID={{ arrstack_puid }} + - PGID={{ arrstack_pgid }} + - TZ={{ arrstack_tz }} + - UMASK_SET={{ arrstack_umask_set }} volumes: - - "./config/prowlarr:/config" - ports: - - 9696:9696 + - "{{ arrstack_env_dir }}/config/prowlarr:/config" restart: unless-stopped + labels: + caddy: "http://prowlarr.pichi.berlin" + caddy.reverse_proxy: "{{ '{{' }}upstreams 9696{{ '}}'}}" + + beets: + image: lscr.io/linuxserver/beets:latest + container_name: beets + networks: + - caddy + environment: + - PUID={{ arrstack_puid }} + - PGID={{ arrstack_pgid }} + - TZ={{ arrstack_tz }} + - UMASK_SET={{ arrstack_umask_set }} + - MB_USER={{ arrstack_mb_user }} + - MB_PASS={{ arrstack_mb_pass }} + volumes: + - "{{ arrstack_env_dir }}/config/beets:/config" + - "{{ arrstack_data_dir }}/media/music:/music" + - "{{ arrstack_data_dir }}/files/music-unsorted:/downloads" + restart: unless-stopped + labels: + caddy: "http://prowlarr.pichi.berlin" + caddy.reverse_proxy: "{{ '{{' }}upstreams 8337{{ '}}'}}" + sabnzbd: container_name: sabnzbd image: lscr.io/linuxserver/sabnzbd:latest - env_file: - - arr.env + networks: + - caddy + environment: + - PUID={{ arrstack_puid }} + - PGID={{ arrstack_pgid }} + - TZ={{ arrstack_tz }} + - UMASK_SET={{ arrstack_umask_set }} volumes: - - "./config/sabnzbd:/config" + - "{{ arrstack_env_dir }}/config/sabnzbd:/config" - "{{ arrstack_data_dir }}/files/usenet:/data/usenet:rw" - ports: - - 8080:8080 restart: unless-stopped + labels: + caddy: "http://usenet.pichi.berlin" + caddy.reverse_proxy: "{{ '{{' }}upstreams 8080{{ '}}'}}" + vpn: - image: qmcgaw/gluetun:v3 container_name: vpn + image: qmcgaw/gluetun:v3 + networks: + - caddy + environment: + - PUID={{ arrstack_puid }} + - PGID={{ arrstack_pgid }} + - TZ={{ arrstack_tz }} + - UMASK_SET={{ arrstack_umask_set }} + - VPN_PORT_FORWARDING_STATUS_FILE=/gluetun/forwarded_port + - FIREWALL_OUTBOUND_SUBNETS=172.18.0.0/24 + - BLOCK_SURVEILLANCE=on + - VPN_SERVICE_PROVIDER={{ arrstack_vpn_provider }} + - OPENVPN_USER={{ arrstack_vpn_user }} + - OPENVPN_PASSWORD={{ arrstack_vpn_pass }} + - SERVER_REGIONS={{ arrstack_vpn_regions }} + - PORT_FORWARD_ONLY=true + - VPN_PORT_FORWARDING=on + - VPN_PORT_FORWARDING_PROVIDER={{ arrstack_vpn_provider }} + - QBITTORRENT_USER={{ arrstack_qbit_user }} + - QBITTORRENT_PASS={{ arrstack_qbit_pass }} cap_add: - NET_ADMIN devices: - /dev/net/tun:/dev/net/tun - env_file: - - arr.env - - pia.env - environment: - - VPN_PORT_FORWARDING_STATUS_FILE=/gluetun/forwarded_port - - FIREWALL_OUTBOUND_SUBNETS=172.18.0.0/24 - - BLOCK_SURVEILLANCE=on volumes: - - "./config/gluetun:/gluetun" - ports: - - 8000:8000 # gluetun http control - - 8888:8888 # qBittorrent WebUI + - "{{ arrstack_env_dir }}/config/gluetun:/gluetun" + #ports: # TODO: should this be exposed? + # - 8000:8000 # gluetun http control restart: unless-stopped + labels: + caddy: "http://torrent.pichi.berlin" + caddy.reverse_proxy: "{{ '{{' }}upstreams 8888{{ '}}'}}" qbittorrent: image: linuxserver/qbittorrent container_name: qbittorrent - env_file: - - arr.env environment: + - PUID={{ arrstack_puid }} + - PGID={{ arrstack_pgid }} + - TZ={{ arrstack_tz }} + - UMASK_SET={{ arrstack_umask_set }} - WEBUI_PORT=8888 volumes: - - "./config/piaqbit:/config" - - "./config/gluetun:/gluetun" + - "{{ arrstack_env_dir }}/config/piaqbit:/config" + - "{{ arrstack_env_dir }}/config/gluetun:/gluetun" - "{{ arrstack_data_dir }}/files/torrent:/downloads" depends_on: - vpn @@ -120,19 +194,30 @@ services: gluetun-qbittorrent-port-manager: image: patrickaclark/gluetun-qbittorrent-port-manager:latest container_name: qbit-port-manager - env_file: - - arr.env - - pia.env environment: - - QBITTORRENT_SERVER=localhost # IP Address of qbittorrent + - PUID={{ arrstack_puid }} + - PGID={{ arrstack_pgid }} + - TZ={{ arrstack_tz }} + - UMASK_SET={{ arrstack_umask_set }} + - WEBUI_PORT=8888 + - QBITTORRENT_SERVER=qbittorrent # IP Address of qbittorrent - QBITTORRENT_PORT=8888 - PORT_FORWARDED=/gluetun/forwarded_port - HTTP_S=http # Select 'http' or 'https' depending on if you use certificates. - - GLUETUN_HOST=localhost # IP or FQDN of gluetun control server + - GLUETUN_HOST=vpn # IP or FQDN of gluetun control server - GLUETUN_PORT=8000 # port of gluetun control server - RECHECK_TIME=60 # number of seconds between checks to gluetun server for port + - VPN_SERVICE_PROVIDER={{ arrstack_vpn_provider }} + - OPENVPN_USER={{ arrstack_vpn_user }} + - OPENVPN_PASSWORD={{ arrstack_vpn_pass }} + - SERVER_REGIONS={{ arrstack_vpn_regions }} + - PORT_FORWARD_ONLY=true + - VPN_PORT_FORWARDING=on + - VPN_PORT_FORWARDING_PROVIDER={{ arrstack_vpn_provider }} + - QBITTORRENT_USER={{ arrstack_qbit_user }} + - QBITTORRENT_PASS={{ arrstack_qbit_pass }} volumes: - - "./config/gluetun:/gluetun" + - "{{ arrstack_env_dir }}/config/gluetun:/gluetun" depends_on: - vpn network_mode: "service:vpn" @@ -143,67 +228,110 @@ services: timeout: 10s start_period: 60s retries: 3 - jellyfin: - image: lscr.io/linuxserver/jellyfin:latest - container_name: jellyfin - env_file: - - arr.env - #environment: - #- JELLYFIN_PublishedServerUrl=192.168.0.5 #optional - volumes: - - ".config/jellyfin:/config" - - "/mnt/ext/data/media/movies:/media/movies" # FIXME: To be changed? - - "{{ arrstack_data_dir }}/media/tv:/media/tv" - - "{{ arrstack_data_dir }}/media/music:/media/music" - ports: - - 8096:8096 - - 7359:7359/udp #optional - network discovery - - 1900:1900/udp #optional - dlna discovery - restart: unless-stopped - audiobookshelf: - container_name: audiobookshelf - image: ghcr.io/advplyr/audiobookshelf:latest - env_file: - - arr.env - ports: - - 13378:80 - volumes: - - "{{ arrstack_data_dir }}/media/audiobooks:/audiobooks" - # - "{{ arrstack_data_dir }}/media/podcasts:/podcasts" # TODO: If integrating podcasts - - ".config/audiobookshelf:/config" - - ".metadata/audiobookshelf:/metadata" - restart: unless-stopped - jellyseerr: - image: fallenbagel/jellyseerr:latest - container_name: jellyseerr - env_file: - - arr.env - ports: - - 5055:5055 - volumes: - - "./config/jellyseerr:/app/config" - restart: unless-stopped - beets: - image: lscr.io/linuxserver/beets:latest - container_name: beets - env_file: - - arr.env - - mb.env - volumes: - - "./config/beets:/config" - - "{{ arrstack_data_dir }}/media/music:/music" - - "{{ arrstack_data_dir }}/files/music-unsorted:/downloads" - ports: - - 8337:8337 - restart: unless-stopped + homarr: image: ghcr.io/ajnart/homarr:latest container_name: homarr + networks: + - caddy volumes: + - {{ arrstack_env_dir }}/config/homarr/configs:/app/data/configs + - {{ arrstack_env_dir }}/config/homarr/icons:/app/public/icons + - {{ arrstack_env_dir }}/config/homarr/data:/data - /var/run/docker.sock:/var/run/docker.sock # Optional, only if you want docker integration - - ./config/homarr/configs:/app/data/configs - - ./config/homarr/icons:/app/public/icons - - ./config/homarr/data:/data - ports: - - '80:7575' restart: unless-stopped + labels: + caddy: "http://pichi.berlin" + caddy.reverse_proxy: "{{ '{{' }}upstreams 7575{{ '}}'}}" + + jellyseerr: + image: fallenbagel/jellyseerr:latest + container_name: jellyseerr + networks: + - caddy + environment: + - PUID={{ arrstack_puid }} + - PGID={{ arrstack_pgid }} + - TZ={{ arrstack_tz }} + - UMASK_SET={{ arrstack_umask_set }} + volumes: + - "{{ arrstack_env_dir }}/config/jellyseerr:/app/config" + restart: unless-stopped + labels: + caddy: "http://get.pichi.berlin" + caddy.reverse_proxy: "{{ '{{' }}upstreams 5055{{ '}}'}}" + + audiobookshelf: + container_name: audiobookshelf + image: ghcr.io/advplyr/audiobookshelf:latest + networks: + - caddy + environment: + - PUID={{ arrstack_puid }} + - PGID={{ arrstack_pgid }} + - TZ={{ arrstack_tz }} + - UMASK_SET={{ arrstack_umask_set }} + volumes: + - "{{ arrstack_env_dir }}/config/audiobookshelf:/config" + - "{{ arrstack_env_dir }}/data/audiobookshelf:/metadata" + - "{{ arrstack_data_dir }}/media/audiobooks:/audiobooks" + # - "{{ arrstack_data_dir }}/media/podcasts:/podcasts" # TODO: If integrating podcasts + restart: unless-stopped + labels: + caddy: "http://books.pichi.berlin" + caddy.reverse_proxy: "{{ '{{' }}upstreams 80{{ '}}'}}" + + jellyfin: + image: lscr.io/linuxserver/jellyfin:latest + container_name: jellyfin + networks: + - caddy + environment: + - PUID={{ arrstack_puid }} + - PGID={{ arrstack_pgid }} + - TZ={{ arrstack_tz }} + - UMASK_SET={{ arrstack_umask_set }} + devices: + - /dev/dri:/dev/dri + #environment: + #- JELLYFIN_PublishedServerUrl=192.168.0.5 #optional + volumes: + - "{{ arrstack_env_dir }}/config/jellyfin:/config" + - "{{ arrstack_env_dir }}/data/jellyfin:/config/data" + - "/mnt/ext/data/media/movies:/media/movies" # FIXME: To be changed? + - "{{ arrstack_data_dir }}/media/tv:/media/tv" + - "{{ arrstack_data_dir }}/media/music:/media/music" + ports: # FIXME: how to enable discovery behind proxies? + - 7359:7359/udp #optional - network discovery + - 1900:1900/udp #optional - dlna discovery + restart: unless-stopped + labels: + caddy: "http://media.pichi.berlin" + caddy.reverse_proxy: "{{ '{{' }}upstreams 8096{{ '}}'}}" + + gonic: + image: sentriz/gonic:latest + networks: + - caddy + environment: + - PUID={{ arrstack_puid }} + - PGID={{ arrstack_pgid }} + - TZ={{ arrstack_tz }} + - UMASK_SET={{ arrstack_umask_set }} + volumes: + - "{{ arrstack_env_dir }}/data/gonic:/data" + - "{{ arrstack_env_dir }}/data/gonic_playlists:/playlists" + - "/srv/media/music:/music:ro" + - "/srv/media/podcasts:/podcasts" + #- /path/to/cache:/cache # transcode / covers / etc cache dir + labels: + caddy: "http://music.pichi.berlin" + caddy.reverse_proxy: "{{ '{{' }}upstreams 80{{ '}}'}}" + + +networks: + caddy: + external: true + +volumes: + caddy_data: {}