Home Lab Command School
Everything you need to know to run your R720xd stack.
Pick a system below to start learning.
Proxmox
VM management, storage, networking, snapshots, and the shell commands you'll live in.
TrueNAS
ZFS pools, datasets, snapshots, scrubs, and how to manage your 24 drive bays.
Docker
Containers, images, compose, volumes, networks. The full lifecycle from pull to destroy.
Portainer
CLI tricks that work alongside the Portainer UI. Deploy stacks, manage agents, reset access.
Container-Specific
Jellyfin, Nextcloud, Pi-hole, Nginx PM, Frigate, Open WebUI, Navidrome, Calibre Web.
Linux Core
The fundamental shell skills that underpin everything else. Files, permissions, networking, processes.
Proxmox Commands
Run these in the Proxmox Shell (node shell, not inside a VM). Most use the qm and pct CLI tools.
100 TrueNAS running 8192 32.00 12445
101 docker-host running 4096 32.00 12891
qm list. Can also do this from the web UI — CLI is faster once you know your IDs.qm shutdown 100 for a clean OS shutdown. Hard stop risks filesystem corruption on non-journaled drives.qm listsnapshot 100 # list all snapshots
qm rollback 100 before-update # revert to snapshot
qm delsnapshot 100 before-update # delete snapshot
--storage flag specifies where to save. Check your storage names with pvesm status.vzdump 100 101 102 --storage local # backup multiple VMs
pve with your node name. Check the web UI top-right for your node name if unsure.sed -i 's/^deb/#deb/' /etc/apt/sources.list.d/pve-enterprise.list
echo "deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription" > /etc/apt/sources.list.d/pve-no-sub.list
systemctl restart pvedaemon # restart the main Proxmox daemon
pct.pct stop 200 # stop container
pct enter 200 # shell INTO the container
pct exec 200 -- bash # alternative shell access
TrueNAS Commands
Run in TrueNAS Shell (web UI → System → Shell) or SSH into the TrueNAS VM. ZFS is the filesystem underneath everything.
zpool status -v # verbose — shows errors per drive
zpool status tank # check progress (look for "scrub in progress")
zpool scrub -s tank # stop a running scrub
zfs list -r tank # recursive — shows children
zfs destroy tank/media@snap1 # delete a snapshot
zfs diff tank/media@snap1 # see what changed since snapshot
zfs get all tank/media | grep compress # check compression settings
smartctl -t long /dev/sda # run a long self-test (hours)
smartctl -H /dev/sda # just show PASSED/FAILED
zpool status.Docker Commands
Run these in any Linux shell where Docker is installed — your Docker VM, or the Proxmox host if you install Docker directly.
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" # cleaner output
docker kill jellyfin # immediate kill (SIGKILL)
docker restart jellyfin # stop + start in one command
-f flag means "follow" — live stream. Hit Ctrl+C to stop following. This is how you debug a container that's not working right.docker logs -f --tail 100 jellyfin # follow last 100 lines
docker logs jellyfin 2>&1 | grep ERROR # filter for errors
-it = interactive + tty. bash can be replaced with sh if the container doesn't have bash installed.docker exec -it jellyfin sh # if no bash
docker exec jellyfin ls /config # run one command without interactive
docker container prune # remove ALL stopped containers
docker rmi jellyfin/jellyfin # remove an image
docker image prune -a # remove ALL unused images (frees space)
docker compose up -d.docker compose up -d # recreate containers with new images
docker image prune # clean up old image layers
docker-compose.yml. -d = detached (runs in background). This is the main command you'll use to bring up your whole stack.docker compose up -d jellyfin # start only one service
docker compose up -d --force-recreate # force recreate even if nothing changed
docker compose stop # stops but doesn't remove containers
docker compose logs --tail 50 # last 50 lines from all services
docker ps which shows everything, this only shows what's in the current compose file. More focused view.docker volume rm jellyfin_config # ⚠️ delete volume — data gone
docker volume prune # remove all unused volumes
docker network inspect homelab # see connected containers + IPs
docker network connect homelab jellyfin # add container to network
docker system prune -a # ⚠️ removes ALL unused images
docker system prune -a -f # no confirmation prompt
htop but for containers. See which one is eating all your RAM. Hit Ctrl+C to exit.docker stats --no-stream # one snapshot, then exit
Portainer Commands
Portainer is mostly a web UI, but these CLI commands handle install, reset, and the things the UI can't do.
docker run -d \
-p 8000:8000 \
-p 9443:9443 \
--name portainer \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer-ce:latest
docker rm portainer
docker pull portainer/portainer-ce:latest
# then re-run the install command above
docker stop portainer
# Reset password to "newpassword"
docker run --rm \
-v portainer_data:/data \
portainer/portainer-ce:latest \
--admin-password='$2y$05$yourbcrypthash'
# Easier: just nuke the data volume and start fresh
docker rm portainer
docker volume rm portainer_data
docker volume create portainer_data
# then re-run install command
/opt/stacks/ (or similar). You can manage them from CLI too — useful if Portainer is down. The UI and CLI are interchangeable.jellyfin/compose.yml
nextcloud/compose.yml
pihole/compose.yml
nginx-proxy-manager/compose.yml
Service Commands
Common commands, configs, and fixes for each service in your stack.
chown -R 1000:1000 /mnt/media
chmod -R 755 /mnt/media
jellyfin:
image: lscr.io/linuxserver/jellyfin:latest
environment:
- PUID=1000
- PGID=1000
volumes:
- /opt/appdata/jellyfin:/config
- /mnt/media:/media
ports:
- 8096:8096
restart: unless-stopped
occ is Nextcloud's built-in admin tool. You use it for everything that can't be done in the web UI.docker exec -it --user www-data nextcloud php occ [command]
# Common occ commands
... php occ status # health check
... php occ maintenance:mode --on # enable maintenance mode
... php occ maintenance:mode --off # disable it
... php occ files:scan --all # scan for new files added directly to disk
... php occ user:list # list all users
... php occ upgrade # run after updating the image
docker exec -it pihole pihole restartdns # restart DNS resolver
docker exec -it pihole pihole updateGravity # update block lists
docker exec -it pihole pihole -q google.com # test if domain is blocked
docker exec -it pihole pihole whitelist add google.com # unblock a site
docker exec -it pihole pihole blacklist add annoying.com # block a site
Password: changeme
# Or use DNS challenge (works behind NAT)
docker exec -it nginx-proxy-manager certbot renew --dry-run
docker exec -it ollama ollama pull llama3 # download a model
docker exec -it ollama ollama rm llama3 # delete a model
docker exec -it ollama ollama run llama3 "say hello" # test a model
# Open WebUI env var should be:
OLLAMA_BASE_URL=http://ollama:11434 # uses container name, not IP
-show_streams "rtsp://192.168.x.x:554/stream1"
docker exec -it frigate frigate --help
docker logs frigate | grep -i "detector"
Password: admin123
- /opt/appdata/calibre-web:/config
- /mnt/books:/books # point to your books folder
navidrome:
image: deluan/navidrome:latest
volumes:
- /opt/appdata/navidrome:/data
- /mnt/music:/music:ro # ro = read-only, safe for music
ports:
- 4533:4533
environment:
ND_MUSICFOLDER: /music
ND_DATAFOLDER: /data
Linux Shell Commands
The foundation. Everything in your stack runs on Linux. Know these and everything else makes more sense.
ls -lt # sort by modification time (newest first)
cd .. # go up one level
cd - # go back to where you just were
pwd # print where you currently are
head -20 file.txt # print first 20 lines
tail -20 file.txt # print last 20 lines
tail -f /var/log/syslog # follow a log file live
Ctrl+X # Exit
Ctrl+K # Cut a line
Ctrl+U # Paste
Ctrl+W # Search
rm -rf /opt/old-folder/ # ⚠️ delete folder and everything in it
cp -r /source /dest # copy folder recursively
mv /old/path /new/path # move or rename
chown -R 1000:1000 /mnt/media # set owner recursively
chmod -R 755 /mnt/media # rwxr-xr-x permissions
ls -la /mnt/media # check who owns files
top. Colorful, sortable, you can kill processes from it. F10 or Q to quit.free -h # quick RAM usage check
df -h # disk space on all mounts
uptime # how long system has been running
systemctl start docker # start it
systemctl stop docker # stop it
systemctl restart docker # restart it
systemctl enable docker # start on boot
systemctl disable docker # don't start on boot
ip route # show routing table (gateway)
ping -c 4 8.8.8.8 # test internet connectivity
ping -c 4 192.168.1.1 # test gateway reachability
nmap -sP 192.168.1.0/24 # scan for all devices on LAN
ss -tulpn # show open ports and what's listening
curl -I http://localhost:8096 # test if a web service is responding
ssh -p 2222 user@192.168.1.100 # custom port
ssh-keygen -t ed25519 # generate SSH key pair
ssh-copy-id user@192.168.1.100 # copy public key (no more passwords)
grep -v "debug" file.log # exclude lines with "debug"
docker logs jellyfin | grep -i error # filter Docker logs
cat file.txt | grep -c "warning" # count matches