Infrastructure

Home

Proxmox host running Debian 12 Bookworm with LXC containers, a QEMU VM, and two ZFS pools.


Storage Pools

Name Type Total Used Notes
tank ZFS 3.77 TB ~23% Primary data — host path /tank/, mounted as /mnt/tank/ inside containers
local-ssd dir 239 GB ~64% SSD (PCT 102 rootfs)
local-lvm lvmthin 354 GB ~17% LVM thin (PCT 108 rootfs)
local dir 98 GB ~34% Proxmox local storage

ZFS Notes

  • tank/appdata has acltype=posixacl enabled (2026-05-25). Use setfacl when a non-owner user needs access to files owned by a different UID:
    setfacl -R -m u:100000:rx /tank/appdata/nextcloud/data/data/nextcloud/files/obsidian
    setfacl -R -m u:1000:rx /tank/appdata/nextcloud/data/data/nextcloud/files/obsidian
    

LXC Mount Points

All containers: timezone: America/Toronto, onboot: 1. Default PUID/PGID: 1000:1000. Exceptions: nextcloud/firefly 33:33, guacamole/immich 0:0.

PCT 101 (downloads — 192.168.2.190)

Mount Host Container
mp2 /tank/appdata /mnt/tank/appdata

PCT 102 (media-core — 192.168.2.191)

Privileged container (unprivileged: 0). Full ZFS tank pool mounted.

Mount Host Container
mp0 /tank/ /mnt/tank/

Media library root: /mnt/tank/media/content/ — movies, tv, music, books, audiobooks, podcasts, comics, openbooks, roms, photos

Any Docker container without the media-core_ Swarm prefix is standalone. Standalone containers using mode: host ports can conflict with Swarm services — always check pct exec 102 -- docker ps before troubleshooting.

PCT 104 (documents — 192.168.2.105)

Privileged container. Only /tank/media and /tank/appdata/nextcloud are mounted — not the full tank.

Mount Host Container Notes
mp0 /tank/media /mnt/tank/media Media library
mp1 /mnt/media-storage /mnt/media-storage Separate media storage
mp2 /tank/appdata/nextcloud /mnt/tank/appdata/nextcloud Nextcloud data on ZFS (migrated 2026-05-25)
lxc.mount.entry /tank/docker tank/docker Docker storage on ZFS, not rootfs

PCT 107 (debian — 192.168.2.81)

Mount Host Container Notes
mp1 /tank/appdata/nextcloud/data/data/nextcloud/files/obsidian /mnt/obsidian Obsidian vault (ro)

Standalone containers on PCT 107:

Container Notes
archibus-scheduler-archibus-scheduler-1 Custom scheduler, no published ports

PCT 108 (network — 192.168.2.82)

Docker Swarm manager/leader. Appdata on rootfs (local-lvm, 50 GB, ~55% used) — NOT on ZFS. Portainer compose files at /mnt/tank/appdata/portainer/compose/ are on ZFS (mp0 mount).

Mount Host Container
mp0 /tank/ /mnt/tank/
  • Portainer stacks: /mnt/tank/appdata/portainer/compose/<id>/docker-compose.yml
  • Portainer data: network_portainer_data Docker volume (on rootfs)

PCT 109 (ai — 192.168.2.83)

Privileged container. Not a Swarm node. lxc.apparmor.profile: unconfined (required so docker build can run apparmor_parser). lxc.cgroup2.devices.allow: a.

Mount Host Container Notes
mp0 /tank/appdata/nextcloud/data/data/nextcloud/files/obsidian /mnt/obsidian Obsidian vault (read-write) for Hermes + n8n

Node.js 22 installed (via NodeSource) — required for mcp-server-filesystem.

PCT 300 (pterodactyl-panel — 192.168.2.136)

Pterodactyl Panel. Not a Swarm node. Services: apache2, mariadb, redis-server, pteroq.service (queue worker).

Always use explicit env to avoid inheriting TMPDIR=/tmp/claude-0 from Proxmox host shell (breaks MariaDB):

pct exec 300 -- env -i HOME=/root PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin TMPDIR=/tmp LANG=en_US.UTF-8 bash -c "..."

PCT 301 (pterodactyl-wings — 192.168.2.134)

Pterodactyl Wings daemon. Not a Swarm node. Game server data at /var/lib/pterodactyl/volumes/<uuid>/.

Local Docker registry at 192.168.2.134:5000 (container named registry, auto-restart).


GPU Passthrough

NVIDIA GPU passthrough configured for PCT 102, 104, and 109 via lxc.cgroup2.devices.allow and lxc.mount.entry in /etc/pve/lxc/<vmid>.conf. Key NVIDIA libs bind-mounted from the Proxmox host.

Container GPU Use
PCT 102 NVIDIA (media-core) Jellyfin transcoding, Immich ML
PCT 104 GTX 1050 Immich machine-learning (CUDA)
PCT 109 NVIDIA Whisper transcription

nvidia-container-toolkit installed in each. Default Docker runtime set to nvidia in /etc/docker/daemon.json. Runtime mode: legacy (not CDI) — CDI auto-detection fails in LXC because NVML can't init.

To enable GPU in a container:

environment:
  NVIDIA_VISIBLE_DEVICES: all
  NVIDIA_DRIVER_CAPABILITIES: all

No runtime: key needed — nvidia is already the default.

After a Proxmox host driver upgrade: update the versioned lib filenames in /etc/pve/lxc/<vmid>.conf to match the new driver version, chmod 755 the new versioned files, and reboot the affected container.


Home Assistant VM

QEMU VM 200 (haos16.3), 2 cores, 4 GB RAM, 32 GB disk (local-lvm), OVMF/q35. IP: 192.168.2.129. See Home Assistant for full details.

USB passthrough (in VM config):

  • 0a12:0001 — Bluetooth
  • 1a86:7523 — Zigbee stick
  • 303a:1001 — ESP32-C6 (added 2026-06-13)

Management Scripts (Proxmox host /root/)

Script Purpose
create-app-folders.sh Create /tank/appdata/<app> dirs with 1000:1000
setup-lxc-bind-mounts.sh Add ZFS bind mounts to LXC containers (DRY_RUN=false to apply)
create_lxc.sh <CTID> <HOST> <IP> Provision new Ubuntu 22.04 LXC
migrate-appdata-to-zfs.sh Migrate appdata from rootfs to ZFS dataset