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
This commit is contained in:
Marty Oehme 2025-07-14 10:01:19 +02:00
parent 93ae62dc93
commit 2045f4ae58
Signed by: Marty
GPG key ID: 4E535BC19C61886E
3 changed files with 254 additions and 129 deletions

View file

@ -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

View file

@ -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

View file

@ -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: {}