Files
nixos-servers/docs/plans/remote-access.md
Torjus Håkestad fcc410afad
Some checks failed
Run nix flake check / flake-check (push) Has been cancelled
docs: replace ASCII diagram with mermaid in remote-access plan
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 16:28:57 +01:00

4.7 KiB

Remote Access to Homelab Services

Status: Planning

Goal

Enable personal remote access to selected homelab services from outside the internal network, without exposing anything directly to the internet.

Current State

  • All services are only accessible from the internal 10.69.13.x network
  • http-proxy has a WireGuard tunnel (wg0, 10.69.222.0/24) to a VPS (docker2.t-juice.club) on an OpenStack cluster
  • VPS runs Traefik which proxies selected services (including Jellyfin) back through the tunnel to http-proxy's Caddy
  • No other services are directly exposed to the public internet

Decision: WireGuard Gateway

After evaluating WireGuard gateway vs Headscale (self-hosted Tailscale), the WireGuard gateway approach was chosen:

  • Only 2 client devices (laptop + phone), so Headscale's device management UX isn't needed
  • Split DNS works fine on Linux laptop via systemd-resolved; all-or-nothing DNS on phone is acceptable for occasional use
  • Simpler infrastructure - no control server to maintain
  • Builds on existing WireGuard experience and setup

Architecture

graph TD
    clients["Laptop / Phone\n(WireGuard clients)"]

    vps["VPS (OpenStack)\nWireGuard endpoint\nClient peers: laptop, phone\nRoutes 10.69.13.0/24 via tunnel"]

    extgw["extgw01 (gateway + bastion)\nWireGuard tunnel to VPS\nFirewall (allowlist only)\nSSH + 2FA (full access)"]

    internal["Internal network 10.69.13.0/24"]
    grafana["monitoring01:3000\nGrafana"]
    jellyfin["jelly01:8096\nJellyfin"]
    arr["*-jail hosts\narr stack"]

    clients -->|"WireGuard"| vps
    vps -->|"WireGuard tunnel"| extgw
    extgw -->|"allowed traffic only"| internal
    internal --- grafana
    internal --- jellyfin
    internal --- arr

Existing path (unchanged)

The current public access path stays as-is:

Internet → VPS (Traefik) → WireGuard → http-proxy (Caddy) → internal services

This handles public Jellyfin access and any other publicly-exposed services.

New path (personal VPN)

A separate WireGuard tunnel for personal remote access with restricted firewall rules:

Laptop/Phone → VPS (WireGuard peers) → tunnel → extgw01 (firewall) → allowed services

Access tiers

  1. VPN (default): Laptop/phone connect to VPS WireGuard endpoint, traffic routed through extgw01 firewall. Only whitelisted services are reachable.
  2. SSH + 2FA (escalated): SSH into extgw01 for full network access when needed.

New Host: extgw01

A NixOS host on the internal network acting as both WireGuard gateway and SSH bastion.

Responsibilities

  • WireGuard tunnel to the VPS for client traffic
  • Firewall with allowlist controlling which internal services are reachable through the VPN
  • SSH bastion with 2FA for full network access when needed
  • DNS: Clients get split DNS config (laptop via systemd-resolved routing domain, phone uses internal DNS for all queries)

Firewall allowlist (initial)

Service Destination Port
Grafana monitoring01.home.2rjus.net 3000
Jellyfin jelly01.home.2rjus.net 8096
Sonarr sonarr-jail.home.2rjus.net 8989
Radarr radarr-jail.home.2rjus.net 7878
NZBget nzbget-jail.home.2rjus.net 6789

SSH 2FA options (to be decided)

  • Kanidm: Already deployed on kanidm01, supports RADIUS/OAuth2 for PAM integration
  • SSH certificates via OpenBao: Fits existing Vault infrastructure, short-lived certs
  • TOTP via PAM: Simplest fallback, Google Authenticator / similar

VPS Configuration

The VPS needs a new WireGuard interface (separate from the existing http-proxy tunnel):

  • WireGuard endpoint listening on a public UDP port
  • 2 peers: laptop, phone
  • Routes client traffic through tunnel to extgw01
  • Minimal config - just routing, no firewall policy (that lives on extgw01)

Implementation Steps

  1. Create extgw01 host configuration in this repo
    • VM provisioned via OpenTofu (same as other hosts)
    • WireGuard interface for VPS tunnel
    • nftables/iptables firewall with service allowlist
    • IP forwarding enabled
  2. Configure VPS WireGuard for client peers
    • New WireGuard interface with laptop + phone peers
    • Routing for 10.69.13.0/24 through extgw01 tunnel
  3. Set up client configs
    • Laptop: WireGuard config + systemd-resolved split DNS for home.2rjus.net
    • Phone: WireGuard app config with DNS pointing at internal nameservers
  4. Set up SSH 2FA on extgw01
    • Evaluate Kanidm integration vs OpenBao SSH certs vs TOTP
  5. Test and verify
    • VPN access to allowed services only
    • Firewall blocks everything else
    • SSH + 2FA grants full access
    • Existing public access path unaffected