Working notes from running a Proxmox box at home. This part covers containers and host setup; disks are in Adding and Passing Through Disks on Proxmox, and the actual services are in Self-Hosting Services in Proxmox LXCs.

Terminology, because Proxmox assumes you know it

The docs and forum posts throw these around freely:

TermMeaning
PVPhysical volume — a block device (or part of one) where data really lives
VGVolume group — one or more PVs grouped together
LVLogical volume — a volume stored on a VG
thin poolVolumes that can hold LVs without allocating full size upfront
lxcLinux container
pctProxmox Container Toolkit — the CLI for LXC containers
pveProxmox Virtual Environment — the host itself

LXC or VM?

For running Docker containers, both work. The difference is overhead.

A VM gets a fixed memory allocation whether it’s using it or not. An LXC container shares the host kernel and only consumes what it actually needs, so total system resource use is meaningfully lower.

I run Docker inside LXC. This walkthrough covers both approaches if you want to compare.

The catch: LXC needs nesting=1 to run Docker, and unprivileged containers occasionally trip over permissions that a VM wouldn’t. For a home server that trade is worth it. For anything where isolation is a security boundary, use a VM.

Host post-install

First thing on a fresh install, run the community post-install script. It disables the enterprise repo, stops the subscription nag, and applies sensible defaults:

bash -c "$(wget -qLO - https://github.com/tteck/Proxmox/raw/main/misc/post-pve-install.sh)"

Then the shell, because the default root bash on Proxmox is bare. This .bashrc is a good starting point.

# zoxide, for jumping around
curl -sS https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh | bash
echo eval "$(zoxide init bash)" >> .bashrc

# stop the UTF-8 warnings
echo export LC_CTYPE=en_US.UTF-8 >> .bashrc
echo export LC_ALL=en_US.UTF-8 >> .bashrc

apt-get install -y powertop samba mc tmux

curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o ~/.local/bin/yt-dlp
chmod a+rx ~/.local/bin/yt-dlp

Power draw

If the box runs 24/7, it’s worth knowing what it costs you. powertop will write a full report:

powertop --html=report.html

This homelab thread is a good reference for what idle figures are actually achievable.

Creating a container

pveam manages templates. Grab a Debian 12 template:

pveam update
LX=`pveam available | grep debian-12-standard | sed 's/system\s*//g'`
pveam download local $LX

Templates land in /var/lib/vz/template/iso.

Then create and start the container. Note nesting=1 — without it Docker won’t run inside:

ID=103

pct create $ID "local:vztmpl/$LX" \
  --unprivileged 1 \
  -features nesting=1 \
  --net0 name=eth0,bridge=vmbr0,firewall=1,ip=dhcp,type=veth \
  --storage local-lvm

nano /etc/pve/lxc/$ID.conf   # any extra config, e.g. mount points

pct start $ID
sleep 10
pct enter $ID

Inside the container, the first-run ritual:

passwd root
passwd -u root       # the template ships with root locked

apt update
apt dist-upgrade -y
apt install curl -y

echo export LC_CTYPE=en_US.UTF-8 >> .bashrc
echo export LC_ALL=en_US.UTF-8 >> .bashrc

pct commands worth remembering

pct enter 102                          # shell into a container
pct exec 102 -- bash -c 'apk update && apk upgrade'   # run a command (Alpine here)
pct pull 102 /root/site.tar.gz /root/site.tar.gz      # copy a file out
pct resize 102 rootfs 20G              # grow the root disk
pct set 105 -mp0 /media/seagate/,mp=/data              # add a bind mount

Anything set with pct set also lands in /etc/pve/lxc/<ID>.conf, so you can edit it there instead:

mp0: /media/seagate/,mp=/data

Debugging a container that won’t start

pct start failing tells you almost nothing. Start it in the foreground with debug logging instead:

lxc-start -n 101 -F -lDEBUG -o lxc-101.log

Finding container IPs

Three ways, in increasing order of effort:

lxc-info -i -n 110              # from the host, per container

Or from the router: DHCP → DHCP client list for leases, IP & MAC → ARP list for what’s currently reachable.

Check a port is actually bound before blaming the network:

ss -tulpen | grep 9090

Errors I hit

Temporary failure in name resolution

Container has no DNS. Fix /etc/resolv.conf:

search .
nameserver 1.1.1.1

Forum thread with the longer discussion.

SSH to the host

Nothing to configure — SSH is already running on a Proxmox host, log in with root credentials. What you usually want is to stop typing the password:

ssh-keygen -R 192.168.1.100     # clear a stale host key after a reinstall
ssh-copy-id -i ~/.ssh/paul.pub root@192.168.1.100

Other things I’ve bookmarked