A Proxmox VE helper script to automate deployment and configuration of a basic containerized media automation stack focusing on automated API wiring, credential extraction, and simplified operator experience for self-hosted media libraries.
- Prowlarr (indexers)
- Sonarr (TV)
- Radarr (movies)
- Lidarr (music)
- Bazarr (subtitles)
- Seerr (requests)
- Jellyfin (media server)
- qBittorrent (Torrent client)
- SABnzbd (Usenet client)
- Gluetun VPN gateway (optional, opt-in) — see VPN Gateway
- Requests Welcome! Open a discussion to make a request or open a PR with your edits
Derived from @michelroegl-brunner's original community script idea.
- Fully interactive setup — Guided prompts for storage, networking, app selection, IP allocation
- Automatic template preparation — Reads the OS each upstream
ct/*.shdeclares and downloads any missing LXC template (the *arr apps are Debian-based, Jellyfin is Ubuntu-based) - Automatic deployment — Downloads and deploys container scripts with generated configuration
- Headless wiring — Connects Prowlarr → arr apps and download clients via HTTP APIs (no manual config)
- Bazarr integration — Wires Bazarr into each selected *arr app automatically
- Credential extraction — Auto-extracts API keys from all *arr apps and handles qBittorrent WebUI password setup
- Optional example indexer — Can seed Prowlarr with a public indexer (1337x), added disabled and behind an explicit warning prompt
- Validation — IPv4 validation, duplicate IP detection, port availability checks, collision detection
- Summary report — Full deployment details with URLs, credentials, and manual next steps (chmod 600)
- State file — Machine-readable record of every container built (
/root/installarr-state.conf, chmod 600), written on every run - Optional VPN gateway — Installs a Gluetun LXC and prepares an isolated bridge, leaving provider setup and the cutover to you
- Proxmox VE node with root access
- PVE tools:
pct,pvesh,pvesm,pveam - Utilities:
curl,whiptail(ordialog),jq,iputils-ping
To use this version, manually download to your PVE host and run it.
curl -fsSL https://raw.githubusercontent.com/JVKeller/arr-script/main/installarr.sh -o installarr.sh
bash installarr.shIt is highly recommended to use a VPN for your arr-stack traffic. To route it through one and keep your data private, choose the optional Gluetun VPN gateway container when prompted (see VPN Gateway).
Pre-configure settings to skip prompts:
var_container_storage=local-lvm \
var_template_storage=local \
var_bridge=vmbr0 \
var_gateway=192.168.1.1 \
var_cidr=24 \
var_vlan=20 \
var_start_ctid=100 \
var_qbt_password=MyStrongPassword \
INSTALL_MODE=advanced \
SUMMARY_FILE=/root/installarr-summary.txt \
STATE_FILE=/root/installarr-state.conf \
var_installarr_ref=main \
sudo bash installarr.sh- Install Mode —
defaultfor a flat untagged network, oradvancedto also set a VLAN tag - Storage & Network Selection — Choose container storage, template storage, network bridge, gateway, CIDR, and (advanced only) the VLAN tag applied to every container
- App Selection — Pick which *arr apps, media server, and download clients to install
- Example Indexer Prompt — Optionally seed Prowlarr with a disabled public indexer
- IP Assignment — Enter IPs for each container (interactive form or list mode)
- CTID Allocation — Set starting container ID (auto-increments for used IDs)
- Confirmation — Review full config before deployment
- Template Preparation — Verifies and downloads any LXC templates the selected apps require
- Installation — Downloads and deploys each container with progress gauge
- Credential Extraction — Waits for startup, extracts API keys
- API Wiring — Connects Prowlarr → Sonarr/Radarr/Lidarr, adds qBittorrent/SABnzbd to *arr apps, wires Bazarr
- Summary — Displays URLs, credentials, and manual next steps
- State — Writes
/root/installarr-state.confdescribing every container built
If the VPN gateway was selected, a prompt appears after app selection, the Gluetun container is installed alongside the others, and the isolated bridge is prepared. No other container is modified during the run.
Installs Gluetun in its own LXC and prepares an
uplink-less bridge (default vmbr1) for tunnelled traffic. Because that bridge has no
physical uplink, isolation is structural: if the tunnel drops there is no path to WAN at all,
without relying on firewall rules.
installarr.sh does not configure a VPN provider and does not move any container
behind the tunnel. There are too many providers to prompt for sensibly, and moving a container
onto an uplink-less bridge before a tunnel exists would leave it with no internet at all.
So when the installer finishes, the gateway is inert and bypassed. Every container still uses its normal LAN route and the stack is fully functional. You can test everything before touching the VPN.
The exact commands, with your CTIDs filled in, are written to the summary file. In short:
1. Configure your provider inside the Gluetun container:
pct exec <gluetun-ctid> -- nano /opt/gluetun-data/.env
pct exec <gluetun-ctid> -- chmod 600 /opt/gluetun-data/.envFirst remove the helper script's default OPENVPN_* and VPN_SERVICE_PROVIDER=custom
entries. Then set VPN_SERVICE_PROVIDER, VPN_TYPE, and your credentials. For WireGuard that
means WIREGUARD_PRIVATE_KEY and WIREGUARD_ADDRESSES.
WIREGUARD_ADDRESSESmust be the address and prefix from your provider's config (e.g.10.14.0.2/16). A hostname here is the single most common cause of Gluetun failing to start.Prefer
SERVER_COUNTRIESoverSERVER_HOSTNAMES— hostnames break whenever Gluetun refreshes its server list.
2. Confirm the tunnel came up:
pct exec <gluetun-ctid> -- systemctl restart gluetun
pct exec <gluetun-ctid> -- ip -o link | grep -E 'wg[0-9]|tun[0-9]'
pct exec <gluetun-ctid> -- journalctl -u gluetun -n 50 # if nothing matches3. Move the stack behind the tunnel:
/root/installarr-vpn.shReads /root/installarr-state.conf, and refuses to run until step 2 succeeds. For each
member it sets the default route to the gateway, keeps the LAN address on a second NIC for
management, points DNS at the gateway (clearing the inherited search domain, which can cause a
DNS loop), and staggers boot order. Then it verifies: one default route via the gateway,
reverse-path filtering, the management route service, DNS resolution, every member egressing
the same address as the gateway, no [dns] warnings or CPU spin in Gluetun, and a kill-switch
test that stops Gluetun and confirms nothing reaches WAN.
Safe to re-run at any time — every step is idempotent, and re-running is how you re-verify.
Pass -y to skip the confirmation prompt.
| Behind the VPN | Stays on the LAN |
|---|---|
| Prowlarr, Sonarr, Radarr, Lidarr, Bazarr | Jellyfin |
| qBittorrent, SABnzbd | Seerr |
Jellyfin and Seerr are consumer-facing — tunnelling them breaks remote access. Members keep their LAN address on a second NIC, so web UIs stay reachable and the API wiring between apps is unaffected.
Point each container's net0 back at the LAN bridge:
pct set <ctid> -net0 name=eth0,bridge=vmbr0,gw=<lan-gw>,ip=<lan-ip>/24,type=veth
pct set <ctid> -delete net1
pct set <ctid> -delete nameserver
pct set <ctid> -delete searchdomain
pct reboot <ctid>Status: the VPN gateway is new and has had no real-world testing yet. Every
pct,iptablesandsystemctlpath is unexercised. Feedback and bug reports welcome.
After provisioning:
- Prowlarr — Add indexers. If you accepted the example indexer, 1337x is present but disabled — verify you trust it before enabling via Settings → Indexers → 1337x → Enable
- Sonarr/Radarr/Lidarr — Set root folders and create quality profiles
- Bazarr (if selected) — Open
http://<ip>:6767and configure subtitle providers and languages - Jellyfin (if selected) — Open
http://<ip>:8096, complete the setup wizard, and configure library paths - SABnzbd (if selected) — Open web wizard at
http://<ip>:7777and complete setup - Seerr (if selected) — Open web wizard at
http://<ip>:5055, then add Sonarr/Radarr instances
The optional example indexer is a public indexer. Public indexers can surface malicious or mislabeled content. It is deliberately added in a disabled state and is never enabled automatically. Verify it is a legitimate indexer you trust before enabling it.
This script is one-time provisioning only — it is not designed to be re-run or auto-update.
However, each container can be updated independently via its own ProxmoxVE helper script:
Open the terminal on the container you want to update and simply type update
Each *arr container script is separately maintained by the community-scripts project and can be updated without affecting others.
installarr.sh— Main provisioning script (one-time use)installarr-vpn.func— Install-time VPN gateway support, fetched only if you opt ininstallarr-vpn.sh— Post-install cutover and verification, saved to/root//root/installarr-state.conf— Machine-readable record of the build (chmod 600)/root/installarr-summary.txt— Generated summary (created after successful run)/tmp/installarr-<pid>.log— Verbose log of suppressed command output
Check /tmp/installarr-<pid>.log for detailed error logs. Script will display the last 20 lines on exit.
The script checks the node's template catalog with pveam and downloads what the selected apps need. If a template is unavailable, confirm the node can reach the catalog and that the chosen template storage accepts vztmpl content.
Ensure containers are fully started and listening on their ports. Check container logs:
pct logs <ctid>pct exec <ctid> -- journalctl -u gluetun -n 50. The usual cause is WIREGUARD_ADDRESSES
set to a hostname instead of an address and prefix.
It found no wg/tun interface in the Gluetun container. That is deliberate — the VPN bridge
has no uplink, so converting containers without a tunnel would cut their internet entirely.
Finish the provider setup first.
Look for [dns] warnings: pct exec <gluetun-ctid> -- journalctl -u gluetun --since '5 minutes ago' | grep dns.
Every routed container and the gateway must have an empty search domain
(pct config <ctid> should show no searchdomain); re-run /root/installarr-vpn.sh to reapply it.
Check the container kept its LAN NIC: pct config <ctid> should show net1 on the LAN bridge
with no gw=. Only net0 carries a default route. If you use a management subnet, also check
pct exec <ctid> -- systemctl status mgmt-route.service; it retries until the LAN gateway is reachable.
The MSS clamp is missing. Run
pct exec <gluetun-ctid> -- systemctl restart gluetun-gw.service and confirm with
iptables -t mangle -S.
If the script detects a failure, the default adminadmin password remains active. Set manually via web UI.
Derived from community-scripts (MIT License).
When requesting help, include the log file from your pve server /tmp/installarr-<pid>.log for debugging output from failed deployments.