/
/
/
Ansible role that provisions my storage server.
1---
2# Storage Services - Arr Stack (Sonarr, Radarr, Prowlarr, Readarr + 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: '0775'
11 loop:
12 - "{{ arr_config_dir }}"
13 - "{{ sonarr_config_dir }}"
14 - "{{ radarr_config_dir }}"
15 - "{{ prowlarr_config_dir }}"
16 - "{{ readarr_config_dir }}"
17 - "{{ jellyseer_config_dir }}"
18 - "{{ gluetun_config_dir }}"
19 tags:
20 - storage
21 - arr-stack
22 - directories
23
24- name: Set group sticky bit on Arr Stack directories for permission inheritance
25 file:
26 path: "{{ item }}"
27 state: directory
28 mode: "g+s"
29 loop:
30 - "{{ arr_config_dir }}"
31 - "{{ sonarr_config_dir }}"
32 - "{{ radarr_config_dir }}"
33 - "{{ prowlarr_config_dir }}"
34 - "{{ readarr_config_dir }}"
35 - "{{ jellyseer_config_dir }}"
36 tags:
37 - storage
38 - arr-stack
39 - permissions
40
41- name: Generate Arr Stack environment file
42 template:
43 src: arr-stack.env.j2
44 dest: "{{ arr_config_dir }}/.env"
45 owner: "{{ storage_user }}"
46 group: "{{ storage_group }}"
47 mode: '0600'
48 notify: restart arr-stack
49 tags:
50 - storage
51 - arr-stack
52 - config
53 - env
54
55- name: Deploy Arr Stack Docker Compose file
56 template:
57 src: arr-stack-compose.yml.j2
58 dest: "{{ arr_config_dir }}/docker-compose.yml"
59 owner: "{{ storage_user }}"
60 group: "{{ storage_group }}"
61 mode: '0664'
62 notify: restart arr-stack
63 tags:
64 - storage
65 - arr-stack
66 - config
67 - compose
68
69- name: Start Arr Stack services
70 community.docker.docker_compose_v2:
71 project_src: "{{ arr_config_dir }}"
72 state: present
73 register: arr_start_result
74 tags:
75 - storage
76 - arr-stack
77 - deploy
78
79- name: Wait for VPN connection if enabled
80 pause:
81 seconds: 30
82 when: gluetun_enabled
83 tags:
84 - storage
85 - arr-stack
86 - vpn
87
88- name: Verify Arr Stack services are running
89 uri:
90 url: "http://localhost:{{ item.port }}"
91 method: GET
92 status_code: [200, 302]
93 register: arr_health
94 retries: 10
95 delay: 5
96 until: arr_health.status in [200, 302]
97 ignore_errors: true
98 loop:
99 - { name: "Sonarr", port: "{{ sonarr_port }}" }
100 - { name: "Radarr", port: "{{ radarr_port }}" }
101 - { name: "Prowlarr", port: "{{ prowlarr_port }}" }
102 - { name: "Readarr", port: "{{ readarr_port }}" }
103 - { name: "Jellyseer", port: "{{ jellyseer_port }}" }
104 when: arr_stack_enabled
105 tags:
106 - storage
107 - arr-stack
108 - validation
109 - health-check
110
111- name: Display Arr Stack deployment summary
112 debug:
113 msg: |
114 Arr Stack Deployment:
115 - Status: {{ 'Started' if arr_start_result is changed else 'Already running' }}
116 - VPN: {{ 'Enabled via Gluetun' if gluetun_enabled else 'Disabled' }}
117
118 Services:
119 {% if sonarr_enabled %}
120 - Sonarr (TV Shows): http://{{ ansible_default_ipv4.address }}:{{ sonarr_host_port }}
121 {% endif %}
122 {% if radarr_enabled %}
123 - Radarr (Movies): http://{{ ansible_default_ipv4.address }}:{{ radarr_host_port }}
124 {% endif %}
125 {% if prowlarr_enabled %}
126 - Prowlarr (Indexers): http://{{ ansible_default_ipv4.address }}:{{ prowlarr_host_port }}
127 {% endif %}
128 {% if readarr_enabled %}
129 - Readarr (Books): http://{{ ansible_default_ipv4.address }}:{{ readarr_host_port }}
130 {% endif %}
131 {% if jellyseer_enabled %}
132 - Jellyseer (Requests): http://{{ ansible_default_ipv4.address }}:{{ jellyseer_host_port }}
133 {% endif %}
134
135 Directories:
136 - Configuration: {{ arr_config_dir }}
137 - Downloads: {{ arr_downloads_dir }}
138
139 Next Steps:
140 1. Configure VPN credentials in encrypted vault
141 2. Set up indexers in Prowlarr
142 3. Configure quality profiles in each Arr app
143 4. Add root folders for media types
144 5. Configure download client settings
145 6. Set up Jellyseer with Jellyfin integration
146 tags:
147 - storage
148 - arr-stack
149 - summary