Skip to content

VPS (cloud droplet)

The VPS is the public-facing edge of the estate. Since the backup leg was retired on 2026-08-11 it no longer stores or receives any backup data — its jobs are purely network-facing.

Roles at a glance

Role What it does Where it lives
NPM reverse proxy Terminates web traffic on 80/443, passes Minecraft UDP straight through Docker, /home/elliott/npm/
RustDesk relay Self-hosted remote-desktop rendezvous/relay (hbbs + hbbr) Docker, /opt/rustdesk/
WireGuard hub wg0 10.10.0.1/24, carries the Minecraft game traffic home /etc/wireguard/ (root) — see WireGuard
Tailscale node Member of the tailnet (100.75.121.110) tailscaled

Pending operator actions (audit 2026-08-12)

  • Reboot — uptime is past 355 days; a reboot is pending to pick up kernel updates.
  • Tailscale accept-routes — the VPS has not yet run sudo tailscale set --accept-routes, so it cannot reach the LAN (192.168.1.0/24) via the ops subnet router. See Tailscale.
  • RustDesk ports — exposure review done 2026-08-12: 21115–21119 verified closed to the public (tailnet-only). See below and Remote desktop.

Nginx Proxy Manager

Runs as a single Docker container (jc21/nginx-proxy-manager:latest) defined in /home/elliott/npm/docker-compose.yml, with config in ./data and certificates in ./letsencrypt.

Published ports:

Port Proto Purpose
80 TCP HTTP (redirects / ACME)
443 TCP HTTPS
19132 UDP Minecraft — Creative
19134 UDP Minecraft — Survival
19136 UDP Minecraft — Survival World (classic)

The admin panel port (81) is deliberately not published — it is commented out in the compose file. To use the panel, temporarily publish it (or tunnel to it) and close it again afterwards.

The Minecraft UDP ports are stream passthroughs: NPM forwards them over the WireGuard tunnel to the Minecraft VM at 10.10.0.2. See WireGuard and the Minecraft runbook.

TODO: export the proxy-host rules to this page

The actual proxy-host and stream rules (which hostname maps to which backend, which streams forward where) live only inside NPM's SQLite database (/home/elliott/npm/data/). They are not documented anywhere else. Next time the panel is opened — or via a sudo sqlite3 read of the database — copy the rule list into a table here. Until then this page only knows the ports, not the rules.

RustDesk relay

Self-hosted OSS remote desktop (hbbs + hbbr) in Docker under /opt/rustdesk/, set up by /home/elliott/rustdesk-setup/rustdesk-setup.sh (idempotent, root). VPN-only via Tailscale — full detail, client onboarding and the security model live on the dedicated Remote desktop (RustDesk) page.

RustDesk uses ports 21115–21119, all tailnet-only.

Port review closed — 2026-08-12

External scan confirmed 21115–21119 are closed to the public and open only over the tailnet. The containers use network_mode: host (not -p publishing), so Docker adds no rules that bypass UFW — the audit's "Docker may be publishing around UFW" worry does not apply here. See Remote desktop.

SSH and firewall

Hardening applied by /home/elliott/vps-harden.sh (run with sudo):

  • SSH on port 2222, key-only. No password auth.
  • fail2ban: default jail bans for 1h after 5 failures in 10m; the sshd jail is stricter — 3 failures on port 2222 → 24h ban.
  • UFW: default deny incoming, allow outgoing. Allowed in:
Port Proto Comment
2222 TCP SSH
80 TCP NPM HTTP
443 TCP NPM HTTPS
51820 UDP WireGuard
19132 UDP Minecraft Creative
19134 UDP Minecraft Survival

19136 is in Docker but not in the UFW script

The compose file publishes 19136/udp (Survival World classic) but the harden script's UFW rules stop at 19134. Docker typically bypasses UFW for published ports, so it probably works anyway — but the script and reality have drifted. Worth reconciling next time the harden script runs.

Operational notes

  • No passwordless sudo — by design. Interactive commands needing root will prompt; automation should not assume root on this box.
  • Backup leg fully retired (2026-08-11). No rsync push from the LAN, no retention timers, old tarballs deleted. If you find backup remnants here, they are safe to remove. Offsite copies are handled elsewhere — see offsite backups.
  • If the VPS is unreachable, see oh no: unreachable.