Server Cheat Sheet

Reference card for skyhouse.dev

The "what is what / where is what" reference for this server. For "something is wrong, what do I do" see the Troubleshooting Guide; for full prose orientation see /home/plex/docs/server-context.md. Verified 2026-05-20.

1. Network & access

ItemValue
Host / LAN IPplex192.168.1.136 (static DHCP reservation)
SSHport 2222 (not 22) — ssh -p 2222 plex@skyhouse.dev
TopologyISP modem (bridge mode) → GL.iNet router (fw v4.8.4, 192.168.1.1) → server
Router port-forwardsWAN 80, 443, 32400, 2222 → 192.168.1.136 (same ports)
Emergency hostnamecw526dc.glddns.com — GL.iNet DDNS, always tracks current WAN IP
DNSCloudflare anycast NS (luciane/remy.ns.cloudflare.com) for skyhouse.dev, botaa.org, room101.com (registered at Dynadot). All records DNS-only (grey cloud) → origin 174.21.187.113. Apex = flattened CNAME → cw526dc.glddns.com (router DDNS) so IP changes self-heal; * wildcard → apex. room101 email = Cloudflare Email Routing. dns-monitor.sh notifies only.

2. Port map

Red = forwarded to the internet. Green = LAN / localhost only.

PortServiceScope
80 / 443Nginx Proxy Manager — HTTP / HTTPS for every subdomainPublic
81NPM admin UI — manages all proxy hosts & certsLAN only (UFW-restricted)
32400Plex Media Server (main)Public (Plex remote access)
32401Plex (local control)localhost
2222SSH / SFTPPublic
9443 / 9000Portainer — the web UI that manages all Docker containers (9443 = HTTPS, preferred)LAN only
2283Immich (photos)LAN; public via photos.skyhouse.dev
3000Pairdrop (file sharing)LAN; public via share.skyhouse.dev
5001SharedmomentsLAN; public via btst.skyhouse.dev
8000 / 8001Music Discovery — client / API serverLAN; public via music.skyhouse.dev
3001Uptime Kuma (status page)LAN; public via status.skyhouse.dev
19999Netdata (system monitoring)LAN; public via monitor.skyhouse.dev
8989Sonarr (TV PVR)LAN only (external access not yet wired — see 2026-05-28 journal)
7878Radarr (Movie PVR)LAN only (external access not yet wired)
6500rdt-client (Real-Debrid client)LAN only
8123Home Assistant (host-networked)LAN; public via ha.skyhouse.dev
8095Music Assistant (host-networked)LAN; public via ma.skyhouse.dev
9876ddns-go UI — legacy, slated for retirementLAN only
53systemd-resolved (local DNS stub)localhost
internalVaultwarden :80, immich Postgres :5432, immich Redis :6379, npm-db MariaDB :3306, npm-php :9000Docker network only (no host port)

3. Reverse-proxy (subdomain) map

Authoritative hostname → backend, as configured in Nginx Proxy Manager.

HostnameBackend
skyhouse.devstatic site — /home/plex/www (legacy sites served as path subfolders, e.g. /randoma)
plex.skyhouse.dev192.168.1.136:32400
photos.skyhouse.dev192.168.1.136:2283 (Immich)
music.skyhouse.dev192.168.1.136:8000 (/api → :8001)
vault.skyhouse.devvaultwarden:80 — LAN-allowlisted, not public
share.skyhouse.dev192.168.1.136:3000 (Pairdrop)
btst.skyhouse.dev192.168.1.136:5001 (Sharedmoments)
monitor.skyhouse.dev192.168.1.136:19999 (Netdata)
status.skyhouse.dev192.168.1.136:3001 (Uptime Kuma)
router.skyhouse.devhttps://192.168.1.1 (GL.iNet admin)
portainer.skyhouse.devhttps://192.168.1.136:9443 (Portainer)
npm.skyhouse.devhttp://127.0.0.1:81 (NPM admin — LAN only)
sonarr.skyhouse.dev192.168.1.136:8989 (Sonarr)
radarr.skyhouse.dev192.168.1.136:7878 (Radarr)
rdtclient-tv.skyhouse.dev192.168.1.136:6500 (RDTClient TV — cache-only, for Sonarr)
rdtclient-movies.skyhouse.dev192.168.1.136:6501 (RDTClient Movies — open slots, for Radarr)
prowlarr.skyhouse.dev192.168.1.136:9696 (Prowlarr — indexer manager)
ha.skyhouse.dev192.168.1.136:8123 (Home Assistant — host IP, not a container name; WebSockets on)
ma.skyhouse.dev192.168.1.136:8095 (Music Assistant — host IP; WebSockets on + hardened Advanced location block for its auth handshake)
room101.comstatic — /home/plex/www/room101
botaa.org / share.botaa.org / smut.botaa.orgstatic / Pairdrop / Plex (group connect URL)

4. Service inventory

Docker containers (21)

ContainerPurposeCompose dir
npm-app-1 / npm-db-1 / npm-php-1Nginx Proxy Manager + MariaDB + PHP-FPM/home/plex/npm
immich_server / _postgres / _machine_learning / _redisImmich photo platform (4-container stack)/home/plex/immich-app
music-discovery-client / -serverNext.js music app + API/home/plex/music_discovery
uptime-kumaService uptime monitoring/home/plex/uptime-kuma
vaultwardenPassword vault (Bitwarden-compatible)standalone docker run
pairdropCross-device file sharingstandalone
sharedmomentsShared photo albumstandalone (network btst_default)
portainerDocker management web UI — pinned to portainer-ee:2.42.0 after May 27 :latest drift (journal)standalone
prowlarrIndexer manager for Sonarr & Radarrportainer stack, port 9696
sonarrTV PVR — library at /media/plex2/TV, config at /home/sonarr/data. After the split-rdtclient migration, root folder inside container = /data/TV (journal)portainer stack, port 8989
radarrneeds /media/plex1 (hotplug DAS); restart=no — started via das-up.sh after attaching the DAS. Movie PVR — library at /media/plex1/Movies, config at /home/radarr/data. After split, root folder = /data/Movies; download client reaches rdt-client by Docker service name on the internal port (rdtclient-movies:6500, not host-IP:6501) (journal, rewiring, plex1 offline)portainer stack, port 7878
rdtclientRDTClient TV (for Sonarr; intended cache-only but not actually gated — see 2026-05-29 journal) — downloads to /media/plex2/torbox_downloads, db at /home/rdtclient/db (journal)portainer stack, port 6500
rdtclient-moviesneeds /media/plex1 (hotplug DAS); restart=no — started via das-up.sh after attaching the DAS. RDTClient Movies (open slots, for Radarr) — downloads to /media/plex1/torbox_downloads, db at /home/plex/rdtclient-movies/db. Compose at /home/plex/rdtclient-movies/docker-compose.yml (journal, plex1 offline)docker compose (outside Portainer), port 6501
homeassistantHome Assistant — network_mode: host, port 8123. Config at /opt/appdata/homeassistant/config. HubZ Zigbee/Z-Wave stick passed through via two /dev/serial/by-id paths → ttyUSB0/ttyUSB1. Also mounts /etc/localtime + /run/dbus. [journal]portainer stack home-assistant, port 8123
music-assistantMusic Assistant — network_mode: host, port 8095. Data at host /home/music-assistant → container /data; library /media/plex3/Music mounted ro. Caps: SYS_ADMIN, DAC_READ_SEARCH, apparmor:unconfined. [journal]portainer stack home-assistant, port 8095
ddns-goLegacy DDNS updater — slated for retirementstandalone

systemd services (non-stock)

plexmediaserver · netdata · fail2ban · smartmontools · ssh (port 2222) · docker / containerd. (openvpn was disabled in the 2026-05 cleanup.) Note: plexmediaserver is temporarily masked as of 2026-06-04 (plex1 SATA link wedged); systemctl unmask plexmediaserver to restore. [journal]

5. Key paths

WhatPath
Web root/home/plex/www
Server journal & these docs/home/plex/www/serverjournal/
Plex config / library DB/var/lib/plexmediaserver/Library/Application Support/Plex Media Server/
Docker data root/var/lib/docker (on the OS disk)
NPM config & certs/home/plex/npm/data/, /home/plex/npm/letsencrypt/
Maintenance scripts/usr/local/bin/ and /home/plex/bin/ and /home/plex/*.sh
Logs/var/log/plex-backup.log, ~/.cache/ip-watch.log, ~/.cache/nextjs-check.log
Secrets (locations only)/etc/telegram_notify.conf, ~/.messaging-keys, /etc/netdata/health_alarm_notify.conf, /home/plex/npm/data/.htpasswd
Orientation docs/home/plex/docs/ — server-context.md, server-audit-2026-05.md, server-runbook.md, disk-cutover-guide.md
Audit archive (movable junk)/home/plex/archive/2026-05-cleanup/

6. Cron schedule (user plex)

WhenJobPurpose
*/5 * * * *cpu_watchdog.shHigh-CPU alerting
*/5 * * * *bin/dns-monitor.shCloudflare-era DNS notifier (🌐 IP-changed / ✅ resynced / ⚠️); no DNS writes
0 3 * * *backup-plex3.shrsync plex3 → plex3_backup
30 3 * * *backup-plex2.shdisabled (sdb degraded)
30 4 * * *backup-plex1.shrsync plex1 → plex1_backup — paused 2026-06-04 (plex1 SATA link wedged). [journal]
30 3 * * *bin/arr-config-backup.sh*arr + rdt-client config snapshot (settings/API-keys/DBs) → /media/plex3_backup/config-backups/, keep 14. Stops the stack ~15s for a consistent SQLite copy. Restore with bin/arr-config-restore.sh. [journal]
0 4 * * *plex-checkPlex version alert
0 5 * * *nextjs-checkNext.js version alert

7. Storage & drives

DeviceMountRole
1 TB SSD "SSV8" (AA0…2477)/ + /boot/efiOS disk — replaced the ancient Corsair via live ddrescue clone 2026-06-03; root ext4 grown to 938 GB (UUID 879bcc42-…). [journal]
sdc1 (14 TB)/media/plex1Media — ~92% full
sdh1 (14 TB, ext4)/media/plex1_backupBackup of plex1 (USB ext.) — reformatted NTFS→ext4 2026-05-31, UUID 70d95e9e-…. [journal]
sdg1 (14 TB)/media/plex2Media
(removed)/media/plex2_backupDead drive retired — WD 9RHHSV3L (5,483 offline-uncorrectable, confirmed 2026-06-04 even via toaster) physically removed; backup-plex2.sh cron stays disabled (no target). [journal]
sdd1 (12 TB)/media/plex3Media; also holds swapfile_extra
sde1 (10 TB)/media/plex3_backupBackup of plex3
Kingston 128 GB SSD (203S10Q4T73Z)/media/scratchScratch disk (internal SATA, ext4 117 GB, UUID 46b67b3d-…) — hosts Plex transcode temp (/media/scratch/transcode). Disposable: ~9.8 yr-old SSD, nothing irreplaceable here. nofail. [journal]

Swap: /swapfile 4 GB (OS disk) + /media/scratch/swapfile_extra 32 GB (scratch SSD, sw,nofail) — 35 GB total. Moved off plex3 → scratch 2026-06-04. Media drives mount by UUID in /etc/fstab with nofail. [Journal: 2026-06-04]

SMART monitoring (rebuilt by-id 2026-06-04): /etc/smartd.conf lists every present drive explicitly by serial (/dev/disk/by-id/ata-<model>_<serial> -d sat, no DEVICESCAN) — boot SSD, scratch SSD, plex1, plex2, plex3, plex1_backup. The detachable toaster drive plex3_backup uses -d removable (auto-detects as SAT when present, and lets smartd survive it being unplugged). ⚠ smartd EXITS (status 16) if a non-removable listed device is absent — so when you retire or move a drive you MUST drop/adjust its by-id line, or smartd dies silently at next boot (exactly what a stale Corsair line did after the 6/3 boot swap). netdata's smartctl collector (/etc/netdata/go.d/smartctl.conf) now monitors everything present (device_selector: '* *', no /dev/sdX exclusion) — the JMicron bridge that once hung it is gone, and netdata only scans present devices, so it's shuffle-proof. Backups: /etc/smartd.conf.bak-20260604, /etc/netdata/go.d/smartctl.conf.bak-20260604. [Journal: 2026-06-04]

8. Maintenance scripts

ScriptDoes
sudo plex-updateDownload + install latest Plex Media Server
plex-check / nextjs-checkVersion checks — Telegram alert if behind
cpu_watchdog.shAlerts on sustained high CPU by non-allowlisted procs
telegram_notify.shShared Telegram-send helper used by the others
bin/dns-monitor.shCloudflare-era notifier: Telegram on IP-change + resync confirm + ⚠️; no DNS writes, no API token (2026-06-07)
bin/lib-pubip.shHardened multi-source public-IP fetch (used by dns-monitor)
Dynadot-era (RETIRED, rollback-only):ip-watch.sh, dns-watchdog.sh, ip-recovery-verify.sh, dns-push.sh, dynadot-update.py — only useful if reverting NS to Dynadot
backup-plex{1,2,3}.sh + robust_rsync.shNightly media mirroring. plex1 rsync runs as root via /usr/local/sbin/backup-plex1-rsync.sh (sudo NOPASSWD) so it can read immich's root-owned library
bin/pre-swap-config-backup.shOne-shot (run manually) pre-boot-disk-swap safety backup: DB dumps (immich PG, NPM MariaDB, vaultwarden) + all configs/certs/compose//etc/media/plex3/pre-swap-backup-<date>/. See swap runbook
bin/arr-config-backup.shNightly (03:30) consistent snapshot of the media-download stack's config — sonarr/radarr/prowlarr/rdtclient(-movies) settings, API keys, and SQLite DBs → /media/plex3_backup/config-backups/arr-config-<ts>.tar.gz (~40 MB, keep 14). Briefly stops the stack so WAL is checkpointed; refuses to run if the dest drive isn't mounted. [journal]
bin/arr-config-restore.shRestore the above after a settings loss. arr-config-restore.sh (no args) lists snapshots; arr-config-restore.sh latest or … <file> restores (prompts y/N). Saves a pre-restore-<ts>.tar.gz of current state first, so the restore is itself reversible. Then in Prowlarr: Settings → Apps → Sync App Indexers if indexers look off.
lock_ssh.sh / unlock_ssh.shDisable / enable SSH password auth (key-only toggle)

9. Verification checklist

Copy-paste to confirm the server is healthy — e.g. after a reboot or the disk swap. Each line prints OK / a status when good.

Services

systemctl is-active plexmediaserver netdata fail2ban ssh smartmontools
for c in npm-app-1 immich_server music-discovery-client music-discovery-server \
         vaultwarden pairdrop sharedmoments portainer uptime-kuma ddns-go; do
  printf '%-26s ' "$c"; docker inspect -f '{{.State.Status}}' "$c" 2>/dev/null || echo MISSING
done
curl -sf http://localhost:2283/api/server/ping        # Immich -> {"res":"pong"}

Mounts & freshness

for m in / /media/plex1 /media/plex2 /media/plex3 /media/scratch \
         /media/plex1_backup /media/plex3_backup; do  # plex2_backup drive retired 6/4
  printf '%-24s ' "$m"; mountpoint -q "$m" && echo OK || echo "NOT MOUNTED"
done
find /var/log/plex-backup.log -mtime -2 | grep -q . && echo "backups fresh"
find ~/.cache/ip-watch.log    -mtime -1 | grep -q . && echo "ddns log fresh"

External reachability

curl -s ifconfig.me ; echo                # current public IP
dig +short skyhouse.dev @1.1.1.1          # should match the line above

10. Accounts & externals

AccountDetail
DynadotRegistrar + DNS for skyhouse.dev, room101.com, botaa.org (the dsm-iii/dsm-3 domains exist; hosting retired)
GL.iNet router192.168.1.1 — firmware v4.8.4
Telegram bot@skyhouse_server_bot — all alert delivery. Credentials in the 3 secret files listed in §5; rotating means updating all three.
Plex.tvaccount damienmjones

11. Quirks & gotchas

← Back to Admin Hub