I recently moved to a new apartment. First things first, of course I had to setup a new homelab. More compute, more space, better networking. Initially I planned on buying the performant ‘Minisforum MS-01’. However, ram-prices have since skyrocketed and I could not justify the cost of this setup. Instead, I looked on the second hand market and found the following:
Proxmox Server Setup
- HP Prodesk 600 G5 8 x Intel(R) Core(TM) i7-9700 CPU
- 32 GB Memory
- 1 TB nvme (~ CHF 400)
Additionally I will install the two SSDs from my old server:
- 2x2TB SATA SSD
As well as four 4TB Harddrives I bought of Ricardo:
- 4x4TB HDD (~ CHF 350)
On the old server, I had Truenas Scale installed. It served me well. Truenas hides some complexity with its sleek UI. This especially helps in the beginning. For the new setup however, I opt for Proxmox. I find it offers more control and transparency than Truenas and can be set up in a more flexible way. Also, at work I have to do with Proxmox so it poses a good learning opportunity.
My final setup offes decent compute with eight 9th generation Intel-cores, 32 GB DDR4 memory and a total of 21TB bare storage, of which around 13 will realistically be usable. The Intel iGPU will allow for efficient video transcoding. All this for around CHF 750. All parts second hand.
The following lines are my personal notes on the installation. They are primarily meant for me as a memory aid. However, they might be useful to someone else, so I post them here.
OS Installation
No surprises, no notes
Configuration
SSD ZFS POOL (Name: ‘hot’):
- Wipe SSDs over GUI (Node -> Disks)
- Create ZFS Pool (Node -> Disks -> ZFS -> Create ZFS) (Mirror over both ssds)
check:
zpool status
zfs list
zfs create hot/appdata
zfs create hot/immich
zfs create hot/shared
zfs create hot/documents
zfs create hot/backups
zfs create hot/media
resize recordsize for big-file-directories for better performance:
zfs set recordsize=1M ssdpool/immich
User Management and Permissions:
Decided to add one priviledged user (lkslba) and system users for each application:
On Conainer / VM:
adduser --system --group syncthing
adduser --system --group filebrowser
# etc
# create shared group
addgroup --gid 2000 data
# add syncthing to data group
usermod -aG data syncthing
On Host:
chown -R 102000:102000 /hot/shared # 10'000 + UID / GID of Container
chmod -R 775 /hot/shared
chmod g+s /hot/shared
Moving files onto the server:
# example
lsblk
mkdir -p /mnt/backup
mount /dev/sdc1 /mnt/backup
rsync -avh --progress /mnt/backup/shared/ /hot/shared/
umount /mnt/backup
Syncthing LXC:
Notes: use static IP adress out of DHCP range (router-settings). nice: end of ip-addr = container-number.
OS: Debian 13 Unprivileged: Yes Nesting: Yes CPU: 1 cores RAM: 1 GB Rootfs: on hot (8GB)
Add mount: Host path: /hot/shared Container path: /data CAUTION: Do not add the mount over the GUI unless you know what you do. If the container owns the mounted volume, it will be deleted when the container gets deleted. Better:
# add: 'mp0: /hot/shared,mp=/data'
vim /etc/pve/lxc/200.conf
Install Syncthing:
sudo apt update
sudo apt install -y syncthing
The syncthing user needs a dedicated home dir for syncthing to startup:
sudo mkdir -p /var/lib/syncthing
sudo chown -R syncthing:syncthing /var/lib/syncthing
sudo chmod 700 /var/lib/syncthing
sudo usermod -d /var/lib/syncthing syncthing
sudo systemctl enable --now syncthing@syncthing.service
sudo systemctl start syncthing@syncthing.service
# sudo systemctl reset-failed syncthing@syncthing.service
# sudo systemctl restart syncthing@syncthing.service
sudo systemctl status syncthing@syncthing.service --no-pager
Find and configure syncthing so it listens at the containers ip:
sudo -u syncthing syncthing -paths
sudo -u syncthing nano /var/lib/syncthing/.local/state/syncthing/config.xml # <address>127.0.0.1:8384</address> -> <address>0.0.0.0:8384</address>
sudo systemctl restart syncthing@syncthing.service
# Now enable lingering, so it runs even without login:
loginctl enable-linger syncthing
# check:
sudo -u syncthing systemctl --user status syncthing
Adguard
zfs create hot/adguard
chown -R 102000:102000 /hot/adguard
chmod -R 775 /hot/adguard
chmod g+s /hot/adguard
curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v
Set up Adguard on 192.168.1.201 and enable adguard as DHCP Server while disabling (!) the DHCP function on the router. The Zyxel ax7501 does firmware-wise not support third-party dns servers.
to verify on a linux-client:
sudo dhclient -r
sudo dhclient -v
ip route
cat /etc/resolv.conf
nslookup example.com
Jellyfin
root@falcon:~# zfs create hot/media
root@falcon:~# zfs create hot/jellyfin
root@falcon:~# zfs create hot/jellyfin/cache
root@falcon:/hot# chown -R 102000:102000 /hot/jellyfin
root@falcon:/hot# chown -R 102000:102000 /hot/media
root@falcon:/hot# chmod -R 775 /hot/media /hot/jellyfin/
Create CT
Template: Debian 12 Unprivileged: yes Nesting: enabled Keyctl: enabled
Resources
CPU: 4 cores RAM: 4096 MB Swap: 1024 MB Root disk: 32 GB
vim /etc/pve/lxc/202.conf
# mp0: /hot/media,mp=/media
# mp1: /hot/jellyfin,mp=/config
# mp2: /hot/jellyfin/cache,mp=/cache
groupadd -g 2000 data || true
usermod -aG data jellyfin
Enable iGPU passthrough (Intel)
https://diymediaserver.com/post/jellyfin_intel_quicksync_unprivileged_lxc/
set non free firmware repo for host and container:
root@falcon:~# cat /etc/apt/sources.list.d/debian.sources
Types: deb
URIs: http://deb.debian.org/debian/
Suites: trixie trixie-updates
Components: main contrib non-free non-free-firmware
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
Types: deb
URIs: http://security.debian.org/debian-security/
Suites: trixie-security
Components: main contrib non-free non-free-firmware
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
apt update
apt install intel-gpu-tools vainfo intel-media-va-driver-non-free
vainfo | grep -i enc
echo "i915" >> /etc/modules
modprobe i915
ls /dev/dri
#card0
#renderD128
vim /etc/pve/lxc/202.conf
#lxc.cgroup2.devices.allow: c 226:0 rwm
#lxc.cgroup2.devices.allow: c 226:128 rwm
#lxc.mount.entry: /dev/dri dev/dri none bind,optional,create=dir
# lxc.idmap: u 0 100000 65536
# lxc.idmap: g 0 100000 992
# lxc.idmap: g 992 993 1
# lxc.idmap: g 993 100993 64543
pct restart 202
curl https://repo.jellyfin.org/install-debuntu.sh | sudo bash
What These Lines Do lxc.cgroup2.devices.allow - Grants permission to access specific device nodes lxc.mount.entry - Bind mounts the entire /dev/dri directory into the container
Host render group Host render GID = 993
Container render group Container render GID = 992
Authorization (Host) File: /etc/subgid root:993:1
ID Mapping (Container Config) lxc.idmap: u 0 100000 65536 lxc.idmap: g 0 100000 992 lxc.idmap: g 992 993 1 lxc.idmap: g 993 100993 64543
Result: Host render group successfully mapped into unprivileged container
Jellyfin Configuration Dashboard → Playback → Transcoding
Hardware acceleration: VAAPI VAAPI device: /dev/dri/renderD128
Hardware decode: enabled Hardware encode: enabled
Runtime Confirmation Forced a transcode in Jellyfin Observed Video engine activity via: intel_gpu_top CPU usage dropped significantly Jellyfin logs confirmed VAAPI usage
immich
Set up immich on Docker inside a Ubuntu 24.04 Server VM.
Machine: q35 Bios: UEFI EFI Storage:local-lvm QEMU Agent: yes!
Storage Architecture: root disk on local-lvm (100GiB). Later ‘bind’ to zfs pool /hot/docker/immich using virtio.
start Container, setup Ubuntu, then
sudo apt update
sudo apt upgrade
sudo apt install -y qemu-guest-agent
sudo systemctl enable --now qemu-geust-agent
sudo systemctl status qemu-guest-agent
sudo mkdir -p /mnt/immich /mnt/paperless
Now we have to setup proxmox virtio in order to access /hot/docker/xy from our vm. helpful: https://forum.proxmox.com/threads/proxmox-8-4-virtiofs-virtiofs-shared-host-folder-for-linux-and-or-windows-guest-vms.167435/
On the host:
apt install acl
zfs create hot/docker
zfs create hot/docker/immich
zfs create hot/docker/paperless
chown -R root:2000 /hot/docker
chmod -R 2775 /hot/docker
setfacl -R -m g:2000:rwx /hot/docker
setfacl -R -d -m g:2000:rwx /hot/docker
# should resemble drwxrwxr-x+ root 2000 immich
zfs set xattr=sa hot/docker
zfs set acltype=posixacl hot/docker
zfs set atime=off hot/docker
zfs set sync=disabled hot/docker
Then in the Proxmox Web UI : Datacenter → Directory Mappings → Add
| Name (TAG) | Path |
|---|---|
| DOCKER_IMMICH | /hot/docker/immich |
| DOCKER_PAPERLESS | /hot/docker/paperless |
Then, still in the Web UI : VM → Hardware → Add → VirtioFS For each share:
Directory ID: DOCKER_IMMICH (or DOCKER_PAPERLESS) I checked all boxes.
Then in the VM:
groupadd -g 2000 data
usermod -aG data lkslba #dockeruser
logout
login
# now try to mount the directories and test:
sudo mkdir -p /mnt/immich /mnt/paperless
sudo mount -t virtiofs DOCKER_IMMICH /mnt/immich
sudo mount -t virtiofs DOCKER_PAPERLESS /mnt/paperless
id
touch /mnt/immich/testfile
ls -ln /mnt/immich
if this worked, make persistent by changing /etc/fstab. add:
DOCKER_IMMICH /mnt/immich virtiofs defaults,nofail 0 0
DOCKER_PAPERLESS /mnt/paperless virtiofs defaults,nofail 0 0
reboot to check.
If this worked, storage is setup and we go on to setting up docker:
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Signed-By: /etc/apt/keyrings/docker.asc
EOF
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo mkdir -p /mnt/immich/{library,upload,thumbs,profile}
sudo chown -R root:2000 /mnt/immich
sudo chmod -R 2775 /mnt/immich
mkdir -p ~/immich
cd ~/immich
get the .env file and the docker-compose file from the immich website. adjust them so they use our mounted directories
docker compose pull
docker compose up -d
paperless ngx
on the same VM as immich
sudo mkdir -p /mnt/paperless/{consume,media,data,export}
sudo chown -R root:2000 /mnt/paperless
sudo chmod -R 2775 /mnt/paperless
consume = drop files here media = stored PDFs + originals data = app state (index, config, etc.) export = exports
Windows VM
RDP Connect:
xfreerdp3 korriban.rdp
Inside korriban.rdp:
❯ cat korriban.rdp
full address:s:192.168.1.28
username:s:rdpuser
domain:s:korriban
authentication level:i:2
enablecredsspsupport:i:1
dynamic resolution:i:1
desktopwidth:i:3440
desktopheight:i:1440
redirectclipboard:i:1
What remains:
Things I still have on my list and / or have to document:
- ARM (automatic ripping machine)
- Karakeep (bookmarks)
- Prometheus (monitoring)
- Grafana (graphs)
- Caddy (reverse proxy)
- copyparty (file-server)
For some of these tools, I will probably take advantage of the handy Proxmox helper-scripts collections.