Server Setup (log)

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:

For some of these tools, I will probably take advantage of the handy Proxmox helper-scripts collections.

Tell me what you think: