Networking / Note 01
Network Topology
In this note
Master overview of the current and planned Open Lab Frame homelab network.
Homelab Overview | Pi-hole | Tailscale | Nginx Proxy Manager | VPS Caddy | Proxmox Host
Current Network Overview
The homelab currently uses:
Starlink
as the Internet connection.
Starlink is configured in bypass mode , allowing the:
TP-Link Archer BE550
to act as the primary household router.
Current high-level topology:
Internet
↓
Starlink
↓
TP-Link Archer BE550
↓
Home LAN
│
├── HP ProDesk 600 G4 / Proxmox
├── Raspberry Pi 5
├── Raspberry Pi 3
├── Personal PC
├── Wi-Fi devices
└── Normal household devices
The homelab is designed to remain:
Opt-in
+
Administratively private
Normal household users should not need to participate in:
Pi-hole DNS
Tailscale
Internal homelab DNS
Nginx Proxy Manager
Proxmox administration
Homelab experiments
Internet Connection
Primary Internet connection:
Starlink
Current design:
Internet
↓
Starlink
↓
BE550
The network is intentionally being kept simple and uses a single Starlink connection with the Archer BE550 as the primary router.
Current Router
Current router:
TP-Link Archer BE550
Responsibilities:
NAT
DHCP
LAN routing
Wi-Fi
General household Internet access
Main home-network gateway
Starlink remains in bypass mode while the BE550 performs the actual router role.
The BE550 is also planned to remain the main router and Wi-Fi device in the future.
Current Switching
Current small switch:
TP-Link TL-SG105S-M2
Capabilities:
5 ports
2.5GbE
Unmanaged
It currently provides wired connectivity for selected homelab equipment.
A managed Omada switch is planned as the future wired distribution layer.
Current Core Systems
Current Logical Topology
Internet
↓
Starlink
↓
TP-Link Archer BE550
↓
<private home LAN>
│
┌───────────────────┼───────────────────┐
│ │ │
↓ ↓ ↓
HP ProDesk Raspberry Pi 5 Raspberry Pi 3
<private Proxmox host> <private Pi 5 host> <private Pi 3 host>
│ │ │
│ │ ├── Pi-hole
│ │ ├── Tailscale DNS
│ │ └── Subnet routing
│ │
│ ├── Open Lab Frame
│ ├── Uptime Kuma
│ ├── Beszel
│ ├── Grafana
│ ├── Prometheus
│ └── Cloudflare Tunnel
│
└── Proxmox
│
├── VM100 - <private Jellyfin host>
├── VM101 - <private development host>
└── VM102 - <private management host>
DNS Architecture
Pi-hole
Raspberry Pi 3 hosts Pi-hole .
Current Pi 3:
Hostname: <pi3-hostname>
Network: Private LAN
SSH: ssh <pi3-alias>
Pi-hole is intentionally:
OPT-IN
It is not the required DNS server for the entire household.
Normal Household DNS
Friends, family, guests, TVs, and normal household devices can continue using ordinary router/network behavior.
Normal Household Device
↓
Archer BE550
↓
Normal DNS
↓
Starlink
↓
Internet
These clients should not depend on:
Pi-hole
Tailscale
Proxmox
NPM
Internal homelab DNS
Homelab-Aware Devices
Selected personal/admin devices can use Pi-hole intentionally.
Personal Device
↓
Pi 3 / Pi-hole
↓
Homelab-aware DNS
↓
Internal services
+
Internet
This allows private service names without changing normal household behavior.
Private Internal DNS
Most private service names use:
<private internal wildcard>
Pi-hole generally resolves these hostnames to:
<private management host>
which is:
VM102 - Management
running:
Nginx Proxy Manager
Internal DNS Architecture
Client
↓
Pi-hole
↓
service.<private internal domain>
↓
<private management host>
↓
VM102 / NPM
↓
Actual backend service
Pi-hole answers:
Where is the service?
NPM answers:
Which backend should receive the HTTPS request?
Current Internal Service Names
Examples:
<private development hostname>
<private monitoring hostname>
<private proxy-admin hostname>
<private container-admin hostname>
<private Beszel hostname>
Nginx Proxy Manager
Nginx Proxy Manager runs on:
VM102
<private management host>
Its responsibilities include:
Private HTTPS
Friendly internal hostnames
Reverse proxying
Central internal service routing
General path:
Client
↓
Pi-hole
↓
<private management host>
↓
NPM
↓
Backend
NPM Route - Beszel
Friendly URL:
<private Beszel URL>
Path:
<private Beszel hostname>
↓
<private management host>
↓
NPM
↓
<private Pi 5 host>:<SERVICE_PORT>
↓
Beszel Hub
NPM Route - Grafana
<private monitoring hostname>
↓
<private management host>
↓
NPM
↓
<private Pi 5 host>:<SERVICE_PORT>
↓
Grafana
NPM Route - Portainer
<private container-admin hostname>
↓
<private management host>
↓
NPM
↓
Portainer
NPM Route - NPM
<private proxy-admin hostname>
↓
<private management host>
↓
NPM
↓
NPM Admin Interface
NPM Route - Open Lab Frame Development
<private development hostname>
↓
<private management host>
↓
NPM
↓
<private development host>:<SERVICE_PORT>
↓
VM101
VM101 - OpenLabFrame Dev is normally powered off unless website development is actively taking place.
Therefore:
<private development hostname> offline
is normally expected while VM101 is off.
Tailscale
Tailscale provides the private remote-access layer.
It allows selected personal devices to reach private homelab services while away from home.
Raspberry Pi 3 Tailscale Role
Raspberry Pi 3 provides:
Pi-hole DNS
Tailscale DNS
Subnet routing
Private LAN reachability
The Pi 3 helps remote personal devices resolve and reach:
<private home LAN>
services.
Raspberry Pi 5 Tailscale Role
Raspberry Pi 5 provides:
Tailscale connectivity
Exit-node functionality
Private application access
It also hosts several private applications that may be reached through Tailscale.
VM100 Tailscale
VM100 - Jellyfin has a Tailscale address:
<private Jellyfin Tailscale endpoint>
This is used for:
Private Jellyfin access
VPS → Jellyfin connectivity
Secure remote communication
Remote Personal Access
When a personal device is away from home:
iPhone / Laptop
↓
Tailscale
↓
Pi 3 DNS + subnet routing
↓
Home LAN
↓
Private services
Example:
iPhone on 5G
↓
Tailscale
↓
Pi 3 DNS
↓
↓
<private management host>
↓
NPM
↓
This allows private hostnames to work both:
At Home
+
Away Through Tailscale
without publicly exposing the service.
Home Wi-Fi Is Still LAN
A device does not need to be physically connected by Ethernet to use the local network.
Example:
iPhone
↓
BE550 Wi-Fi
↓
Home LAN
↓
<private home LAN> services
Home Wi-Fi clients can communicate locally unless intentionally isolated.
Jellyfin Networking
Local Jellyfin Path
At home:
iPhone on Wi-Fi
↓
Pi 3 DNS
↓
<private Jellyfin host>
↓
VM100 / Jellyfin
A Jellyfin session was observed from:
<private local client>
confirming that the iPhone was communicating with Jellyfin directly through the home LAN.
Private Remote Jellyfin Path
Away from home, a personal device can use Tailscale.
Observed iPhone Tailscale address:
<private remote Tailscale client>
Path:
iPhone
↓
Tailscale
↓
VM100
<private Jellyfin Tailscale endpoint>
↓
Jellyfin
Public Jellyfin / Friend Path
Friends and other normal remote users use the public VPS path.
Remote User
↓
Internet
↓
jellyfin.openlabframe.com
↓
VPS
↓
Caddy
↓
Tailscale
↓
VM100
<private Jellyfin Tailscale endpoint>:<SERVICE_PORT>
↓
Jellyfin
Nginx Proxy Manager is not part of this path.
VPS
Current VPS public address:
<public VPS address omitted>
Windows SSH alias:
ssh <vps-alias>
The VPS provides a publicly reachable ingress point because the Starlink home connection operates behind CGNAT.
VPS Caddy
VPS Caddy provides the public Jellyfin reverse proxy.
Conceptual configuration:
jellyfin.openlabframe.com {
reverse_proxy <private Jellyfin Tailscale endpoint>:<SERVICE_PORT>
}
The VPS connects to VM100 through Tailscale.
Why VPS Is Used
Starlink CGNAT prevents the normal inbound IPv4 port-forwarding model from being the preferred public-access method.
Therefore:
Public Internet
↓
VPS
↓
Tailscale
↓
VM100
provides the required public ingress without directly opening the home network.
Cloudflare
Cloudflare is used separately for the public Open Lab Frame website.
Architecture:
Visitor
↓
Cloudflare
↓
Cloudflare Tunnel
↓
Raspberry Pi 5
↓
Nginx / ehworld
↓
Open Lab Frame
This is separate from both:
VPS / Jellyfin
and:
NPM / Private homelab services
Architecture Separation
The homelab intentionally uses different ingress technologies for different purposes.
Open Lab Frame
Cloudflare
→ Cloudflare Tunnel
→ Pi 5
Public Jellyfin
VPS Caddy
→ Tailscale
→ VM100
Private Internal Web Services
Pi-hole
→ VM102 NPM
→ Backend
Private Remote Access
Tailscale
→ Pi 3 DNS / subnet route
→ Home LAN
These paths should remain separate unless there is a real technical reason to combine them.
Monitoring
Uptime Kuma
Uptime Kuma runs on Raspberry Pi 5 .
It monitors important infrastructure and application availability.
Examples:
Proxmox
VM100
VM102
Jellyfin
Gluetun
ARR Stack
NPM
Portainer
Open Lab Frame
Alert flow:
Problem
↓
Uptime Kuma
↓
Discord
+
ntfy
↓
iPhone
Beszel
Beszel provides lightweight resource visibility.
Current monitored systems:
HP ProDesk - Proxmox
Pi 5
VM100 - Jellyfin
VM102 - Management
The Pi 3 is intentionally not included.
Beszel is used for:
CPU
Memory
Disk
Network
Temperature
Uptime
Docker/container visibility
Administrative Privacy
The homelab is administratively private.
Being connected to the home LAN does not automatically grant administrative access.
Protected systems include:
Proxmox
NPM
Portainer
Pi-hole
Uptime Kuma
Beszel
SSH
Other management services
Authentication remains required.
Future Managed Switch
Planned managed switch:
TP-Link Omada SG2210XMP-M2
Target features:
2.5GbE
PoE+
2 × 10Gb SFP+
Managed / Omada
It will become the primary wired distribution layer for the homelab.
Future Wired Topology
Internet
↓
Starlink
↓
TP-Link Archer BE550
↓
TP-Link Omada SG2210XMP-M2
│
├── NAS / Compute
├── HP ProDesk 600 G4
├── Raspberry Pi 5
├── Raspberry Pi 3
├── Homelab / Admin Clients
└── Other selected wired systems
The Archer BE550 remains:
Router
+
Wi-Fi
+
DHCP
+
NAT
+
Main household gateway
Future NAS / Compute
NAS Compute Build will eventually connect through the Omada managed switch.
Starlink
↓
BE550
↓
Omada Switch
↓
NAS / Compute
The NAS / compute system will eventually handle heavier:
Storage workloads
Media storage
Virtualization
Immich
Game-server storage
Backups
Other compute-heavy applications
Opt-In Homelab Design
The future network keeps the same basic philosophy as the current network.
Normal Household Devices
Phone / TV / Guest Device
↓
BE550
↓
Starlink
↓
Internet
They should not depend on:
Pi-hole
Tailscale
NPM
Internal DNS
Homelab services
Selected Homelab / Personal Devices
Personal Device
↓
Normal LAN
+
Optional Pi-hole
+
Optional Tailscale
↓
Homelab services
The fundamental rule is:
Household Network
≠
Mandatory Homelab Participation
Future VLANs
The Omada managed switch may eventually be used for VLAN experimentation.
Possible logical groups could include:
Management
Servers
Trusted Personal Devices
General Household Devices
IoT
Guests
VLANs are optional.
They should only be introduced when there is a clear benefit and should not unnecessarily complicate normal household Internet access.
Current vs Future
Current
Internet
↓
Starlink
↓
Archer BE550
↓
Current LAN
│
├── HP ProDesk / Proxmox
├── Raspberry Pi 5
├── Raspberry Pi 3
└── Clients
Future
Internet
↓
Starlink
↓
Archer BE550
↓
Omada SG2210XMP-M2
│
├── NAS / Compute
├── HP ProDesk
├── Raspberry Pi 5
├── Raspberry Pi 3
└── Homelab / Admin Clients
Design Principles
The network should continue following these rules:
Starlink remains the single Internet/WAN connection.
The Archer BE550 remains the primary router.
The Archer BE550 remains the main Wi-Fi device.
The Omada switch becomes the future managed wired distribution layer.
Homelab participation remains opt-in.
Household Internet should function independently of Pi-hole.
Household Internet should function independently of Tailscale.
Pi-hole remains optional for selected devices.
Tailscale remains the preferred private remote-access method.
NPM remains primarily for private/internal reverse proxying.
VPS/Caddy remains the public Jellyfin ingress path.
Cloudflare Tunnel remains the public Open Lab Frame ingress path.
Administrative services remain authenticated.
Private services should not be publicly exposed without a clear reason.
DNS, reverse proxying, routing, and remote access should remain clearly separated.
Network changes should be introduced gradually and tested before becoming permanent.
Related Notes
Homelab Overview
Pi-hole
Tailscale
Nginx Proxy Manager
VPS Caddy
Proxmox Host
HP ProDesk 600 G4
Raspberry Pi 5
Raspberry Pi 3
VM100 - Jellyfin
VM102 - Management
NAS Compute Build
Back to Networking
Networking / Note 02
Pi-hole
In this note
Private, opt-in DNS filtering and homelab name-resolution service running on the Raspberry Pi 3 .
Homelab Overview | Raspberry Pi 3 | Tailscale | Network Topology | Nginx Proxy Manager
Status
State: In use
Host: Raspberry Pi 3
Hostname: private / internal
Network: Private LAN
Role: DNS filtering + local DNS + Tailscale DNS integration
Operation: Always on
Purpose
Pi-hole provides DNS services for selected personal and homelab devices.
Its responsibilities include:
DNS filtering
Local DNS records
Friendly homelab hostnames
Internal service discovery
DNS for selected Tailscale clients
Integration with private remote access
Pi-hole is intentionally not the mandatory DNS server for the entire household .
Design Philosophy
The homelab DNS design is opt-in.
Normal Household Devices
Friends / Family
↓
Normal home Wi-Fi
↓
TP-Link router DNS
↓
Internet
These devices should continue working normally even if:
Pi-hole is restarted
Homelab DNS records change
Tailscale is unavailable
Internal services are being tested
Selected Personal Devices
Personal Device
↓
Pi-hole
↓
DNS filtering
↓
Local homelab record if applicable
↓
Internet / Internal service
This keeps homelab experimentation isolated from the rest of the household.
Host
Pi-hole runs on:
Raspberry Pi 3
Current Pi 3 details:
Hostname: <pi3-hostname>
Network: Private LAN
User: <admin-user>
SSH:
ssh <pi3-alias>
Upstream DNS
Pi-hole has used Cloudflare resolvers:
<public DNS resolver>
<public DNS resolver>
General resolution path:
Client
↓
Pi-hole
↓
Cloudflare DNS
↓
Internet
Local DNS records are answered internally without needing to query the upstream resolver.
Local DNS
Pi-hole provides local DNS records for homelab services.
The main internal pattern is:
<private internal wildcard>
Many of these names resolve to:
<private management host>
which is VM102 - Management running Nginx Proxy Manager .
Current Internal Records
Examples include:
<private development hostname>
→ <private management host>
<private monitoring hostname>
→ <private management host>
<private proxy-admin hostname>
→ <private management host>
<private container-admin hostname>
→ <private management host>
→ <private management host>
<private Beszel hostname>
→ <private management host>
NPM then forwards each hostname to the appropriate backend.
Why DNS Points to VM102
Pi-hole usually does not point these service names directly at the application server.
Instead:
Client
↓
Pi-hole
↓
service.<private internal domain>
↓
<private management host>
↓
VM102 / Nginx Proxy Manager
↓
Correct backend
This gives the homelab:
Friendly hostnames
Central HTTPS handling
Cleaner backend changes
One reverse-proxy entry point
Example: Beszel
Pi-hole record:
<private Beszel hostname>
→ <private management host>
Traffic path:
Client
↓
Pi-hole
↓
<private management host>
↓
NPM
↓
<private Pi 5 host>:<SERVICE_PORT>
↓
Beszel on Pi 5
Friendly URL:
<private Beszel URL>
Example: Grafana
Pi-hole record:
<private monitoring hostname>
→ <private management host>
NPM backend:
<private Pi 5 host>:<SERVICE_PORT>
Path:
Client
↓
Pi-hole
↓
VM102 / NPM
↓
Pi 5 / Grafana
Example: Open Lab Frame Development
Pi-hole record:
<private development hostname>
→ <private management host>
NPM backend:
<private development host>:<SERVICE_PORT>
Target:
VM101 - OpenLabFrame Dev
Because VM101 is intentionally powered off when not developing:
<private development hostname> unavailable
is normal while VM101 is off.
Jellyfin Local DNS
Pi-hole is also used to help selected devices take a direct local Jellyfin path.
Local Jellyfin server:
<private Jellyfin host>
Target:
VM100 - Jellyfin
At home:
iPhone on Wi-Fi
↓
Pi-hole DNS
↓
<private Jellyfin host>
↓
Jellyfin
An observed iPhone LAN address was:
<private local client>
which confirmed that the device was reaching Jellyfin directly over the home LAN instead of unnecessarily going out through the VPS and back.
Home Wi-Fi and LAN
A device does not need to be connected by Ethernet to use local DNS and local services.
A phone on the normal home Wi-Fi is still part of the home LAN unless it is intentionally isolated.
Example:
iPhone
↓
Wi-Fi
↓
Home LAN
↓
Pi-hole
↓
Internal service
Tailscale DNS Integration
Pi-hole also participates in the Tailscale design.
Selected remote devices can continue using homelab DNS while away from home.
Example:
iPhone on 5G
↓
Tailscale
↓
Pi 3 / Pi-hole
↓
↓
<private management host>
↓
NPM
↓
This lets the same private hostname work:
At home
+
Away through Tailscale
without publicly exposing the backend.
Pi 3 Subnet Routing
The Raspberry Pi 3 also provides Tailscale subnet-routing functionality.
This allows selected Tailscale clients to reach private LAN addresses such as:
<private Proxmox host>
<private Jellyfin host>
<private Pi 5 host>
<private management host>
while away from home.
DNS and routing work together:
Pi-hole
→ tells client which private IP to use
Tailscale subnet route
→ provides a path to that private IP
DNS vs Routing
Pi-hole does not carry the application traffic itself.
Its job is primarily:
Hostname
↓
IP address
For example:
↓
<private management host>
The actual HTTPS traffic then travels through the normal LAN or Tailscale network path.
Pi-hole and NPM
Pi-hole and Nginx Proxy Manager have different jobs.
Pi-hole
Name resolution
service.<private internal domain>
↓
<private management host>
NPM
HTTPS request arrives
↓
Read requested hostname
↓
Forward to correct backend
Together:
Client
↓
Pi-hole
↓
VM102
↓
NPM
↓
Application
Pi-hole and Cloudflare
The Pi-hole DNS service is separate from Cloudflare's role in the public Open Lab Frame website.
Pi-hole
Used for:
Private DNS
Filtering
Internal homelab names
Tailscale-connected personal devices
Cloudflare
Used for:
Public Open Lab Frame DNS
Cloudflare Tunnel
Public website delivery
CDN/caching
Public-facing protections
These systems should not be confused with each other.
Pi-hole and Jellyfin Public Access
Pi-hole is primarily relevant for the user's private/local Jellyfin access.
Friends using public Jellyfin access instead use:
Internet
↓
VPS Caddy
↓
Tailscale
↓
VM100
They do not need the Pi 3 to use the public Jellyfin service.
Monitoring
Pi-hole can be monitored through Uptime Kuma .
The Pi 3 itself is intentionally not currently included in Beszel .
This keeps the Beszel dashboard focused on:
Pi-hole is lightweight enough that detailed resource monitoring is not currently considered necessary.
Upstream DNS Troubleshooting
Pi-hole has previously logged upstream errors involving:
<public DNS resolver>#53
<public DNS resolver>#53
with messages similar to:
TCP connection failed while receiving payload length from upstream
Resource temporarily unavailable
These should be treated separately from local DNS records.
For example:
This example was not included in the public notes.
can still be a valid local record even if an unrelated upstream Cloudflare DNS request experiences a temporary failure.
Useful Troubleshooting Concepts
Local DNS Record Works
If:
This example was not included in the public notes.
resolves to:
<private management host>
then Pi-hole has done its job.
If the website still does not open, investigate:
NPM
Backend application
TLS
Routing
Firewall
Tailscale
rather than assuming DNS is the problem.
Basic DNS Test
From a client using Pi-hole:
This example was not included in the public notes.
Expected general result:
Address: <private management host>
The exact formatting depends on the operating system.
Security
Pi-hole is infrastructure and should remain private.
Important rules:
Do not expose the Pi-hole admin interface publicly.
Keep administration authenticated.
Keep SSH public-key-only.
Use Tailscale for private remote access.
Do not make Pi-hole mandatory for the household without deliberately changing the network design.
Avoid storing passwords or secrets in this Obsidian vault.
Failure Philosophy
Because Pi-hole is opt-in:
Pi-hole failure
should not take down normal Internet access for the entire household.
That isolation is intentional.
Selected homelab-aware devices may temporarily lose:
DNS filtering
Internal hostname resolution
Private .<private internal domain> names
while normal household clients continue using regular DNS.
Relationship With Raspberry Pi 3
Raspberry Pi 3 is the physical host for Pi-hole.
Current host details:
Hostname: <pi3-hostname>
Network: Private LAN
User: <admin-user>
SSH: ssh <pi3-alias>
The Pi 3 is intentionally dedicated primarily to lightweight DNS/networking responsibilities.
Relationship With Raspberry Pi 5
Raspberry Pi 5 hosts many of the applications that Pi-hole helps clients locate indirectly.
Examples:
Beszel
Grafana
Uptime Kuma
Open Lab Frame
Pi-hole may resolve the friendly hostname to VM102/NPM, which then proxies to the Pi 5.
Relationship With VM102
VM102 - Management is the central reverse-proxy target for most private service hostnames.
Pi-hole
↓
<private management host>
↓
VM102
↓
NPM
This is one of the central pieces of the current internal-service design.
Future Network Changes
Future homelab networking may add:
Managed switching
Optional VLAN segmentation for homelab services
The Archer BE550 remains the main router, Wi-Fi, DHCP, and NAT device in the current plan.
Pi-hole can continue providing DNS for selected networks/devices.
Its exact network placement can be redesigned later without changing the overall principle:
Homelab DNS should remain deliberate and controlled.
Related Notes
Homelab Overview
Raspberry Pi 3
Tailscale
Network Topology
Nginx Proxy Manager
VM102 - Management
Raspberry Pi 5
VM100 - Jellyfin
Beszel
Back to Networking
Networking / Note 03
Tailscale
In this note
Private remote-access network connecting selected personal devices, homelab systems, the VPS, and the home LAN without exposing internal services directly to the Internet.
Homelab Overview | Network Topology | Pi-hole | Raspberry Pi 3 | Raspberry Pi 5 | VM100 - Jellyfin | VPS Caddy
Status
State: In use
Role: Private remote access / secure overlay network
Design: Opt-in
Primary Home DNS / Subnet Router: Raspberry Pi 3
Exit Node: Raspberry Pi 5
Tailscale is intentionally used only by selected devices and homelab systems.
Normal household devices do not need Tailscale.
Purpose
Tailscale provides private connectivity between devices that may be:
On the home LAN
On cellular data
On another Wi-Fi network
Behind CGNAT
Running on the public VPS
Physically remote from the homelab
The main goal is:
Private remote connectivity
without publicly exposing
internal homelab services
Why Tailscale Is Important
The home Internet connection uses Starlink.
Starlink operates behind CGNAT, so normal inbound IPv4 port forwarding is not the preferred method for reaching private services.
Tailscale creates a private encrypted network between authorized devices.
Conceptually:
Remote Device
↓
Tailscale
↓
Private Tailscale Network
↓
Home Homelab
Current Tailscale Roles
Raspberry Pi 3
Raspberry Pi 3 is the primary Tailscale networking node for:
Pi-hole DNS
Subnet routing
Private LAN reachability
Current LAN details:
Hostname: <pi3-hostname>
Network: Private LAN
The Pi 3 is responsible for allowing selected Tailscale devices to reach private LAN services.
Raspberry Pi 5
Raspberry Pi 5 also participates in Tailscale.
Its primary Tailscale-related role includes:
Exit-node functionality
Private service access
The Pi 5 also hosts services including:
Open Lab Frame
Uptime Kuma
Beszel
Grafana
Prometheus
VM100 - Jellyfin
VM100 - Jellyfin has its own Tailscale connection.
Tailscale endpoint:
<private Jellyfin Tailscale endpoint>
This address is used for:
Private Jellyfin access
VPS → Jellyfin connectivity
Secure remote media-server communication
Subnet Routing
The Pi 3 acts as the Tailscale subnet-routing node for the home LAN.
This allows selected remote Tailscale devices to reach private addresses such as:
<private Proxmox host>
<private Jellyfin host>
<private Pi 5 host>
<private management host>
<private Pi 3 host>
without exposing those systems publicly.
General path:
Remote Tailscale Device
↓
Tailscale
↓
Raspberry Pi 3
↓
Home LAN
↓
<private home LAN> service
DNS Integration
Pi-hole runs on the Raspberry Pi 3 and provides DNS for selected Tailscale devices.
This allows private homelab names to work remotely.
Example:
This example was not included in the public notes.
can resolve to:
<private management host>
even while the client is away from home.
DNS + Subnet Routing Together
These two functions solve different parts of remote access.
Pi-hole
Answers:
What IP address belongs to this hostname?
Example:
↓
<private management host>
Tailscale Subnet Router
Answers:
How does the remote device reach <private management host>?
Together:
Remote Client
↓
Pi-hole DNS
↓
<private management host>
↓
Tailscale subnet route
↓
Home LAN
↓
VM102 / NPM
Remote Private Service Example
At home:
iPhone
↓
Home Wi-Fi
↓
Pi-hole
↓
↓
<private management host>
↓
NPM
↓
Away from home:
iPhone on 5G
↓
Tailscale
↓
Pi 3 DNS / subnet routing
↓
↓
<private management host>
↓
NPM
↓
The same friendly hostname can therefore work both locally and remotely.
Internal .<private internal domain> Services
Selected private services include:
<private Beszel hostname>
<private monitoring hostname>
<private proxy-admin hostname>
<private container-admin hostname>
<private development hostname>
Most of these resolve through Pi-hole to:
<private management host>
which is VM102 - Management running Nginx Proxy Manager .
Tailscale allows remote authorized devices to reach that private address.
Jellyfin Private Access
Tailscale provides a direct private route to VM100 - Jellyfin .
VM100 Tailscale address:
<private Jellyfin Tailscale endpoint>
Example:
Personal Remote Device
↓
Tailscale
↓
<private Jellyfin Tailscale endpoint>
↓
Jellyfin
This private path is useful for personal access.
Observed iPhone Tailscale Connection
An iPhone Jellyfin session was previously observed using:
<private remote Tailscale client>
This showed that the iPhone had connected to Jellyfin through the Tailscale network rather than through the local <private home LAN> LAN path.
Local vs Tailscale Jellyfin
Home Wi-Fi
iPhone
↓
<private home LAN> LAN
↓
VM100
<private Jellyfin host>
Away From Home
iPhone
↓
Tailscale
↓
VM100
<private Jellyfin Tailscale endpoint>
Both can reach the same Jellyfin server.
Network Route vs Direct Play
Tailscale determines the network path .
It does not determine whether Jellyfin Direct Plays or transcodes media.
These are separate concepts:
Direct/private network route
≠
Jellyfin Direct Play
For example:
iPhone
→ Tailscale
→ Jellyfin
may still result in:
Transcoding
if the client does not support the:
Container
Audio codec
Subtitle codec
Video format
Bitrate
VPS / Jellyfin Integration
The public VPS Caddy server also participates in the Tailscale network.
Public Jellyfin architecture:
Remote Friend
↓
Internet
↓
jellyfin.openlabframe.com
↓
VPS
↓
Caddy
↓
Tailscale
↓
<private Jellyfin Tailscale endpoint>:<SERVICE_PORT>
↓
VM100 / Jellyfin
This allows the VPS to reach Jellyfin without exposing Jellyfin directly from the home network.
Why NPM Is Not in the Public Jellyfin Path
The public Jellyfin route is intentionally:
VPS
↓
Caddy
↓
Tailscale
↓
VM100
not:
VPS
↓
NPM
↓
VM100
This avoids an unnecessary additional proxy hop.
Nginx Proxy Manager remains focused primarily on private/internal homelab web services.
Exit Node
Raspberry Pi 5 is used as the Tailscale exit-node component of the homelab.
An exit node allows a selected Tailscale device to route general Internet traffic through the Pi 5 / home connection when deliberately enabled.
Conceptually:
Remote Device
↓
Tailscale
↓
Pi 5 Exit Node
↓
Home Internet
↓
Internet
Using the exit node is optional.
It is different from subnet routing.
Exit Node vs Subnet Router
Pi 3 - Subnet Router
Used to reach:
<private home LAN>
home LAN systems.
Pi 5 - Exit Node
Can route general Internet traffic through the home Internet connection.
Conceptually:
Pi 3
→ Reach my private LAN
Pi 5
→ Route general traffic through home
Opt-In Design
Tailscale is intentionally opt-in.
Normal household devices do not need it.
Normal Household Device
↓
BE550
↓
Starlink
↓
Internet
Selected personal devices can additionally use:
Personal Device
↓
Tailscale
↓
Private homelab access
Administrative Privacy
Tailscale connectivity does not replace application authentication.
Being connected to the Tailnet does not automatically grant administrative access.
Services still require their normal authentication.
Examples:
Proxmox
Portainer
NPM
Pi-hole
Beszel
Uptime Kuma
SSH
The model is:
Tailscale
→ provides network access
Application authentication
→ determines permission
Security Principles
Important rules:
Do not expose private Tailscale authentication keys.
Do not store reusable Tailscale auth keys in Obsidian.
Keep administrative services authenticated.
Use Tailscale instead of public exposure where practical.
Only authorize trusted devices.
Remove old devices from the Tailnet when no longer needed.
Use subnet routing only where required.
Keep household participation optional.
Relationship With Pi-hole
Pi-hole provides private DNS resolution.
Tailscale provides the route to the resulting private address.
Example:
Pi-hole:
<private Beszel hostname>
↓
<private management host>
Tailscale:
Remote device
↓
Route to <private management host>
Together they provide remote friendly-name access.
Relationship With NPM
Nginx Proxy Manager handles private HTTPS application routing.
Example:
Remote Device
↓
Tailscale
↓
Pi-hole
↓
<private Beszel hostname>
↓
<private management host>
↓
NPM
↓
Beszel
Tailscale gets the client to the private network.
NPM routes the web request to the correct application.
Relationship With Starlink
Tailscale is particularly useful because Starlink uses CGNAT.
Instead of requiring inbound home port forwarding:
Internet
X
Direct inbound connection
Tailscale creates an outbound-established private overlay:
Home Device
↓
Tailscale
↕
Remote Device
This works even when the home connection is behind CGNAT.
Failure Behavior
If Tailscale becomes unavailable:
Normal household Internet
Should continue operating normally.
Local LAN services
Should continue working locally.
Remote private access
May stop working until Tailscale recovers.
Public Open Lab Frame
Should remain unaffected because it uses:
Cloudflare Tunnel
Public Jellyfin
May be affected because the VPS → VM100 route depends on Tailscale.
Current Architecture Summary
TAILSCALE
│
┌────────────────┼────────────────┐
│ │ │
↓ ↓ ↓
Raspberry Pi 3 Raspberry Pi 5 VM100
Subnet Router Exit Node Jellyfin
Pi-hole DNS Services <private Jellyfin Tailscale endpoint>
│
↓
<private home LAN>
Home LAN
Related Notes
Homelab Overview
Network Topology
Pi-hole
Raspberry Pi 3
Raspberry Pi 5
VM100 - Jellyfin
VM102 - Management
Nginx Proxy Manager
VPS Caddy
Jellyfin
Back to Networking
Networking / Note 04
Nginx Proxy Manager
In this note
Private/internal reverse-proxy layer for friendly HTTPS homelab service names.
Homelab Overview | Network Topology | Pi-hole | Tailscale | VM102 - Management | VPS Caddy
Status
State: In use
Host: VM102 - Management
Network: Private LAN
Role: Internal reverse proxy / HTTPS service routing
Operation: Always on
Nginx Proxy Manager is intentionally used primarily for private homelab web services .
It is not the main public ingress path for Jellyfin.
Host System
NPM runs on:
VM102 - Management
LAN IP:
<private management host>
VM102 also hosts:
Portainer
Beszel Agent
Other lightweight management tooling
Purpose
Nginx Proxy Manager provides:
Friendly internal URLs
HTTPS
Reverse proxying
Centralized internal service routing
TLS certificate handling
WebSocket proxying where required
Instead of remembering:
<private Pi 5 host>:<SERVICE_PORT>
<private Pi 5 host>:<SERVICE_PORT>
<private Pi 5 host>:<SERVICE_PORT>
<private development host>:<SERVICE_PORT>
<private management host>:<SERVICE_PORT>
services can use names such as:
<private Beszel hostname>
<private monitoring hostname>
<private development hostname>
<private container-admin hostname>
Core Architecture
The normal private service path is:
Client
↓
Pi-hole DNS
↓
service.<private internal domain>
↓
<private management host>
↓
VM102 / NPM
↓
Backend application
Pi-hole performs DNS resolution.
NPM performs HTTP/HTTPS routing.
These are separate jobs.
DNS Role
Pi-hole answers:
Where should this hostname go?
For most private .<private internal domain> services:
service.<private internal domain>
↓
<private management host>
NPM Role
NPM receives the request and determines:
Which backend application should receive it?
Example:
<private Beszel hostname>
↓
NPM
↓
<private Pi 5 host>:<SERVICE_PORT>
Current Proxy Hosts
Current important Proxy Hosts include:
<private development hostname>
<private monitoring hostname>
<private proxy-admin hostname>
<private container-admin hostname>
<private Beszel hostname>
<private development hostname>
Friendly URL:
<private development URL>
Backend:
<private service endpoint>
Target:
VM101 - OpenLabFrame Dev
Path:
Client
↓
Pi-hole
↓
<private management host>
↓
NPM
↓
<private development host>:<SERVICE_PORT>
↓
VM101
VM101 is intentionally powered off when website development is not taking place.
Therefore:
<private development hostname> unavailable
is normal while VM101 is off.
<private monitoring hostname>
Friendly URL:
<private monitoring URL>
Backend:
<private service endpoint>
Target:
Raspberry Pi 5
Path:
Client
↓
Pi-hole
↓
NPM
↓
<private Pi 5 host>:<SERVICE_PORT>
↓
Grafana
<private proxy-admin hostname>
Friendly URL:
<private proxy-admin URL>
Backend:
<internal proxy endpoint>
This allows NPM to proxy its own admin interface.
The direct NPM admin endpoint remains available at:
<private service endpoint>
This direct address is useful for troubleshooting if the friendly hostname is unavailable.
<private container-admin hostname>
Friendly URL:
<private container-admin URL>
NPM backend:
<internal container-admin endpoint>
Direct recovery/backend access:
<private service endpoint>
The direct HTTPS backend is especially useful if NPM itself is unavailable.
Beszel
Friendly URL:
<private Beszel URL>
Backend:
<private service endpoint>
Target:
Beszel Hub on Raspberry Pi 5
Architecture:
Client
↓
Pi-hole
↓
<private Beszel hostname>
↓
<private management host>
↓
NPM
↓
<private Pi 5 host>:<SERVICE_PORT>
↓
Beszel
Wildcard TLS Certificate
NPM uses the internal wildcard certificate:
<private internal wildcard>
<private internal domain>
This allows the same certificate to cover services such as:
<private proxy-admin hostname>
<private container-admin hostname>
<private monitoring hostname>
<private Beszel hostname>
<private development hostname>
Typical SSL Settings
Current normal configuration:
SSL Certificate:
<private internal wildcard>, <private internal domain>
Force SSL:
ON
HTTP/2 Support:
ON
HSTS:
OFF
HSTS Subdomains:
OFF
HSTS has intentionally been left off rather than enabling it without a specific need.
Typical Proxy Host Settings
Normal internal Proxy Host configuration:
Scheme:
http
Forward Hostname / IP:
Backend-specific
Forward Port:
Backend-specific
Cache Assets:
OFF
Block Common Exploits:
ON
Websockets Support:
ON where applicable
WebSockets
WebSocket support is enabled for applications that require or benefit from it.
Examples include applications such as:
Beszel
Other interactive web applications
This allows long-lived application connections to pass correctly through NPM.
Publicly Accessible
Some NPM Proxy Hosts use:
Access List:
Publicly Accessible
This wording can be misleading.
Within NPM, it means:
NPM does not add an additional Access List login
It does not automatically mean:
The service is exposed to the public Internet
Actual reachability still depends on:
DNS
Routing
Firewall configuration
Router exposure
Tailscale
Public tunnels
Port forwarding
The private .<private internal domain> architecture remains internal.
Why Not Add NPM Authentication Everywhere
Adding a separate NPM Access List in front of some applications may interfere with:
Mobile applications
API clients
WebSockets
Native login flows
Therefore, native application authentication is preferred where appropriate.
Pi-hole Integration
Pi-hole provides the internal DNS records used by NPM.
Example:
↓
<private management host>
NPM then forwards to:
<private Pi 5 host>:<SERVICE_PORT>
General architecture:
Pi-hole
↓
VM102
↓
NPM
↓
Backend
Tailscale Integration
Tailscale allows authorized remote personal devices to reach private NPM services while away from home.
Example:
iPhone on 5G
↓
Tailscale
↓
Pi 3 DNS / subnet route
↓
↓
<private management host>
↓
NPM
↓
The NPM hostname does not need to become publicly exposed for this to work.
Home LAN Access
At home:
Laptop / iPhone
↓
Wi-Fi or Ethernet
↓
Pi-hole DNS
↓
VM102 / NPM
↓
Backend
Wi-Fi clients are still LAN clients unless intentionally isolated.
NPM vs VPS Caddy
NPM and VPS Caddy have different roles.
NPM
Primarily used for:
Private/internal homelab services
Examples:
Beszel
Grafana
Portainer
Development site
NPM itself
VPS Caddy
Used for:
Public Jellyfin ingress
Path:
Internet
↓
VPS
↓
Caddy
↓
Tailscale
↓
VM100
Jellyfin Does Not Normally Use NPM
Friends accessing Jellyfin use:
jellyfin.openlabframe.com
↓
VPS Caddy
↓
Tailscale
↓
VM100
They do not normally use:
NPM
in that route.
This reduces unnecessary proxy hops.
Cloudflare Is Also Separate
Open Lab Frame uses:
Cloudflare
↓
Cloudflare Tunnel
↓
Pi 5
rather than NPM.
Current ingress responsibilities are therefore:
Open Lab Frame
→ Cloudflare Tunnel
Public Jellyfin
→ VPS Caddy
Private Web Services
→ NPM
Private Remote Access
→ Tailscale
This separation is intentional.
Direct Backend Access
Friendly NPM hostnames are convenient, but direct backend access remains valuable for troubleshooting.
Examples:
NPM:
<private service endpoint>
Portainer:
<private service endpoint>
Beszel:
<private service endpoint>
<private service endpoint>
Grafana:
<private service endpoint>
These should normally be used only from authorized internal devices.
Monitoring
Uptime Kuma monitors important VM102 services independently.
Current examples include:
VM102 - Management
NPM - VM102
Portainer - VM102
VM102 Monitor
Purpose:
Is VM102 itself reachable?
Target:
<private management host>
Monitor type:
Ping
NPM Monitor
Purpose:
Is NPM responding?
Target:
<private service endpoint>
Healthy response:
HTTP 200
Portainer Monitor
Purpose:
Is Portainer responding?
Target:
<private service endpoint>
Healthy response:
HTTP 200
TLS verification can be ignored for the direct Portainer backend monitor because the local Portainer certificate is not the NPM wildcard certificate.
Why Separate Host and Service Monitoring
Example:
VM102 UP
NPM DOWN
Portainer UP
means:
VM is healthy
NPM itself has a problem
Whereas:
VM102 DOWN
NPM DOWN
Portainer DOWN
suggests a VM-level or host-level failure.
Beszel Monitoring
Beszel also monitors VM102.
Typical observed values:
CPU: < 1%
Memory: ~15–16%
Disk: ~11%
This confirms that the management VM is lightweight.
Beszel and Uptime Kuma have different roles:
Uptime Kuma
→ Is NPM up?
Beszel
→ How much resource is VM102 using?
Recovery Test
A controlled reboot of Proxmox Host was used to validate recovery.
During the reboot:
VM102
NPM
Portainer
became temporarily unavailable.
Uptime Kuma detected failures such as:
NPM - VM102
DOWN
Portainer - VM102
DOWN
After the Proxmox host returned:
VM102 started automatically
Docker started automatically
NPM returned
Portainer returned
Beszel Agent returned
Uptime Kuma changed the monitors back to Up
No manual service startup was required.
Recovery Sequence
HP ProDesk boots
↓
Proxmox
↓
VM102
↓
Linux
↓
Docker
↓
NPM
Portainer
Beszel Agent
↓
Internal services available
Failure Considerations
Because many internal hostnames point to:
<private management host>
an NPM or VM102 outage can affect access to several friendly internal URLs simultaneously.
However, the backend applications may still be healthy.
Example:
NPM DOWN
↓
while:
<private Pi 5 host>:<SERVICE_PORT>
may still be working.
This is why direct backend addresses are useful for troubleshooting.
Security
NPM is an administrative system and should remain private.
Important rules:
Do not expose the NPM admin interface publicly.
Keep VM102 SSH key-only.
Keep administrative access authenticated.
Do not store NPM passwords in Obsidian.
Do not store wildcard private keys in Obsidian.
Do not publicly expose private .<private internal domain> services unnecessarily.
Use Tailscale for private remote access.
Preserve direct backend access for recovery when appropriate.
VM102 Relationship
VM102 - Management is the underlying host.
VM102
├── Nginx Proxy Manager
├── Portainer
└── Beszel Agent
NPM therefore depends on:
HP ProDesk
↓
Proxmox
↓
VM102
↓
Docker
↓
NPM
Raspberry Pi 5 Relationship
Several NPM backends run on Raspberry Pi 5 .
Examples:
Grafana
→ <private Pi 5 host>:<SERVICE_PORT>
→ <private Pi 5 host>:<SERVICE_PORT>
Beszel
→ <private Pi 5 host>:<SERVICE_PORT>
The Pi 5 hosts the applications.
NPM provides the friendly HTTPS frontend.
VM101 Relationship
VM101 - OpenLabFrame Dev uses:
<private development hostname>
Backend:
<private development host>:<SERVICE_PORT>
VM101 can remain off while NPM remains running.
Architecture Summary
Pi-hole
↓
<private management host>
↓
VM102 / NPM
│
┌─────────────────┼─────────────────┐
↓ ↓ ↓
Raspberry Pi 5 VM101 VM102
services dev site management
Current Friendly URLs
<private development URL>
<private monitoring URL>
<private proxy-admin URL>
<private container-admin URL>
<private Beszel URL>
Related Notes
Homelab Overview
Network Topology
Pi-hole
Tailscale
VM102 - Management
Raspberry Pi 5
VM101 - OpenLabFrame Dev
Beszel
VPS Caddy
Uptime Kuma
Back to Networking
Networking / Note 05
VPS Caddy
In this note
Public reverse-proxy ingress for Jellyfin, bridging the public Internet to VM100 through Tailscale.
Homelab Overview | Network Topology | Tailscale | VM100 - Jellyfin | Jellyfin | Nginx Proxy Manager
Status
State: In use
Role: Public Jellyfin reverse proxy
Public Address: Omitted from public copy
SSH User: <admin-user>
SSH Administration: Public-key authentication
Reverse Proxy: Caddy
Backend Transport: Tailscale
Primary Public Service: Jellyfin
Purpose
The VPS provides a publicly reachable endpoint for services that genuinely need public Internet access.
Its main current role is:
Public Jellyfin ingress
The VPS accepts HTTPS traffic from remote Jellyfin clients and sends that traffic securely back to VM100 - Jellyfin through Tailscale .
Why the VPS Exists
The home Internet connection uses:
Starlink
Starlink operates behind CGNAT.
This means normal inbound IPv4 port forwarding from the public Internet to the home network is not the preferred architecture.
Instead of:
Internet
↓
Home Public IPv4
↓
Router Port Forward
↓
Jellyfin
the homelab uses:
Internet
↓
Public VPS
↓
Tailscale
↓
VM100 / Jellyfin
This avoids depending on inbound connectivity through Starlink CGNAT.
Public Jellyfin URL
Public Jellyfin hostname:
https://jellyfin.openlabframe.com
Remote users connect to this hostname rather than directly to a home IP address.
Full Jellyfin Path
Remote User
↓
Internet
↓
jellyfin.openlabframe.com
↓
Public VPS
<public VPS address omitted>
↓
Caddy
↓
Tailscale
↓
VM100
<private Jellyfin Tailscale endpoint>:<SERVICE_PORT>
↓
Jellyfin
VM100 Backend
VM100 - Jellyfin has a Tailscale address:
<private Jellyfin Tailscale endpoint>
Jellyfin listens on:
8096
Therefore, the VPS backend is:
<private Jellyfin Tailscale endpoint>:<SERVICE_PORT>
Caddy
Caddy runs on the VPS and acts as the public HTTPS reverse proxy.
Its role includes:
Accepting public HTTPS requests
TLS certificate handling
Forwarding requests to Jellyfin
Maintaining the public jellyfin.openlabframe.com endpoint
Using Tailscale to reach VM100 privately
Conceptual Caddy Configuration
The essential Jellyfin configuration is conceptually:
jellyfin.openlabframe.com {
reverse_proxy <private Jellyfin Tailscale endpoint>:<SERVICE_PORT>
}
This means:
Request for:
jellyfin.openlabframe.com
↓
Caddy forwards to:
<private Jellyfin Tailscale endpoint>:<SERVICE_PORT>
Why Tailscale Is Used Between VPS and VM100
The VPS is public.
VM100 is private.
Tailscale bridges those two systems without requiring Jellyfin to be directly exposed from the home router.
Architecture:
VPS
↓
Encrypted Tailscale connection
↓
VM100
This allows the public endpoint to exist while keeping the Jellyfin backend on the private homelab network.
Public vs Private Components
Public
jellyfin.openlabframe.com
VPS
Caddy HTTPS endpoint
Private
VM100
<private Jellyfin Tailscale endpoint>
Jellyfin backend
Home LAN
The VPS acts as the boundary between the public and private sides.
Why Nginx Proxy Manager Is Not Used Here
Nginx Proxy Manager is intentionally not part of the normal public Jellyfin path.
Current public path:
Remote User
↓
VPS Caddy
↓
Tailscale
↓
VM100 / Jellyfin
Not:
Remote User
↓
VPS
↓
NPM
↓
Jellyfin
Adding NPM would introduce another unnecessary proxy hop.
Caddy can already reach Jellyfin directly through Tailscale.
NPM Role Instead
NPM remains focused primarily on private/internal services such as:
<private Beszel hostname>
<private monitoring hostname>
<private proxy-admin hostname>
<private container-admin hostname>
<private development hostname>
This keeps the roles clean:
Caddy
→ Public Jellyfin
NPM
→ Private homelab services
Local Jellyfin Does Not Need VPS
When a personal device is at home, Jellyfin traffic can remain completely local.
iPhone
↓
Home Wi-Fi
↓
Pi-hole DNS
↓
<private Jellyfin host>
↓
VM100 / Jellyfin
The VPS is unnecessary for local playback.
Private Remote Jellyfin Does Not Need VPS
A personal device connected through Tailscale can also reach VM100 privately.
Personal Remote Device
↓
Tailscale
↓
<private Jellyfin Tailscale endpoint>
↓
Jellyfin
Therefore there are three different Jellyfin network paths.
Jellyfin Access Paths
Local Personal Access
Home Device
↓
LAN
↓
<private Jellyfin host>
↓
Jellyfin
Private Personal Remote Access
Remote Personal Device
↓
Tailscale
↓
<private Jellyfin Tailscale endpoint>
↓
Jellyfin
Public Remote / Friend Access
Remote Friend
↓
Internet
↓
VPS Caddy
↓
Tailscale
↓
VM100
↓
Jellyfin
These are deliberately separate.
Public Access for Friends / Family
Remote users do not need:
Tailscale
Pi-hole
NPM
Direct access to the home LAN
Knowledge of private VM100 addresses
They simply use:
https://jellyfin.openlabframe.com
The VPS handles the connection back to the home Jellyfin server.
SSH Access
Windows SSH alias:
ssh <vps-alias>
Current Windows SSH configuration:
Host <vps-alias>
HostName <public VPS address omitted>
User <admin-user>
IdentityFile <SSH_KEY_FILE>
IdentitiesOnly yes
This allows administration without repeatedly typing:
<admin-user>@<public VPS address omitted>
SSH Key
Windows private key:
<SSH_KEY_FILE>
Public-key authentication should remain the normal SSH method.
Do not store the private key contents in Obsidian.
VPS Administration
Typical administration flow:
Windows PC
↓
ssh <vps-alias>
↓
VPS
↓
Caddy / Tailscale / system services
Caddy Configuration
Caddy configuration should be treated as important infrastructure.
Changes should be:
Edited carefully
Validated
Reloaded only after validation
Tested from outside the home network
The exact active Caddyfile should remain documented separately if it becomes substantially more complex.
TLS
Caddy handles HTTPS for:
jellyfin.openlabframe.com
This allows remote Jellyfin clients to connect through a normal trusted HTTPS endpoint.
General TLS path:
Remote Client
↓
HTTPS
↓
Caddy
↓
Private backend
DNS
Public DNS for:
jellyfin.openlabframe.com
ultimately directs public clients toward the VPS.
This is different from the private Pi-hole DNS overrides used inside the homelab.
Split Local Behavior
Selected local devices can resolve Jellyfin differently through Pi-hole .
For the user's own devices at home:
jellyfin.openlabframe.com
↓
Pi-hole
↓
<private Jellyfin host>
This allows local clients to avoid:
Home
↓
Internet
↓
VPS
↓
Tailscale
↓
Back Home
and instead use:
Home Device
↓
VM100 directly
Why Local Routing Matters
Sending home Jellyfin traffic through the VPS would:
Add unnecessary latency
Use Internet upload/download bandwidth
Add additional proxying
Depend on the VPS unnecessarily
Local DNS allows the user's own devices to use the shortest available route.
Direct Route vs Direct Play
Using the VPS, Tailscale, or LAN determines the network route .
It does not determine whether Jellyfin Direct Plays the media.
For example:
Remote User
→ VPS
→ Jellyfin
could still:
Direct Play
or:
Transcode
depending on:
Media codec
Container
Audio format
Subtitle format
Client support
Bitrate limits
Relationship With Starlink
Starlink remains the single home Internet connection.
Current public Jellyfin architecture does not require changing that.
Home Jellyfin
↓
Outbound Tailscale connectivity
↓
VPS
↓
Public Internet
The Tailscale overlay avoids requiring inbound public IPv4 connectivity through Starlink.
Relationship With Tailscale
Tailscale is critical to the VPS architecture.
The VPS and VM100 must both maintain working Tailscale connectivity.
If the VPS cannot reach:
<private Jellyfin Tailscale endpoint>
then the public Jellyfin backend becomes unavailable even if Jellyfin itself is still healthy.
Failure Scenarios
VPS Down
Public Jellyfin
→ DOWN
while:
Local Jellyfin
→ May still work
Tailscale private Jellyfin
→ May still work
Caddy Down
Public HTTPS endpoint
→ DOWN
while VM100 itself may remain healthy.
VPS Tailscale Down
Caddy
→ Cannot reach VM100
→ Public Jellyfin fails
VM100 Down
Local Jellyfin
→ DOWN
Private Tailscale Jellyfin
→ DOWN
Public VPS Jellyfin
→ DOWN
because all paths ultimately depend on VM100.
Home Internet Down
The VPS may remain online, but its backend becomes unreachable.
VPS
↓
Tailscale
X
Home Jellyfin
Public Jellyfin therefore fails until home connectivity returns.
Monitoring Philosophy
The architecture should ideally distinguish:
Is the VPS alive?
Is Caddy alive?
Can Caddy reach Jellyfin?
Is VM100 alive?
Is Jellyfin itself responding?
These are separate failure points.
Uptime Kuma can be expanded to monitor these individually if useful.
Security
The VPS is publicly reachable and should be treated as Internet-facing infrastructure.
Important rules:
Keep SSH public-key-only.
Keep the OS updated.
Expose only required services.
Avoid unnecessary open ports.
Keep Caddy updated.
Protect SSH credentials.
Do not store private SSH keys in Obsidian.
Do not store reusable Tailscale authentication keys in Obsidian.
Do not expose VM100 directly to the public Internet unnecessarily.
Keep the Caddy → VM100 path on Tailscale.
What the VPS Should Not Become
The VPS should not automatically become a catch-all entry point for every homelab service.
Private services such as:
Beszel
Grafana
Portainer
NPM
Proxmox
should generally remain private unless there is a deliberate reason to expose one publicly.
The current principle is:
Public when necessary
Private by default
Architecture Separation
Current ingress design:
Open Lab Frame
Internet
↓
Cloudflare
↓
Cloudflare Tunnel
↓
Pi 5
Public Jellyfin
Internet
↓
VPS Caddy
↓
Tailscale
↓
VM100
Private Services
Pi-hole
↓
VM102 / NPM
↓
Backend
Remote Personal Access
Tailscale
↓
Private homelab
These paths are intentionally independent.
Current Public Jellyfin Architecture
INTERNET
│
↓
jellyfin.openlabframe.com
│
↓
Public VPS
<public VPS address omitted>
│
Caddy
│
↓
Tailscale
│
↓
<private Jellyfin Tailscale endpoint>
│
↓
VM100
│
↓
Jellyfin
Future Direction
The current VPS/Caddy architecture can remain even as the home homelab grows.
The future network is still planned around:
Starlink
↓
Archer BE550
↓
Omada Managed Switch
↓
Homelab
The VPS remains useful because the Starlink connection still operates behind CGNAT.
Related Notes
Homelab Overview
Network Topology
Tailscale
Pi-hole
Nginx Proxy Manager
VM100 - Jellyfin
Jellyfin
Raspberry Pi 3
Raspberry Pi 5
Uptime Kuma
Back to Networking