/
/
/
Ansible role that provisions my storage server.
1---
2# Storage Services - Arr Stack (Sonarr, Radarr, Prowlarr, LazyLibrarian + Gluetun VPN)
3
4- name: Create Arr Stack configuration directory structure
5 file:
6 path: "{{ item }}"
7 state: directory
8 owner: "{{ storage_user }}"
9 group: "{{ storage_group }}"
10 mode: '2775'
11 loop:
12 - "{{ arr_config_dir }}"
13 - "{{ sonarr_config_dir }}"
14 - "{{ radarr_config_dir }}"
15 - "{{ prowlarr_config_dir }}"
16 - "{{ lazylibrarian_config_dir }}"
17 - "{{ bazarr_config_dir }}"
18 - "{{ jellyseer_config_dir }}"
19 - "{{ gluetun_config_dir }}"
20 - "{{ flaresolverr_config_dir }}"
21 - "{{ qbittorrent_config_dir }}"
22 - "{{ lidarr_config_dir }}"
23 - "{{ cleanuparr_config_dir }}"
24
25- name: Deploy LazyLibrarian custom Dockerfile
26 copy:
27 src: lazylibrarian/Dockerfile
28 dest: "{{ arr_config_dir }}/Dockerfile"
29 owner: "{{ storage_user }}"
30 group: "{{ storage_group }}"
31 mode: '0644'
32 when: lazylibrarian_enabled and lazylibrarian_custom_build | default(false)
33 notify: restart arr-stack
34
35- name: Generate Arr Stack environment file
36 template:
37 src: arr-stack.env.j2
38 dest: "{{ arr_config_dir }}/.env"
39 owner: "{{ storage_user }}"
40 group: "{{ storage_group }}"
41 mode: '0660'
42 notify: restart arr-stack
43
44- name: Deploy Arr Stack Docker Compose file
45 template:
46 src: arr-stack-compose.yml.j2
47 dest: "{{ arr_config_dir }}/docker-compose.yml"
48 owner: "{{ storage_user }}"
49 group: "{{ storage_group }}"
50 mode: '0664'
51 notify: restart arr-stack
52
53- name: Check if Arr Stack directory exists
54 stat:
55 path: "{{ arr_config_dir }}"
56 register: arr_dir_stat
57 changed_when: false
58
59- name: Start Arr Stack services
60 community.docker.docker_compose_v2:
61 project_src: "{{ arr_config_dir }}"
62 state: present
63 register: arr_start_result
64 check_mode: no
65 when: arr_dir_stat.stat.exists
66
67- name: Wait for VPN connection if enabled
68 pause:
69 seconds: 30
70 when: gluetun_enabled
71
72- name: Verify Arr Stack services are running
73 uri:
74 url: "http://localhost:{{ item.port }}"
75 method: GET
76 status_code: [200, 302, 401]
77 register: arr_health
78 retries: 10
79 delay: 5
80 until: arr_health.status in [200, 302, 401]
81 ignore_errors: true
82 loop:
83 - { name: "Sonarr", port: "{{ sonarr_host_port }}" }
84 - { name: "Radarr", port: "{{ radarr_host_port }}" }
85 - { name: "Prowlarr", port: "{{ prowlarr_host_port }}" }
86 - { name: "LazyLibrarian", port: "{{ lazylibrarian_host_port }}" }
87 - { name: "Bazarr", port: "{{ bazarr_host_port }}" }
88 - { name: "Jellyseer", port: "{{ jellyseer_host_port }}" }
89 - { name: "Flaresolverr", port: "{{ flaresolverr_host_port }}" }
90 - { name: "qBittorrent", port: "{{ qbittorrent_host_port }}" }
91 - { name: "Lidarr", port: "{{ lidarr_host_port }}" }
92 - { name: "Cleanuparr", port: "{{ cleanuparr_host_port }}" }
93 when: arr_stack_enabled
94
95- name: Display Arr Stack deployment summary
96 debug:
97 msg: |
98 Arr Stack Deployment:
99 - Status: {{ 'Started' if arr_start_result is changed else 'Already running' }}
100 - VPN: {{ 'Enabled via Gluetun' if gluetun_enabled else 'Disabled' }}
101
102 Services:
103 {% if sonarr_enabled %}
104 - Sonarr (TV Shows): http://{{ ansible_default_ipv4.address }}:{{ sonarr_host_port }}
105 {% endif %}
106 {% if radarr_enabled %}
107 - Radarr (Movies): http://{{ ansible_default_ipv4.address }}:{{ radarr_host_port }}
108 {% endif %}
109 {% if prowlarr_enabled %}
110 - Prowlarr (Indexers): http://{{ ansible_default_ipv4.address }}:{{ prowlarr_host_port }}
111 {% endif %}
112 {% if lazylibrarian_enabled %}
113 - LazyLibrarian (Books): http://{{ ansible_default_ipv4.address }}:{{ lazylibrarian_host_port }}
114 {% endif %}
115 {% if bazarr_enabled %}
116 - Bazarr (Subtitles): http://{{ ansible_default_ipv4.address }}:{{ bazarr_host_port }}
117 {% endif %}
118 {% if jellyseer_enabled %}
119 - Jellyseer (Requests): http://{{ ansible_default_ipv4.address }}:{{ jellyseer_host_port }}
120 {% endif %}
121 {% if flaresolverr_enabled %}
122 - Flaresolverr (Cloudflare): http://{{ ansible_default_ipv4.address }}:{{ flaresolverr_host_port }}
123 {% endif %}
124 {% if qbittorrent_enabled %}
125 - qBittorrent (Downloads): http://{{ ansible_default_ipv4.address }}:{{ qbittorrent_host_port }}
126 {% endif %}
127 {% if lidarr_enabled %}
128 - Lidarr (Music): http://{{ ansible_default_ipv4.address }}:{{ lidarr_host_port }}
129 {% endif %}
130 {% if cleanuparr_enabled %}
131 - Cleanuparr (Cleanup): http://{{ ansible_default_ipv4.address }}:{{ cleanuparr_host_port }}
132 {% endif %}
133
134 Directories:
135 - Configuration: {{ arr_config_dir }}
136 - Downloads: {{ arr_downloads_dir }}
137
138 Next Steps:
139 1. Configure VPN credentials in encrypted vault
140 2. Set up indexers in Prowlarr
141 3. Configure quality profiles in each Arr app
142 4. Add root folders for media types
143 5. Configure download client settings
144 6. Set up Jellyseer with Jellyfin integration
145