Zkitszo - The Real
September 03, 2026

Note to Blog Post

Some information saved to notes... they'll get barried there- who am I kidding... thinking I'll revisit them. Looking at my Sticky Note application; so so so many- I may as well share.

A bonus? Maybe having these more visible... will help with my recollection...and I share with you, my readers.



Every homelab has the same problem: you set something up once, it works for two years, and then the day you need to touch it again your brain hands you nothing. This post is the fix — a running cheat sheet of the Linux commands and mini-recipes that are too small to deserve their own bookmark but too fiddly to retype from memory. Docker updates, reverse proxies with free SSL, disk setup, firewalls, fleet SSH, the works.

The short version: copy the block you need, swap in your own paths and names, move on with your life.

Update every Docker container at once

If your containers are defined in a Docker Compose file, updating all of them is one line. Your settings live on the host filesystem (that's what the volumes: mappings are for), not inside the container, so pulling a fresh image keeps all your config.

A Compose file is just a list of instructions so Docker sets everything up in one go instead of you typing run commands one by one. A couple of services from a real-world example, so you can see the shape of it:

name: optiplex

services:
  sabnzbd:
    image: lscr.io/linuxserver/sabnzbd:latest
    container_name: sabnzbd
    environment:
      - PUID=0
      - PGID=0
      - TZ=Australia/Victoria
    volumes:
      - /root/dockers/sabnzbd:/config
      - /storage:/downloads
      - /root/sabtmp:/incomplete-downloads
    ports:
      - 8080:8080
    restart: unless-stopped

  plex:
    image: plexinc/pms-docker:latest
    container_name: plex
    network_mode: host
    environment:
      - PLEX_UID=0
      - PLEX_GID=0
      - TZ=Australia/Victoria
    volumes:
      - /root/dockers/plex:/config
      - /storage:/storage
    devices:
      - /dev/dri:/dev/dri
    restart: unless-stopped

Same pattern for every extra service — image, name, environment, volumes, ports, restart: unless-stopped. Swap the TZ for your own timezone. (Running everything as root with PUID=0 works, but it's the lazy option — the linuxserver.io images are built to run as a normal user if you give them your own UID/GID.)

Then the actual update, all three moves chained together — pull the newest images, restart the containers on them, delete the old images to reclaim disk:

docker compose pull && docker compose up -d && docker image prune -af
  • One caveat on the prune. docker image prune -af deletes every image not currently used by a container, not just the ones you replaced. If you keep spare images around on purpose, drop that last part.
  • Auto-updates exist, but waiting is smarter. Tools like Watchtower will do this automatically when a new image is published, but running the command yourself means you can wait a few days and see if an update breaks things for other people first.

If Docker Compose somehow isn't installed (it almost always is), the official install instructions cover it.

Reverse proxy with free automatic SSL (Caddy)

You've got containers serving web UIs on random ports and you want real domain names with HTTPS. Caddy does this with a config file so short it feels like cheating — it talks to Let's Encrypt, gets certificates, and renews them, all without you doing anything.

Internet :80 / :443 Caddy HTTPS termination auto Let's Encrypt nzbhydra2 :5076 sonarr :8989

Add Caddy to your compose.yml (adjust the volume paths to wherever you want Caddy to keep its data):

caddy:
    image: caddy:latest
    container_name: caddy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - /home/youruser/caddy/caddy_data:/data
      - /home/youruser/caddy/caddy_config:/config
    restart: unless-stopped

volumes:
  caddy_data:
  caddy_config:

Create a file called Caddyfile next to it. First line is your domain (you need a DNS A-record already pointing at your external IP). Inside the block goes the container name and its internal port — list your containers with docker ps -a to find the name:

nzb.example.com:443 {
    reverse_proxy nzbhydra2:5076
}

Bring it up with the same pull-and-up one-liner from above, give it a minute or two, and your domain loads the container's UI over HTTPS. That's the whole setup.

Don't want a subdomain per app? Route by path instead:

example.com {
    handle /nzb* {
        reverse_proxy nzbhydra:5076
    }

    handle /sonarr* {
        reverse_proxy sonarr:8989
    }

    @cleanurls path_regexp ^/(nzbhydra|sonarr)/$
    redir @cleanurls /{1}
}

Now example.com/nzb goes to one container and example.com/sonarr to the other, both over SSL. Heads up if you compare against older writeups of this trick: some list the container command as docker -ps a, which isn't a real command — it's docker ps -a.

Add a new disk to a Debian box

Fresh drive in the machine, want it mounted and surviving reboots. Five steps.

Find the disk's device name (something like /dev/sda):

fdisk -l

Wipe whatever old partition data is on it:

wipefs -a /dev/sda

Partition it — cfdisk is the friendliest tool for this. After the wipe it shows as entirely free space: use the whole disk, keep the default Linux filesystem type, write, quit. Then format it as ext4 (plain and boring beats fancy XFS/Btrfs/ZFS unless you know you need them):

mkfs.ext4 /dev/sda

Make a mount point (just a directory the disk shows up in):

mkdir /storage

Now make it mount automatically at boot. Grab the disk's UUID:

blkid

You'll get a line like:

/dev/sda: UUID="1c2b6a84-5f7a-4a8d-b421-a6a52bf17f48" BLOCK_SIZE="4096" TYPE="ext4"

Open /etc/fstab with nano /etc/fstab and add this at the end, swapping in your UUID and mount point:

UUID=1c2b6a84-5f7a-4a8d-b421-a6a52bf17f48       /storage        ext4    defaults,noatime        0       2
  • What those fields actually mean. defaults is the standard mount options bundle, noatime skips writing an access timestamp every time a file is read (less disk churn), the first number disables the ancient dump backup tool, and the trailing 2 means "check this filesystem at boot, after the root disk". The fstab man page has the full story.

Reboot, then confirm it mounted:

df -h /storage

One thing left: the whole disk is owned by root at this point, so expect a round of chown/chmod before regular users can write to it.

Nuke a disk's partition table

Disks that lived in a RAID array, a NAS, or some appliance often have leftover junk in the boot and partition area that confuses partitioning tools. One command clears it all:

wipefs -a /dev/sda

After that, cfdisk/fdisk stop complaining and treat it as a clean disk. Obvious warning: this trashes access to whatever data was on there. Recovery is possible but painful, so triple-check the device name before you press enter. Credit for this one goes to a Server Fault answer that's saved many disks from the "why won't this partition" spiral.

Quick firewall with UFW

The five-command firewall for a fresh server. Basic, but it's the exact sequence everyone forgets. If you're into this kind of tooling, there's a whole pile of network tools worth having bookmarked too.

ufw default allow outgoing

Allow all traffic out.

ufw default deny incoming

Block everything coming in.

ufw allow from xxx.xxx.xxx.xxx

Exception for one IP — your home connection, say — so you don't lock yourself out of SSH.

ufw enable

Turn it on.

ufw status verbose

Verify the rules took. And if the box serves a public website:

ufw allow 443

DigitalOcean's UFW tutorial covers the rest of the bases (allowing port ranges, deleting rules, and so on).

Turn on TCP BBR for a free bandwidth boost

BBR is a congestion-control algorithm from Google that decides how fast TCP pushes data, and it noticeably outperforms the default on busy or long-distance connections. It's not enabled by default on Raspberry Pi OS or most Debian-based systems. (You'll sometimes see it written "BRR" in notes floating around the internet — the actual name is BBR, Bottleneck Bandwidth and Round-trip propagation time.)

sudo bash -c 'echo "net.core.default_qdisc=fq" >> /etc/sysctl.conf'
sudo bash -c 'echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf'
sudo sysctl -p
sudo reboot

What it does under the hood: instead of backing off only when packets get dropped (the old way), BBR continuously estimates how much bandwidth the path can actually carry and paces packets to match. APNIC has a proper deep dive on BBR if you want the theory. If you just want the bandwidth, run the four lines and enjoy.

Share files over the network with Samba

Making a Linux box's folder visible to Windows machines (and everything else) on the LAN.

Install it: sudo apt-get install samba. Then edit the config with sudo nano /etc/samba/smb.conf — go to the end of the file, comment out the printer sections, and add:

[files]
path = /files
valid users = @youruser
browsable = yes
writable = yes
read only = no

Then wire up the user and restart:

sudo smbpasswd -a youruser
sudo smbpasswd -e youruser
sudo systemctl restart smbd

That's add the Samba user, enable them, restart the service. The Samba password is separate from the Linux login password — you're setting a new one here. Last check: make sure the shared directory's filesystem permissions actually let that user read and write, or the share will connect and then mysteriously refuse everything.

On Alpine Linux it's nearly identical, just apk add samba to install and service restart samba to restart.

Mount a Windows share on Linux

The other direction: a Windows machine (or NAS) is sharing a folder and you want it mounted on Linux.

Make sure cifs-utils is installed, then create a .credentials file in your home directory so the password isn't sitting in your shell history:

user=youruser
password=myeyesonly
domain=WORKGROUP

Mount it (swap the IP, share name, and mount point for yours):

sudo mount -t cifs -o rw,vers=3.0,credentials=/home/youruser/.credentials,uid=$(id -u),gid=$(id -g) //192.168.1.81/uploadedscans /windowspc/

To make it survive reboots, add this line to /etc/fstab:

//192.168.1.81/uploadedscans /windowspc cifs uid=0,credentials=/home/youruser/.credentials,iocharset=utf8,vers=3.0,noperm 0 0

One hygiene note since that file holds a plaintext password: chmod 600 ~/.credentials so only you can read it.

Run commands on a whole fleet of servers at once

Got ten servers and a command to run on all of them? Two tools make it painless. Put your hostnames in a file called servers.txt, one per line.

First, accept all their SSH fingerprints in one go instead of typing "yes" ten times:

xargs -I{} ssh-keyscan {} < servers.txt | tee -a ~/.ssh/known_hosts 2>> error_log.txt

That scans each server's host key and appends it to ~/.ssh/known_hosts, logging any failures to error_log.txt. (Some versions of this snippet circulating online leave off the < servers.txt input redirect, which means the command just sits there waiting on stdin — the redirect is load-bearing.)

Then run whatever you want everywhere with parallel-ssh (package name pssh on most distros):

parallel-ssh -h servers.txt -i -l root "uname -a"

That runs uname -a on every host in the file as root, printing each server's output with a success/failure tag. Swap in any command — package upgrades, service restarts, disk checks — and manage a fleet from one terminal. Pairs nicely with knowing how to kill runaway processes when one of those fleet-wide commands goes sideways.

Fast, resumable FTP downloads with lftp

Pulling big files off a seedbox or any FTP server at full line speed, instead of watching a single-threaded transfer crawl. lftp also mirrors whole directory trees so you don't fetch folders one at a time.

Log in:

lftp -u username,password ftp.server.com

Browse with ls, then pick your weapon. For directories full of small files, download many files simultaneously:

mirror --parallel=10

For big files, split each one into chunks and download 10 pieces at once (this is the pget feature — a 1GB file becomes ten 100MB chunks in flight simultaneously):

mirror -c  --use-pget-n=10

The -c flag makes it resumable — disconnect mid-transfer and it picks up where it left off. And to grab only what you don't already have:

mirror --only-newer

Dade2 keeps a solid lftp command reference for everything beyond these basics.

GNU Parallel in two examples

GNU Parallel takes one command and runs many copies of it simultaneously, one per CPU core by default. The {} placeholder is where each input item lands, and ::: introduces the input list — it behaves like a for loop that runs every iteration at once.

Extract every tarball in a directory, in parallel:

parallel -v tar -zxvf {} --one-top-level ::: ~/6tbblock/*.tar.gz

Feed a file of URLs into a downloader, 50 jobs at a time (the -j 50 overrides the cores-only default — fine here because downloads wait on the network, not the CPU):

cat ~/urls.txt | parallel -v -v -j 50 aria2c -c -s 16 -x 16 -k 1M -j 1 {}

Bonus placeholder: {.} is the filename with its extension stripped, so file.ext becomes file:

ls | parallel ia upload {.} /4tb/corel/{}

The official documentation goes far deeper, and the Internet Archive wrote a good guide on using Parallel with their upload tool.

cut & awk for people who refuse to learn cut & awk

Both tools can do absurdly sophisticated text processing. You need about 5% of that. Here's the 5%.

cut splits text on a delimiter and gives you the field you ask for. Strip extensions from a filename like coolfile.tar.gz:

cut -f 1 -d '.'

That says "split on dots, give me field 1" — you get coolfile. Or grab the filename off the end of a URL like https://archive.org/download/edn-1995_08_17/edn-1995_08_17.cbz:

cut -f 6 -d '/'

Split on slashes, take the 6th field: edn-1995_08_17.cbz.

awk is the column grabber. Given typical ls -l output:

-rw-rw-r--  1 ubuntu ubuntu  3.7G May 24 11:07  wireless_world-1983_03-original-scan-tiffs.tar.gz
-rw-rw-r--  1 ubuntu ubuntu  2.9G May 24 11:18  your_computer-1992_06-original-scan-tiffs.tar.gz

Run awk '{ print $5}' and you get just the sizes column (3.7G, 2.9G). Change $5 to $4 and you get the group column instead. Pipe either tool's output into the next command and you've got most of shell text-wrangling covered.

Headless Raspberry Pi: SSH-ready on first boot

Setting up a Pi with no monitor or keyboard attached. Since April 2022, Raspberry Pi OS ships with no default "pi" user, so you create your own on the microSD card before first boot. (If you'd rather run Ubuntu on the Pi, that's its own quick setup — and once it's running you can even ditch the WiFi dongle.)

Flash the card with the Raspberry Pi Imager. Then two files go into the card's /boot directory:

  • An empty file named ssh. Its existence alone enables the SSH server on first boot.
  • A file named userconf.txt. This creates your user — but it needs the password pre-encrypted.

Generate the encrypted password (it prompts you to type the password you'll actually log in with):

openssl passwd -6

It spits out a long hash like:

$6$.FgPgqCf1SD8qR51$nZeB0tdlO7N0Agk0w95Fc2sO6gRxLUWqS3cM2E6hovST40s6/re2WJwDZ7SthJ3va5aUXAi.iAHuNH0ZZ3pV8/

Then userconf.txt is a single line — your username, a colon, and that hash:

youruser:$6$.FgPgqCf1SD8qR51$nZeB0tdlO7N0Agk0w95Fc2sO6gRxLUWqS3cM2E6hovST40s6/re2WJwDZ7SthJ3va5aUXAi.iAHuNH0ZZ3pV8/

Save it to /boot on the card, pop it in the Pi, and SSH straight in. The official docs cover this too (the Imager can also pre-configure a user in its settings gear, which does the same thing with a GUI).

Make a bootable Windows USB from Linux

Windows ISOs won't boot from a straight dd to USB — the install media needs special handling. WoeUSB is the classic tool for turning a Windows ISO from Microsoft's site into a bootable stick, entirely from Linux. It hasn't seen updates in a while but still works.

If you'd rather use something actively maintained, Ventoy is the modern free option — you flash Ventoy to the stick once, then just copy ISO files onto it (Windows, Linux, whatever) and pick which one to boot from a menu. And before flashing anything, a proper formatting tool saves you from half the weird "stick won't flash" problems.

Record live TV with a DVB-T tuner

A USB or PCIe TV tuner plus Linux gets you free-to-air recordings as plain .ts files. The pipeline is: detect the device, scan frequencies, list channels, record.

Detect. Plug it in and check dmesg — modern kernels support most DVB tuners out of the box, though some need a firmware file your distro may not include (dmesg names the firmware it's looking for). Working tuners show up as adapter devices under /dev/dvb.

Install the tools. On Ubuntu/Debian the packages are dvb-tools and dvb-apps (documented on the LinuxTV wiki), plus w-scan for the initial frequency scan.

Scan for frequencies. This finds every broadcast frequency in your area — run it once, not per tuner (swap AU for your own country code):

w_scan -c AU -x >> channels.conf

Pre-made scan files exist under /usr/share/dvb/dvb-t, but a fresh local scan catches things the stale files miss, like local re-transmitter towers.

List the channels. Each frequency carries multiple channels, so build the channel list from the frequency list:

dvbv5-scan -I CHANNEL channels.conf -o dvb_channels.conf

This step sometimes half-fails with some channels missing names — rebooting or replugging the tuner and re-running eventually fills them all in.

Record. dvbv5-zap tunes and dumps the stream to disk. It wants the channel name, not the service ID. With multiple tuners (-a picks the adapter) you can record several channels at once — here's five HD channels simultaneously, 60 seconds each:

sudo dvbv5-zap -a 0 -c dvb_channel.conf "ABCTV HD" -t 60 -o abc_test.ts
sudo dvbv5-zap -a 1 -c dvb_channel.conf "SBS ONE HD" -t 60 -o sbs_test.ts
sudo dvbv5-zap -a 2 -c dvb_channel.conf "10 HD" -t 60 -o 10test.ts
sudo dvbv5-zap -a 3 -c dvb_channel.conf "9HD Melbourne" -t 60 -o 9test.ts
sudo dvbv5-zap -a 4 -c dvb_channel.conf "7HD Melbourne" -t 60 -o 7test.ts

Discourse: only get told about stable updates

Slightly off the Linux path, but if you run a Discourse forum in Docker: by default it nags you about beta releases. To only hear about stable ones (per this Discourse meta thread):

  • Stop the forum (stop its Docker containers).
  • Edit app.yml: uncomment the #version: test-passed line and change test-passed to stable.
  • Rebuild:
git pull
launcher rebuild app

Done — beta nags gone.

That's the whole cheat sheet. Got a command or mini-recipe you keep having to look up — the one that lives on a sticky note or in a text file called notes2-final.txt? Drop it in the comments, this list has room to grow.

Glossary

  • Docker — software that runs apps in isolated packages called containers, so each app carries its own dependencies and doesn't mess with the host system.
  • Docker Compose — a YAML file plus command (docker compose) that defines and manages a whole set of containers at once instead of one by one.
  • Container image — the downloadable template a container runs from; updating an app usually means pulling a newer image.
  • Reverse proxy — a server that sits in front of your apps, receives all incoming web traffic, and forwards each request to the right app behind it.
  • Caddy — a web server / reverse proxy whose party trick is fully automatic HTTPS certificates.
  • Let's Encrypt — a free, automated certificate authority that issues the SSL certificates behind HTTPS.
  • DNS A-record — the DNS entry that points a domain name at an IP address.
  • UUID — a long unique identifier; disks get one so the system can find them reliably even if device names shuffle.
  • fstab — the file (/etc/fstab, "file system table") that tells Linux which disks and shares to mount at boot and where.
  • Mount point — the directory where a disk or network share's contents appear.
  • ext4 — the default, dependable Linux filesystem.
  • UFW — "Uncomplicated Firewall", a friendly front-end for Linux's firewall rules.
  • TCP BBR — Google's congestion-control algorithm that paces network traffic by measuring actual path capacity instead of waiting for packet loss.
  • Samba — the Linux implementation of Windows file sharing (the SMB protocol), for serving folders to the network.
  • CIFS/SMB — the network file-sharing protocol Windows uses; cifs-utils lets Linux mount those shares.
  • SSH fingerprint — a server's identity key; your machine records it in ~/.ssh/known_hosts the first time you connect.
  • Seedbox — a remote server used for downloading, which you then pull files from over FTP/SFTP.
  • lftp — a command-line file-transfer client that supports multi-threaded, resumable downloads and directory mirroring.
  • GNU Parallel — a tool that runs many copies of a command at the same time across CPU cores.
  • Headless — running a computer with no monitor or keyboard, managed over the network.
  • DVB-T — the digital terrestrial TV broadcast standard; a DVB-T tuner receives free-to-air channels.
  • ISO — a disc-image file; operating system installers usually ship as one.

Sources

Comments

← Newer