homelab-blueprint/docs/DEPLOYMENT.md

5.6 KiB

Proxmox LXC arr-stack Deployment

This walkthrough deploys the arr stack inside a Docker LXC. While unprivileged is the security default, this guide assumes a Privileged LXC if you intend to use NVIDIA GPU acceleration for Emby.

  • app configs and SQLite databases on local LXC disk at /opt/arr-stack/appdata;
  • downloads and media on a UniFi UNAS Pro NFS share;
  • NFS mounted only on the Proxmox host;
  • the NFS-backed directory bind-mounted into the LXC at /mnt/unas/arr_data;
  • the full shared root visible to Radarr and Sonarr at /data.

Privileged vs Unprivileged

  • Privileged (Recommended for GPU): Required for seamless NVIDIA driver access and CUDA compute. Root inside the LXC maps directly to root on the host.
  • Unprivileged (Standard Security): Safer, but requires complex UID mapping for GPU and NFS write access.

The storage path is:

UNAS NFS export
  -> Proxmox host: /mnt/unas/arr_data
  -> LXC: /mnt/unas/arr_data
  -> Docker containers: /data

Do not start the Compose stack until the storage verification steps pass.

Values Used in This Guide

Replace these examples with your real values:

Name Example Meaning
UNAS_IP 10.0.10.20 UNAS Pro IP address
PVE_IP 10.0.10.10 Proxmox host IP allowed by the UNAS
VMID 120 Docker LXC container ID
NFS_EXPORT /volume1/.srv/.unifi-drive/Media/.data Real export from showmount
HOST_DATA /mnt/unas/arr_data NFS mountpoint on Proxmox
LXC_DATA /mnt/unas/arr_data Bind-mount destination inside the LXC
CONFIG_ROOT /opt/arr-stack/appdata Local LXC config path
PUID:PGID 1000:1000 Identity used by the containers

Run Proxmox commands from the Proxmox shell as root. Run LXC commands after entering the LXC with pct enter 120.

1. Enable NFS on the UNAS

Why: the Proxmox host needs permission to mount the shared drive. The LXC must not mount NFS itself.

  1. Open the UniFi Drive web interface for the UNAS.
  2. Create or select the shared drive that will contain the arr data, for example Media.
  3. Enable NFS for that shared drive.
  4. Add the Proxmox host IP, for example 10.0.10.10, to the NFS allowed clients/hosts list. Do not add only the LXC IP because Proxmox is the NFS client.
  5. Grant that client read/write access.
  6. Save/apply the NFS settings.

2. Discover the Real NFS Export Path

On the Proxmox host, install the NFS client tools:

apt update
apt install -y nfs-common

Set the UNAS address and list its exports:

UNAS_IP=10.0.10.20
showmount -e "$UNAS_IP"

Copy the exact export path (e.g., /volume1/.srv/.unifi-drive/Media/.data).

3. Mount NFS on the Proxmox Host

Set the values for this shell session:

UNAS_IP=10.0.10.20
NFS_EXPORT=/volume1/.srv/.unifi-drive/Media/.data
HOST_DATA=/mnt/unas/arr_data

Create the empty host mountpoint:

mkdir -p "$HOST_DATA"

Back up and edit /etc/fstab:

nano /etc/fstab

Add one line:

10.0.10.20:/volume1/.srv/.unifi-drive/Media/.data /mnt/unas/arr_data nfs vers=4.1,noatime,nofail,_netdev,x-systemd.automount,x-systemd.mount-timeout=10s 0 0

Apply and verify:

systemctl daemon-reload
mount -a
findmnt "$HOST_DATA"

4. Bind Mount the Host Path into the LXC

Stop the LXC before changing mountpoints:

VMID=120
pct stop "$VMID"

Confirm the LXC is configured correctly (privileged if using GPU):

pct config "$VMID"

Bind mount the host path:

pct set "$VMID" -mp0 /mnt/unas/arr_data,mp=/mnt/unas/arr_data

Start and enter the LXC:

pct start "$VMID"
pct enter "$VMID"

5. Understand UID/GID Mapping

Why: In a Privileged LXC, mapping is 1:1. UID 1000 inside the LXC is UID 1000 on the host. In an Unprivileged LXC, IDs are shifted.

This guide assumes container/LXC user 1000:1000.

Inside the LXC, create the user if it does not exist:

groupadd --gid 1000 arrstack
useradd --uid 1000 --gid 1000 --create-home --shell /bin/bash arrstack

Set ownership on the NFS-backed arr data from the Proxmox host:

chown -R 1000:1000 /mnt/unas/arr_data

Verify write access inside the LXC:

su -s /bin/sh -c 'touch /mnt/unas/arr_data/.lxc-write-test && rm /mnt/unas/arr_data/.lxc-write-test' arrstack

6. Prepare Local Config and Shared Data

Create local config directories on the LXC root disk:

CONFIG_ROOT=/opt/arr-stack/appdata
mkdir -p "$CONFIG_ROOT"/{gluetun,qbittorrent,sabnzbd,prowlarr,radarr,sonarr,bazarr,emby,seerr,recyclarr,unpackerr}
chown -R 1000:1000 /opt/arr-stack

Create the TRaSH-style shared directory tree:

su -s /bin/bash -c 'mkdir -p /mnt/unas/arr_data/torrents/{movies,tv} /mnt/unas/arr_data/usenet/{incomplete,complete/{movies,tv}} /mnt/unas/arr_data/media/{movies,tv}' arrstack
touch /mnt/unas/arr_data/.arr-stack-storage
chown 1000:1000 /mnt/unas/arr_data/.arr-stack-storage

7. Configure Paths Inside the Applications

All applications must use paths under the same /data prefix for hardlinks to work.

Application Path
qBittorrent /data/torrents/movies, /data/torrents/tv
SABnzbd /data/usenet/incomplete, /data/usenet/complete
Radarr /data/media/movies
Sonarr /data/media/tv
Bazarr / Emby /data/media/movies, /data/media/tv

Import a torrent through Radarr or Sonarr, then check the link count:

stat -c '%h %n' /mnt/unas/arr_data/torrents/movies/<file> /mnt/unas/arr_data/media/movies/<file>

A link count of 2 proves the hardlink is working.