Reference
Self-hosting glossary
85 terms you will meet in documentation, forum answers and error messages, defined the way they are actually used rather than the way a marketing page uses them.
A#
ACME
The protocol (RFC 8555) a client uses to prove it controls a domain and get a certificate back, with no human in the loop. Let's Encrypt made it the default way self-hosters get TLS. Certificates are 90 days and clients renew at 30 days remaining, so a broken renewal breaks your site a month after it actually failed. Caddy and Traefik speak ACME internally; nginx does not, so you run certbot or acme.sh beside it. ACME proves domain control only. It says nothing about who you are.
See also: Reverse proxy and TLS, Caddy
Append-only repository
A backup destination whose credentials can add data but not remove it. Borg has a server-side append-only mode, restic's rest-server has --append-only, and object stores offer bucket policies plus object lock. This is the control that survives the two failures nobody plans for: ransomware that follows your backup credentials from the compromised server, and a person typing forget --prune against the wrong repository at midnight. Pruning then happens from the destination side or with a second key that never lives on the machine being backed up.
See also: Backups that actually restore, Resilience scorecard
ARC
ZFS's adaptive replacement cache: a RAM cache that tracks both recently used and frequently used blocks, so a single large sequential read cannot flush everything useful out of it. On Linux it will grow to about half of system memory by default and gives it back under pressure, but it is reported as used memory, which is why a healthy ZFS box looks alarmingly full. The old "1 GB of RAM per TB of pool" rule is folklore that came from deduplication tables. Without dedup, more ARC buys read latency, not correctness.
See also: ZFS, btrfs, mdadm or one disk, Stack planner
B#
Bind mount
A host directory mapped into a container at a path you choose, written ./config:/config in compose. You own the path, you can read it with normal tools, and your backup job can see it. Two traps. There is no ownership translation, so the UID inside the container has to match the UID that owns the directory on the host. And if the source path does not exist, Docker creates an empty directory rather than failing, which is why a typo in a volume line looks like an application that lost all its settings.
See also: Docker Compose conventions
Bit rot
Data at rest quietly changing: a marginal sector, a firmware bug, a bad cable, memory corruption on the way through. Nothing reports an error, so you find it years later in a photo you had not opened since 2019. Checksumming filesystems detect it on every read and repair it automatically when there is redundancy to repair from, which is the main argument for ZFS or btrfs over ext4 for a media archive. On a filesystem without checksums the corrupted bytes are handed to you, and your backup dutifully copies them.
See also: ZFS, btrfs, mdadm or one disk
C#
CalDAV and CardDAV
Calendar and contact synchronization over HTTP, both built on WebDAV, carrying iCalendar and vCard data. They are the reason you can leave a hosted calendar without changing phones: iOS and macOS support both natively, Thunderbird does, and Android does through DAVx5. Nextcloud provides both, and Vikunja exposes tasks over CalDAV. The part that usually needs attention is discovery, since clients look for /.well-known/caldav and /.well-known/carddav and expect a redirect that your reverse proxy has to pass through.
See also: Nextcloud, Replace Google Drive
CGNAT
Carrier-grade NAT: your ISP puts hundreds of customers behind one public IPv4 address. The tell is a WAN address in 100.64.0.0/10 on your router that does not match what a what-is-my-IP site reports. Inbound connections are impossible, port forwarding silently does nothing, and no amount of router configuration fixes it. Your options are IPv6 if the ISP provides it, a small VPS as a relay, a mesh VPN that falls back to relays, or asking the ISP for a real address, which some sell for a few currency units a month.
See also: Remote access without port forwarding
Compose project
The namespace for one stack. Compose derives it from the directory name unless you set name: in the file or COMPOSE_PROJECT_NAME in the environment, then prefixes every container, network and named volume with it. This is behind one of the most alarming false alarms in self-hosting: rename or move the directory, run docker compose up, and you get empty volumes and an application that has forgotten everything. The data is intact under the old prefix. Set the project name explicitly and the directory stops mattering.
See also: Docker Compose conventions, Moving a service to a new machine
Context window
The maximum number of tokens a model can hold in view at once, prompt and response together. Everything a chat interface "remembers" is re-sent inside it on every turn, so long conversations get slower and eventually get truncated from the front. Long contexts cost VRAM, because the key-value cache grows with length, and they cost time. Serving software often defaults to a much smaller window than the model supports, so a pasted document can be quietly cut rather than refused. Check the server's context setting before blaming the model.
See also: Ollama, Open WebUI
Copy-on-write
Never overwriting a live block: the new version is written elsewhere and the pointer is switched atomically. That is what gives ZFS and btrfs instant snapshots, cheap clones and a consistent on-disk state after a power cut. The cost is fragmentation under random writes, which is why database files and VM images on a copy-on-write filesystem want tuning (a smaller recordsize for Postgres, or disabling copy-on-write per directory on btrfs) and why these pools slow down badly once they pass roughly 80 percent full.
See also: ZFS, btrfs, mdadm or one disk
Cron and systemd timers
Two ways to run a job on a schedule. cron is everywhere and gives you a minimal PATH, no dependency ordering and output mailed to an account nobody reads. A systemd timer gives you OnCalendar expressions, logs in journald under the unit name, RandomizedDelaySec so twenty machines do not hit a repository at once, and Persistent=true, which runs a missed job once the machine comes back. On a server that sleeps or reboots overnight, that last option is the difference between a nightly backup and no backup.
See also: Backups that actually restore
CVE
An identifier for one publicly disclosed vulnerability, usually quoted with a CVSS severity assigned by whoever scored it. Scan any container image and you will get dozens, mostly in base OS packages your application never invokes. Counting them is meaningless; a critical in a code path you do not reach is not an incident, and a medium in your authentication path is. Triage by exposure: is the affected component reachable from the network, and is the service reachable from outside your house? Then patch on that order.
See also: A security baseline for a home server, An update strategy that does not lose data
D#
Deduplication
Storing each unique block of data once across an entire repository, so tonight's snapshot of a barely changed directory costs kilobytes. Backup tools do it by splitting files into variable-length chunks with a rolling hash, which is what keeps a single byte inserted at the front of a large file from shifting every chunk boundary after it. restic, BorgBackup and Kopia all work this way. The tradeoff is that the repository is no longer a browsable copy of your files, and corruption or loss of the repository takes every snapshot in it at once.
See also: restic vs BorgBackup, Backups that actually restore
Direct play
The server sends the file untouched and the client decodes it, costing the server almost nothing but disk reads. Direct stream is the middle case: the container is repackaged but the video is not re-encoded. Most complaints about buffering are actually a transcode triggered by one small thing, usually an audio track the client cannot decode, an image-based subtitle that has to be burned in, or a quality cap left set in the app. Every player has a playback info overlay that names the reason. Read it before buying a GPU.
See also: GPUs, transcoding and local AI, Jellyfin vs Plex
DKIM
A cryptographic signature the sending server adds over chosen headers and the message body, verified against a public key published at <selector>._domainkey.yourdomain. Unlike SPF it survives forwarding, because it does not depend on which IP connected. Rotate keys by publishing a new selector first and switching afterwards. A mailing list that appends a footer or rewrites the subject invalidates the signature, which is why lists rewrite the From header to their own domain instead.
See also: mailcow vs Stalwart
DMARC
A policy record at _dmarc.yourdomain telling receivers what to do when neither SPF nor DKIM aligns with the domain a human sees in the From header, plus an address for aggregate reports: v=DMARC1; p=none; rua=mailto:reports@yourdomain. Alignment is the whole point, since SPF passing for some unrelated bounce domain proves nothing about your brand. Start at p=none, read reports for a few weeks until you have found every legitimate sender you forgot about, then move to quarantine and then reject.
See also: mailcow vs Stalwart
DNS rebinding protection
A resolver rule that discards answers from public zones pointing into private ranges such as 192.168.0.0/16, because a hostile website could otherwise resolve its own name to your router and attack it from your browser. It is on by default in many routers, in Pi-hole and in AdGuard Home. It is also why your public hostname stops working the moment you point it at a LAN address for split-horizon use. The fix is to allowlist your own domain in the resolver, not to disable the protection globally.
See also: DNS for self-hosters, Pi-hole vs AdGuard Home
DNS-01 challenge
The ACME challenge that proves control by publishing a TXT record at _acme-challenge.yourdomain. It is the only way to get a wildcard, and the only way to get a trusted certificate for a hostname that never resolves publicly, which makes it the right choice for a server reachable only over a VPN. The cost is an API credential for your DNS provider sitting on the server, so scope the token to one zone. The stock Caddy binary ships zero DNS provider modules; you rebuild with xcaddy to get one.
See also: DNS for self-hosters, Reverse proxy and TLS
Docker socket
The Unix socket at /var/run/docker.sock that carries the Docker Engine API. Anything that can talk to it can start a container that mounts the host filesystem as root, so mounting it into a container gives that container root on the host. Mounting it read-only changes nothing, because the API is requests over the socket, not file writes. Portainer, Dozzle, Homepage, Traefik and Watchtower all want it. Give it only to things you would trust with the root password.
See also: A security baseline for a home server, Docker Engine
DoH and DoT
Two ways to encrypt DNS queries between you and your resolver. DoH (RFC 8484) tunnels them inside HTTPS on port 443, indistinguishable from web traffic, which is why browsers ship it and why a network operator cannot block it without blocking the endpoint. DoT (RFC 7858) uses a dedicated port, 853, which makes it clean to identify and trivial to block. Both stop your ISP reading queries. Neither hides anything from the resolver itself, so encrypting to a large public resolver is a change of who is watching, not an end to being watched.
See also: AdGuard Home, DNS for self-hosters
E#
Embeddings
A list of numbers representing the meaning of a piece of text or an image, arranged so that similar things sit close together in that space. It is what makes "photos of the dog at the beach" find the right pictures in Immich, and what a retrieval system searches before it builds a prompt. Embeddings need a vector index to be searchable, such as pgvector or VectorChord in Postgres. They are also model-specific: change the embedding model and every stored vector is meaningless, so you re-index the whole library.
F#
fail2ban jail
One configured unit of Fail2ban: a log source, a filter regex that recognizes a failed login, and thresholds (maxretry within findtime gives bantime), plus an action that inserts a firewall rule. Two things break it on a container host. Applications log to the Docker JSON driver rather than a file, so the jail has nothing to read unless you mount a log or change the driver. And behind a reverse proxy every failure appears to come from the proxy, so unless the app logs the forwarded address and your filter reads it, the first ban takes out your own proxy.
See also: Fail2ban, CrowdSec vs Fail2ban, A security baseline for a home server
Forward auth
A reverse proxy pattern: before proxying a request, the proxy asks a separate auth service about it. A 200 means allow, a 401 or a redirect means send the user to a login page. It is auth_request in nginx, a ForwardAuth middleware in Traefik, and forward_auth in Caddy, usually pointed at Authelia or authentik. It is how you put a login in front of software that has none. It gates the HTTP path only: the app still has no idea who you are, anything that reaches the container directly bypasses it, and native mobile apps that do not follow login redirects will simply fail to connect.
See also: Single sign-on for self-hosters, Authelia, Authelia vs authentik
G#
Greylisting
Rejecting the first delivery attempt from an unfamiliar sender, IP and recipient combination with a temporary 4xx error, then accepting the retry minutes later. Legitimate mail servers retry, and a good deal of junk software does not, so it removes real volume for almost no CPU. The cost is paid by you: the first message from a new correspondent is delayed by minutes to an hour, which people notice most with password reset and confirmation emails. Some large senders retry from a different IP each time and can loop.
See also: mailcow vs Stalwart
H#
Healthcheck
A command the container engine runs inside the container on an interval, marking it healthy or unhealthy. Its real value is in compose, where depends_on with condition: service_healthy makes a service wait until its database actually answers. Without one, depends_on waits only for the container process to start, which is why an app races its Postgres on every boot and logs a connection error. Note what it does not do: an unhealthy container is not restarted by itself, it is simply labelled, so pair it with monitoring or a restart policy that acts on it.
See also: Docker Compose conventions, The minimum viable monitoring stack
HSTS
A response header (Strict-Transport-Security) telling browsers to refuse plain HTTP for this host for the next max-age seconds. Useful, and easy to shoot yourself with. includeSubDomains applies to every subdomain including the internal one you serve over plain HTTP, and browsers cache the policy, so the fix is not on the server. Preloading bakes your domain into browser binaries and removal takes months of release cycles. Do not preload a domain you also use for lab hostnames. A year of max-age on a working site is the sensible setting.
See also: A security baseline for a home server
HTTP-01 challenge
The ACME challenge where the certificate authority fetches http://yourdomain/.well-known/acme-challenge/<token> and compares what it finds. It needs port 80 open from the public internet, from several vantage points, which means it cannot work for a name that only resolves on your LAN and cannot issue a wildcard. Redirects to HTTPS are followed, so a permanent redirect on port 80 is fine. If renewal fails after months of working, check that something is still listening on 80: a firewall change or a second proxy is the usual cause.
See also: Reverse proxy and TLS
I#
Image tag and digest
A tag such as :2.3 or :latest is a mutable pointer: the publisher can move it to different content tomorrow, and latest moves constantly. A digest (sha256:...) names the content itself and can never change. Pinning by digest, or at least to a specific minor version, is what stops a routine docker compose pull from carrying a stateful service across a breaking major release while you are not watching. The tradeoff is that nothing updates until you decide, so pair pinning with an update notifier such as Diun.
See also: An update strategy that does not lose data, Watchtower vs Diun
IMAP and POP3
Two ways for a client to fetch mail. IMAP keeps the canonical mailbox on the server and synchronizes folders, flags and read state across every device, over port 993 with TLS. POP3 downloads messages and by default deletes them from the server, over 995. Use IMAP unless you specifically want mail pulled off the server. The operational consequence for a self-hoster: with IMAP the server's mail store is the thing that must be backed up, while with POP3 the only copy of years of mail may be on one laptop.
See also: mailcow vs Stalwart, Replace Gmail
L#
LDAP
A directory protocol, not a single sign-on protocol. An app binds to the directory with a service account, searches for the user by a filter such as (uid=%s), then rebinds as that user with the supplied password to verify it. Group membership drives permissions, usually through memberOf. Every app still shows its own login form, so you get one password everywhere, not one session everywhere. LLDAP exists because most people want the small subset of a directory that self-hosted apps actually query, without administering OpenLDAP.
See also: LLDAP, Single sign-on for self-hosters
Logical and physical backup
A logical backup is the data re-expressed as statements or rows: pg_dump, mariadb-dump, an app's own export. It is portable across versions, architectures and even engines, and it is slow to restore because the target has to rebuild indexes. A physical backup is the actual files or blocks: pg_basebackup, a filesystem snapshot, zfs send. It restores fast and it is only valid on a compatible engine version and page layout, and only consistent if it was taken atomically. Home servers should default to logical and treat snapshots as the fast path, not the only path.
See also: Backing up a running database, Backups that actually restore
M#
Mesh VPN
A VPN where every device connects directly to every other device, with a coordination server that distributes public keys, addresses and access rules but does not carry traffic. Tailscale is the well-known one, and Headscale is a self-hosted implementation of its control plane that works with the official clients. Compared to a hub-and-spoke WireGuard server such as wg-easy, you get roaming, NAT traversal and per-device access control for free, and you take on a control server that has to be reachable for new devices to join.
See also: Headscale, Headscale vs wg-easy, Remote access without port forwarding
MTA
Mail transfer agent: the server that accepts mail and relays it toward its destination over SMTP, as distinct from the delivery agent that writes to a mailbox and the client you read it in. Postfix is the usual one, and both mailcow: dockerized and Stalwart wrap one in a full stack. Sending is the hard half of self-hosted mail. Most residential ISPs block outbound port 25 entirely, and a new address on a cloud provider inherits whatever reputation its neighbours built.
See also: mailcow vs Stalwart, Replace Gmail
Multi-arch image
One image reference backed by a manifest list that maps each CPU architecture to a different image, so docker pull on an arm64 board and on an x86 server both work with the same compose file. 95.2 percent of the tools catalogued here publish arm64 builds. When a project does not, you get exec format error or a slow emulated run under qemu, and on a Raspberry Pi or an ARM mini PC that single fact decides whether the software is an option at all.
See also: Stack planner, Choosing home server hardware
MX record
The DNS record naming which hosts accept mail for a domain, each with a priority where lower is preferred. It must contain a hostname, never an IP address, and that hostname needs its own A or AAAA record. MX affects inbound mail only: whether your outbound mail is accepted depends on the sending IP, its PTR record and SPF and DKIM alignment. If a domain has no MX at all, senders fall back to its A record, which is why mail sometimes arrives at a web server by accident.
See also: mailcow vs Stalwart, DNS for self-hosters
N#
Named volume
Storage Docker manages for you, referenced by name and living under /var/lib/docker/volumes/<name>/_data. Unlike a bind mount, an empty named volume is seeded with whatever the image already has at that path, which is why some images only work this way. It survives docker compose down and container recreation. The risk is invisibility: a backup job pointed at your compose directory copies nothing from it, and renaming the project directory changes the volume prefix so a new empty volume appears and the data looks lost.
See also: Docker Compose conventions, Backups that actually restore
NAT traversal
The set of tricks that let two devices behind separate routers talk directly without either forwarding a port. Both sides send UDP outward at the same time, learn their public address from a STUN server and, if the routers assign predictable ports, the packets meet in the middle. It fails on symmetric NAT and on CGNAT, so every serious mesh VPN keeps relay servers as a fallback. A relayed connection works fine and is slower, so a Tailscale-style network that suddenly halves in speed is usually one that stopped connecting directly.
See also: Remote access without port forwarding, Headscale
NVENC
NVIDIA's dedicated encoder block, available on GeForce as well as professional cards, reached through the NVIDIA Container Toolkit in Docker. Quality per bitrate is good and it handles more simultaneous streams than an iGPU, at the cost of a card that draws real power at idle and occupies a slot. Consumer drivers have historically limited the number of concurrent encode sessions, so check NVIDIA's current support matrix before you size a many-user server around one card. For a household of four, an Intel iGPU is usually the better buy.
See also: GPUs, transcoding and local AI, Choosing home server hardware
O#
OAuth 2
A framework for delegated authorization: it lets an application obtain a token to act on your behalf against an API, with a scope and an expiry. It is not an authentication protocol and never was. It answers "may this app read your calendar", not "who are you". Products that built login on bare OAuth 2 had to invent their own way to fetch a user identity, which is why the same button behaves differently everywhere. When an app says it supports OAuth 2 login, check whether it means OIDC, because that is the part that actually defines identity.
See also: Single sign-on for self-hosters
Object storage and block storage
Block storage hands out fixed-size blocks that a filesystem sits on top of: a disk, an iSCSI LUN, a cloud volume. One machine mounts it and gets normal file semantics. Object storage keeps whole objects addressed by key over HTTP, with metadata, many concurrent clients and no filesystem behaviour: no partial writes, no atomic rename, listings that can lag. Backup repositories and photo blobs fit object storage well. Databases and anything that expects to seek and rewrite in place do not, which is why S3-backed "drives" disappoint.
See also: MinIO vs Garage
OIDC
OpenID Connect: a thin identity layer on OAuth 2 that adds an ID token, a signed JWT carrying a stable subject identifier and usually email and group claims, plus a discovery document at /.well-known/openid-configuration. You register a client ID, a secret and a redirect URI in your provider and paste them into the app. It is the only self-hosted SSO that gives the app a real account. Just 50.0 percent of the catalogued tools that have user accounts support it natively, which is why forward auth is still in the picture.
See also: Single sign-on for self-hosters, The single sign-on gap, Pocket ID
OPML
A small XML file listing your feed subscriptions and their folders, and the only reliable way to move between readers. Every serious one imports and exports it, including FreshRSS and Miniflux. What it carries is feed URLs and folder structure and nothing else: read state, starred items, per-feed rules and filters do not travel, so plan to lose them. Export one after any significant change to your subscriptions. It is a 20 KB file and it is the reason switching readers is a ten minute job.
See also: FreshRSS vs Miniflux, FreshRSS
Orphan container
A container still labelled with your compose project whose service no longer exists in the compose file, usually left by a rename or a removed block. docker compose up warns about them and keeps them running; --remove-orphans deletes them. Its cousin is the dangling image, the untagged <none>:<none> layer left when a rebuild moves a tag, cleared with docker image prune. Be careful with prune -a, which removes every image not currently in use, including the previous version you were planning to roll back to.
See also: Docker Compose conventions, An update strategy that does not lose data
P#
Passkey
A WebAuthn credential stored on your phone, laptop or security key, where the private key never leaves the device and the signature is bound to the site's origin. That origin binding is the point: a passkey cannot be phished onto a lookalike domain the way a password and a TOTP code can. Pocket ID is an OIDC provider that accepts nothing else. The hard part is recovery, not login: register at least two credentials on different devices, or keep a printed recovery code, because a lost phone with one passkey is a locked door.
See also: Pocket ID, Pocket ID vs Authelia
pg_dump
PostgreSQL's logical export. It runs inside one MVCC snapshot, so the output is internally consistent even though the database kept serving traffic throughout, and it restores into the same or a newer major version. pg_dump covers one database; pg_dumpall adds roles and other cluster-wide objects, which is what people forget until a restore has no users. In a container it is docker compose exec -T db pg_dump -U postgres appdb. Your data loss window is the gap between dumps, because nothing after the dump started is in the file.
See also: Backing up a running database, Backup planner
Port forwarding
A NAT rule on your router sending traffic arriving on a public port to one internal host and port. It is the traditional way to reach a home server and the one that gets people compromised, because what you have published is the application's own login page to every scanner on the internet. If you do it, forward 443 to a reverse proxy with authentication in front and nothing else. Forwarding an application port directly, or worse a management UI, is how most home server incidents start.
See also: Remote access without port forwarding, A security baseline for a home server
Presigned URL
A link to one object in an S3-compatible store with a signature and an expiry in the query string, granting one operation to whoever holds it without giving them credentials. Apps use it for direct browser uploads and share links. Treat it as a bearer token pasted into a URL: it appears in proxy logs, browser history and chat previews, and there is no revocation short of rotating the signing key. Keep expiries in minutes rather than days; SigV4 caps them at seven days regardless.
See also: Garage
PTR record
Reverse DNS: the record that maps an IP address back to a hostname, living in the in-addr.arpa zone. Only whoever controls the address block can set it, which means your ISP for a home line and a control panel field for a VPS. Large mail providers reject or heavily penalize SMTP connections from an address with no PTR or a generic one full of dashes and digits. Make it match the hostname your server announces in its SMTP greeting; mismatches are scored against you.
See also: mailcow vs Stalwart, DNS for self-hosters
PUID and PGID
Environment variables, a LinuxServer.io convention rather than a Docker feature, that tell the container's init script to run the application as a specific user and group ID. Set them to the output of id -u and id -g for the account that owns your data and files written to bind mounts come out owned by you. They are not universal. Audiobookshelf ignores them completely and needs compose's user: 1000:1000 instead. Wrong values give you either permission denied at startup or root-owned files you cannot delete without sudo.
See also: Docker Compose conventions
Q#
Quadlet
Podman's systemd generator, available since Podman 4.4. You write a declarative unit such as ~/.config/containers/systemd/immich.container, run systemctl --user daemon-reload, and systemd creates a real service with dependency ordering, restart handling and journald logs. There are matching .volume, .network, .pod and .kube types. It replaced podman generate systemd, which is deprecated. This is the substantive reason to prefer Podman over Docker Engine on a Linux server: your containers become ordinary services the host already knows how to supervise.
See also: Podman, Docker vs Podman
Quantization
Storing model weights at reduced precision, commonly 8, 5 or 4 bits instead of 16, which cuts memory use and memory bandwidth roughly in proportion. A 7 billion parameter model is about 14 GB at 16-bit and about 4 GB at 4-bit, which is the difference between needing a data centre card and running on a laptop. Quality loss is small at 5 to 6 bits and becomes visible below 4, especially for code and long reasoning. Ollama pulls quantized GGUF weights by default, which is why models are smaller than their parameter count suggests.
See also: Ollama, GPUs, transcoding and local AI
Quick Sync
Intel's fixed-function video encode and decode block, present in most Intel iGPUs. For a media server it is the best value hardware in the category: a low-power N100 will handle several simultaneous 4K HEVC transcodes at single-digit watts. In Docker it needs --device /dev/dri:/dev/dri and the host's render group ID passed through with group_add, or ffmpeg silently falls back to the CPU and you conclude the hardware does not work. Plex Media Server gates it behind Plex Pass and Emby behind Premiere; Jellyfin does not gate it at all.
See also: GPUs, transcoding and local AI, Jellyfin vs Plex
R#
RAID is not a backup
RAID keeps a service running when a disk dies. It writes every change to all members immediately, which includes rm -rf, a bad migration, ransomware and a controller writing corruption. Parity RAID (RAID5, RAID6, RAIDZ) computes redundancy so the array survives one or two simultaneous failures, and Unraid computes parity across mixed drive sizes for the same purpose. None of it gives you the file as it was yesterday, and none of it survives fire, theft or the operator. RAID buys uptime; only backups buy history.
See also: ZFS, btrfs, mdadm or one disk, Backups that actually restore
Rate limiting
Capping how many requests a client may make in a window, answering the rest with 429. It is the cheap defence against password guessing and scraping, and it belongs at the proxy so every backend inherits it. nginx has limit_req, Traefik has a RateLimit middleware, and Caddy needs a plugin for it. The mistake that makes it useless: behind another proxy or a CDN, every request arrives from one address, so unless you key on the forwarded client IP you throttle all your users at once or nobody at all.
See also: A security baseline for a home server
Remuxing
Repackaging the same encoded audio and video streams into a different container, MKV into MP4 or into HLS segments for a browser, without re-encoding anything. It is lossless and roughly as expensive as a file copy. Media servers do it whenever the codecs are supported but the container is not, which is most browser playback. The thing that usually turns a cheap remux into a full transcode is subtitles: an image-based track such as PGS has to be burned into the video, and burning in means re-encoding.
See also: GPUs, transcoding and local AI
Restart policy
What the engine does when a container exits: no, on-failure, always or unless-stopped. Use unless-stopped. The difference that matters is that always will restart a container you deliberately stopped as soon as the daemon restarts or the machine boots, which turns a maintenance window into a mystery. A restart policy also only reacts to the process exiting. A container that is running, listening and wedged will be restarted by nothing, which is the gap a healthcheck plus an uptime check fills.
See also: Docker Compose conventions
Retention policy
The rules that decide which snapshots survive pruning, typically expressed as --keep-daily 7 --keep-weekly 5 --keep-monthly 12. Because deduplication makes old snapshots nearly free, the common mistake is keeping too few, not too many: quiet corruption and accidental deletion often surface weeks later, and a seven-day window means you find out after the evidence is gone. Pruning is also the only routine operation that destroys data, so it deserves the tightest credentials, an append-only remote and a check run afterwards.
See also: Backups that actually restore, Backup planner
Reverse proxy
One process listening on 443 that routes each request to a backend based on the hostname, terminates TLS, and adds or strips headers. It is what turns http://192.168.1.20:8096 into https://jellyfin.example.com, and it removes the whole class of port collisions because only the proxy publishes a host port. What it is not: authentication, a firewall, or a WAF. Behind Caddy or Traefik your services are exactly as exposed as they were, just with a nicer name and a valid certificate.
See also: Reverse proxy and TLS, Caddy vs Traefik, Reverse proxy generator
Rootless container
Running the container engine and the workload as an unprivileged user, with user namespaces mapping root inside the container to a normal UID outside it, from your subuid range. A container escape lands on your user account rather than on root. The costs are real: you cannot bind ports below 1024 unless the host lowers net.ipv4.ip_unprivileged_port_start, file ownership on bind mounts is shifted by the namespace mapping, and images that chown files at startup sometimes fail. Podman does it natively; Docker supports it in a separate rootless mode.
See also: Podman, Docker vs Podman, A security baseline for a home server
RPO and RTO
Two numbers that turn "I have backups" into a plan. Recovery point objective is how much work you accept losing, which equals the age of your newest good backup: a nightly job is a 24 hour RPO whether you intended that or not. Recovery time objective is how long from failure to serving again, including sourcing hardware, pulling data over your actual upload link, restoring and reindexing. If you have never timed a restore, your RTO is not short, it is unknown. Write both down and check them against what you would actually accept.
See also: Backups that actually restore, Resilience scorecard
S#
S3-compatible
Implements enough of the Amazon S3 HTTP API (buckets, objects, SigV4 signing, multipart upload) that S3 clients work against it unchanged. It is a claim about the common path, not the whole API: versioning, object lock, lifecycle rules and IAM policy syntax differ or are missing. Garage and MinIO both call themselves S3-compatible and behave differently under retention policies. Test the specific calls your backup tool makes, especially object lock if you were counting on it for immutability.
See also: MinIO vs Garage, Garage
SAML
The older enterprise SSO protocol: XML assertions signed by the identity provider and POSTed through the browser to the service. It works and it is everywhere in corporate software, but it is verbose, the tooling is unforgiving, and the two classic failures are clock skew between the two servers and a signing certificate that expired without anybody watching. Keycloak and authentik both speak it. In self-hosting you rarely need it: almost nothing in a homelab is SAML-only, and OIDC is easier to debug when it breaks.
See also: Keycloak, Keycloak vs authentik
SBOM
A software bill of materials: a machine-readable list of the components inside an image, in SPDX or CycloneDX format. docker buildx build --sbom=true attaches one, and syft generates one for an image you did not build. Its value is answering "does anything I run include this library" in seconds instead of an afternoon. It is not a safety certificate: it lists what the tooling could detect, and dependencies compiled into a static Go or Rust binary often do not appear at all.
See also: A security baseline for a home server
Scrub and resilver
A scrub reads every allocated block in the pool, verifies its checksum and repairs any mismatch from redundancy. Run one monthly; it is how you learn about bit rot before you need the data. A resilver rebuilds a replaced disk, and on ZFS it copies only allocated blocks, so it scales with used capacity rather than disk size. The dangerous part of both is that they read the surviving disks end to end, which is exactly the workload that finds a second marginal drive. Mirrors and RAIDZ2 exist because that happens more often than the odds suggest.
See also: ZFS, btrfs, mdadm or one disk, Scrutiny
SMART
The self-reporting system built into every modern drive, read with smartctl -a /dev/sda. The attributes worth alerting on are reallocated sectors (5), reported uncorrectable (187), command timeout (188), current pending sectors (197) and offline uncorrectable (198); a pending count that is nonzero and climbing means replace the disk this week. A large share of drives still fail with no warning at all, so treat SMART as a cheap early signal rather than a guarantee. Scrutiny tracks the trend over time, which is what makes the numbers useful.
See also: Scrutiny, The minimum viable monitoring stack
Snapshot
A read-only reference to a filesystem at one instant, created in milliseconds because copy-on-write means nothing has to be copied. It grows only as the live data diverges from it. Snapshots are the right answer to a bad upgrade, a wrong rm or a ransomware run you catch quickly, and they are the wrong answer to a dead pool, a fire or a stolen machine, because they live on the same disks as the original. A snapshot becomes a backup only once it has been sent somewhere else.
See also: Backups that actually restore, ZFS, btrfs, mdadm or one disk
SNI
Server Name Indication: the hostname the client sends in the TLS handshake, before encryption starts, so one IP address can serve certificates for many sites. This is what lets your reverse proxy host twenty services on one public address. It is still sent in cleartext under TLS 1.3 unless Encrypted Client Hello is in use, so SNI is visible to anything on the path. A proxy can also route on SNI without decrypting, which is how a TCP router forwards HTTPS it holds no key for. Getting the wrong site's certificate usually means no SNI matched and you hit the default.
See also: Reverse proxy and TLS
Socket proxy
A tiny HAProxy container that sits between an application and the Docker socket and allowlists API endpoints with environment variables, typically CONTAINERS=1 with POST=0. A dashboard can then list containers without being able to create one, and Traefik can read labels without holding a key to the host. It shrinks the blast radius rather than removing it: a read-only container list still exposes environment variables, and anything you set POST=1 for gets the full write path back. It is the standard mitigation and it should be the default for read-only consumers.
See also: A security baseline for a home server, Traefik
SPF
A TXT record listing which hosts may send mail for your domain, such as v=spf1 mx ip4:203.0.113.10 -all. The receiver checks the connecting IP against it. Two things bite: SPF breaks on plain forwarding, because the forwarder's address is not in your record, which is exactly why DKIM exists. And the check is capped at ten DNS lookups, so a couple of nested include: chains from hosted providers push you over and the result becomes permerror, which some receivers treat as a failure.
See also: mailcow vs Stalwart
Split-horizon DNS
The same hostname resolving to different addresses depending on where you ask. Inside the house nextcloud.example.com returns 192.168.1.20; from outside it returns your public address or nothing at all. It keeps LAN traffic on the LAN, avoids depending on your router doing NAT hairpinning, and lets you use real certificates on internal names. The cost is two sets of records that drift apart. Run the internal half on AdGuard Home, Pi-hole or Technitium DNS Server and write down that you did.
See also: DNS for self-hosters, Technitium DNS Server
T#
Three-two-one rule
Three copies of the data, on two different kinds of media, one of them off site. It survives as advice because each part maps to a real failure: two copies on one disk die together, two disks in one machine die in the same fire or theft, and a single local copy dies with the building. The modern amendment is that the off-site copy should be append-only or pulled from the far end, because ransomware and a mistyped command both travel down any path your server can write to.
See also: Backups that actually restore, Backup planner
Token
The unit a language model actually reads and writes: a frequent character sequence rather than a word. English averages roughly four characters per token, so 1000 tokens is about 750 words, and unusual names or code split into many more tokens than they look like they should. Context limits, hosted pricing and generation speed are all quoted in tokens. On your own hardware the number worth measuring is tokens per second at your chosen quantization, because that is what decides whether local inference is pleasant or merely possible.
See also: Ollama
Torn read
A copy that contains bytes from before a write and bytes from after it, because the reader took thirty seconds and the writer did not pause. Copying a live database file with cp or rsync produces one reliably. The nasty part is that the result usually looks fine: the file opens, the app starts, and days later you get database disk image is malformed or a foreign key that points at nothing. 81.9 percent of the tools catalogued here need an export or a stop rather than a live file copy, which is more than most people assume.
See also: Backing up a running database, The backup blind spot
Transcoding
Decoding a video and re-encoding it to a different codec, bitrate or resolution because the client cannot play the original. It is by far the most expensive thing a media server does: one 4K HEVC stream converted to 1080p H.264 in software will occupy several cores and still stutter. Jellyfin and Plex Media Server start one automatically the moment a client reports an unsupported format, so a server that idles at 300 MB and two percent CPU can be pinned by a single phone on mobile data.
See also: GPUs, transcoding and local AI, Jellyfin
Trusted header auth
The app takes identity from an HTTP header the proxy injected, such as Remote-User or X-authentik-username, and creates or logs in that account with no password. It is the cheapest way to get real single sign-on into software with no OIDC support. It is also the easiest way to hand somebody an admin account: the proxy must strip any client-supplied copy of that header, and the app must be unreachable except through the proxy. If a container port is still published on the LAN, anyone who can reach it can set the header themselves.
See also: Single sign-on for self-hosters, The single sign-on gap
V#
VAAPI
The Video Acceleration API, the generic Linux interface that Intel and AMD GPUs implement, used through a render node at /dev/dri/renderD128. It is the portable path, which also means it is nobody's favourite path: on Intel hardware the QSV pipeline usually performs better and supports HDR tone mapping more completely in Jellyfin. Container requirements are the same either way, pass the device and add the render group. On AMD, decode is solid and encode is acceptable rather than excellent.
See also: GPUs, transcoding and local AI, Jellyfin
vdev
The unit ZFS stripes a pool across. Redundancy lives inside a vdev (a mirror, or raidz1/2/3), never between them, so losing one vdev loses the entire pool no matter how healthy the others are. This is the single most expensive thing to get wrong, because for years a vdev could not be removed or widened. OpenZFS 2.3, released in January 2025, added raidz expansion, which grows an existing raidz vdev by a disk but does not rewrite the parity ratio of data already written. Decide the layout before you buy drives.
See also: ZFS, btrfs, mdadm or one disk, Choosing home server hardware
VRAM
Memory on the graphics card, and the binding constraint for running language models locally. The weights plus the key-value cache for your context have to fit, or layers spill to system RAM across the PCIe bus and generation speed drops by an order of magnitude rather than a few percent. Rough sizing: the model file on disk plus one to two gigabytes, plus more for long contexts. System RAM is not a substitute on a discrete card. On Apple Silicon and on iGPUs, unified memory means the pool is shared and the arithmetic changes.
See also: GPUs, transcoding and local AI, Ollama
W#
WAL mode
SQLite's write-ahead logging journal mode, which most self-hosted apps enable because it lets readers continue while a write is in progress. On disk you now have three files: app.db, app.db-wal and app.db-shm. Copying only the .db gives you a database missing every transaction still sitting in the WAL, which can be hours of work. Either stop the service and copy all three, or use the online backup API: sqlite3 app.db ".backup /tmp/app.db", or VACUUM INTO. rsync of a live .db is the single most common cause of a backup that restores to a broken app.
See also: Backing up a running database, Backup planner
WebDAV
HTTP extended with filesystem verbs (PROPFIND, MKCOL, MOVE, LOCK) so a remote directory can be mounted like a drive. It is implemented almost everywhere and it is uniformly slow, because every operation is a separate request: listing a large folder or copying thousands of small files crawls, and many clients cache badly enough to lose changes. Use it as a compatibility layer for an app that speaks nothing else. For actual file sync use the native client of Nextcloud or Syncthing.
See also: Syncthing, Syncthing vs Nextcloud
Websocket upgrade
The HTTP 101 handshake that turns a request into a persistent bidirectional connection. A reverse proxy has to pass the Upgrade and Connection headers, speak HTTP/1.1 upstream and hold the connection open for a long timeout. Caddy does this without configuration; nginx needs the headers set explicitly and a proxy_read_timeout well above the default 60 seconds. The symptom of getting it wrong is unmistakable once you know it: the page loads perfectly and then nothing ever updates. Live logs, terminals, notifications and progress bars all go quiet.
See also: Reverse proxy generator, Reverse proxy and TLS
Wildcard certificate
A certificate for *.example.com. It matches exactly one label, so jellyfin.example.com is covered, a.b.example.com is not, and the bare example.com is not either unless it is added as a separate name. It requires the DNS-01 challenge. The practical reason self-hosters want one is not convenience but privacy: every certificate issued for a specific hostname is published in public Certificate Transparency logs, so per-service certificates publish a list of what you run. A wildcard publishes nothing beyond the domain.
See also: Reverse proxy and TLS, Reverse proxy generator
WireGuard
A VPN protocol in the Linux kernel, small enough to audit, with no cipher negotiation: one modern suite, take it or leave it. Peers are identified by public key, traffic is UDP, and an interface that receives an unauthenticated packet answers nothing at all, so a port scan finds no service. What it deliberately omits is everything around the tunnel: no user accounts, no key distribution, no dynamic routing. That gap is what wg-easy, Tailscale and Headscale fill, and it is why raw WireGuard is a chore past about five devices.
See also: wg-easy, Remote access without port forwarding
Write hole
On parity RAID, a stripe's data blocks and its parity block are written separately. Lose power in between and the parity no longer matches the data, with nothing on disk to say so. A later rebuild then reconstructs plausible garbage silently. mdadm mitigates this with a write journal or partial parity log, hardware controllers with a battery-backed cache. ZFS avoids the problem by design: every write is copy-on-write to a variable-width stripe with a new transaction group, so a half-finished write is simply never referenced.
See also: ZFS, btrfs, mdadm or one disk
Z#
ZFS dataset
A named filesystem inside a pool that shares free space with its siblings and carries its own properties: compression, recordsize, quota, snapshot schedule. Datasets are the unit of snapshotting, of zfs send, and of permission delegation, so the practical advice is one per service rather than a pile of directories in a single dataset. Otherwise every rollback is all or nothing, and you cannot replicate one application without dragging the rest along. They cost nothing to create; make more of them than feels necessary.
See also: ZFS, btrfs, mdadm or one disk, Proxmox vs TrueNAS