homelab / cgnat-access-guide.md
3 methods · 10 sections

Networking · Self-hosting reference

Homelab External Access Guide for CGNAT

This guide is for accessing a homelab from outside the home network when your ISP is using CGNAT. In that situation, inbound port forwarding from the internet is usually not available, so the best options are ZeroTier, WireGuard via a VPS, or Cloudflare Tunnel.

Assumptions used in examples

  • Your homelab is on a private LAN such as 192.168.1.0/24
  • Your homelab host has a private address such as 192.168.1.50
  • You have a VPS with a public IPv4 address
  • You want to reach services such as SSH, Home Assistant, Plex, or a reverse proxy
MethodEffortNeeds a VPSNeeds a domainBest for
ZeroTier Low No No Fastest path to private access, no infrastructure
WireGuard via VPS Medium Yes No Full self-hosted control and flexibility
Cloudflare Tunnel Medium No Yes Public access to specific web services
01

ZeroTier setup — recommended for simplicity

ZeroTier is the easiest way to get remote access when you are behind CGNAT. It creates a virtual private network over the internet without needing port forwarding.

Why ZeroTier fits CGNAT

  • No public IP or inbound port forwarding needed
  • Works from phones, laptops, and other devices
  • Easy to set up and maintain
  • Good for private access to your homelab and LAN services

Step 1 — Create a ZeroTier account

  1. Go to zerotier.com
  2. Create an account and sign in
  3. Create a new network
  4. Keep the network ID handy

Step 2 — Install ZeroTier on the homelab host

On a Linux server or VM, run:

bashhomelab host
curl -s https://install.zerotier.com | sudo bash
sudo zerotier-cli join <NETWORK_ID>

If you are using Docker or a different OS, use the ZeroTier package for that platform.

Step 3 — Approve the node in the ZeroTier UI

  1. Open the ZeroTier admin panel
  2. Select the network you created
  3. Find the new member entry for your homelab host
  4. Click Authorize

Step 4 — Assign a managed IP and test access

Once authorized, ZeroTier should assign the node a private virtual IP (for example 10.147.17.12). You can then connect to the host by that address.

bashexample
ssh user@10.147.17.12

Step 5 — Install ZeroTier on your phone and laptop

  1. Install the ZeroTier app on your phone
  2. Join the same network
  3. Approve the device in the ZeroTier UI
  4. Test access to your homelab services

Step 6 — Route traffic for your home-lab LAN through ZeroTier

If you want to reach devices on your home LAN, such as 192.168.1.50 or an entire subnet like 192.168.1.0/24, you need to make the ZeroTier-connected device act as a gateway.

Easy to miss

Joining ZeroTier alone does not automatically forward LAN traffic — the gateway steps below are required.

A. Enable routing on the gateway device

Use the machine that is on your home LAN and also has ZeroTier installed as the gateway. On that Linux box, enable IP forwarding:

bashgateway
sudo sysctl -w net.ipv4.ip_forward=1

To make it persistent, add this line to /etc/sysctl.conf:

conf/etc/sysctl.conf
net.ipv4.ip_forward=1

Then allow forwarding between the ZeroTier interface and your LAN interface:

bashgateway
sudo iptables -A FORWARD -i zt0 -o eth0 -j ACCEPT
sudo iptables -A FORWARD -i eth0 -o zt0 -j ACCEPT
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

If your interface names differ, check them with:

bashgateway
ip -br addr

Replace zt0 and eth0 with the actual ZeroTier and LAN interface names.

B. Add a managed route in ZeroTier

In the ZeroTier admin panel:

  1. Open your network
  2. Go to Settings or Routes
  3. Add a managed route for your home subnet, for example 192.168.1.0/24
  4. Make sure the route is assigned to the gateway node that is running ZeroTier on your LAN

This tells other ZeroTier clients that traffic for your home subnet should be sent to that gateway node.

C. Optional — route a single host instead of the whole subnet

If you only need one device, such as 192.168.1.50, you can route just that host:

bashclient
sudo ip route add 192.168.1.50/32 via <ZERO_TIER_GW_IP>

For most setups, routing the full subnet is easier.

D. Test it

From a device connected to ZeroTier, try:

bashclient
ping 192.168.1.50

If that works, you can reach services like:

bashclient
ssh user@192.168.1.50

Security tips

  • Use strong device approval and network ACLs
  • Disable unused services on the host
  • Prefer SSH keys over passwords
  • Keep ZeroTier updated
02

Cloudflare Tunnel — good for public web services

Cloudflare Tunnel is a strong option if you want to expose services like Home Assistant, Jellyfin, or a reverse proxy without opening inbound ports on your router.

Why this option is different

Unlike ZeroTier or WireGuard, Cloudflare Tunnel does not require you to expose your homelab directly to the internet. Instead, a lightweight Cloudflare connector runs inside your home network and creates an outbound-only tunnel to Cloudflare.

Important requirements

You will need:

  • A domain name
  • DNS managed in Cloudflare
  • A Cloudflare account
  • A tunnel connector installed on your homelab or a gateway machine

Important note about DNS

Cloudflare Tunnel requires a public DNS name that points to your Cloudflare-managed domain. For example: home.example.com, ha.example.com, media.example.com.

You must control the DNS records for the domain and either use Cloudflare DNS as the authoritative DNS provider, or delegate the relevant subdomains to Cloudflare.

Without this

Without a valid DNS name, the tunnel cannot be used cleanly for public access.

Basic flow

  1. Create a Cloudflare account
  2. Add your domain to Cloudflare
  3. Configure DNS records for the subdomains you want to expose
  4. Install the Cloudflare Tunnel connector on your homelab host or another machine on your LAN
  5. Create a tunnel and define ingress rules
  6. Route traffic from the public hostname to your internal service

Example setup

Suppose you want ha.example.com to reach your Home Assistant instance at http://192.168.1.50:8123. You would create a Cloudflare Tunnel public hostname for that domain and point it to the internal address.

Authentication and access control

Cloudflare Tunnel gives you several strong security options:

  • Cloudflare Access — enforce login before someone can reach the service
  • Zero Trust policies — restrict access by email, group, or device posture
  • Local auth on the application — use your own login page or reverse proxy auth
  • WAF and bot protection — protect your services at the edge

For most homelab setups, the safest approach is:

  • Put the service behind a reverse proxy such as Nginx Proxy Manager or Caddy
  • Require authentication at Cloudflare Access or at the reverse proxy
  • Avoid exposing the service directly to the internet without any auth

Security recommendations

  • Do not expose raw services like Home Assistant directly without auth
  • Prefer a reverse proxy with TLS termination
  • Use Cloudflare Access or another identity layer for sensitive services
  • Keep the tunnel connector updated
  • Restrict access to trusted users and devices

When Cloudflare Tunnel is a good fit

Use Cloudflare Tunnel when you want:

  • Public access to a few web services
  • No inbound port forwarding on your router
  • Strong built-in security and access control
  • A cleaner and more modern setup than raw port forwarding

When it is not the best fit

Cloudflare Tunnel is less ideal when you need:

  • Full LAN-wide access to many devices
  • Low-level VPN-style connectivity for arbitrary protocols
  • A setup that does not depend on a domain and DNS
03

WireGuard via VPS — more self-hosted

WireGuard is a good alternative when you want more control, or when you prefer not to rely on a third-party overlay network.

Why this works behind CGNAT

Your homelab and your phone both create outbound connections to the VPS. Since the VPS has a public IP, the tunnel is established even though your home network is behind CGNAT.

Recommended layout

  • VPS = hub
  • Homelab = spoke 1
  • Mobile phone = spoke 2

Example IP layout

  • VPS private VPN address: 10.20.0.1
  • Homelab VPN address: 10.20.0.2
  • Phone VPN address: 10.20.0.3
  • Home LAN: 192.168.1.0/24
VPS
Public IPv4 hub, always reachable
10.20.0.1
Homelab
Spoke 1 — outbound connection, behind CGNAT
10.20.0.2 → LAN 192.168.1.0/24
Phone
Spoke 2 — outbound connection, roaming
10.20.0.3
04

VPS preparation

Requirements

  • A VPS with a public IPv4 address
  • Ubuntu or Debian installed
  • SSH access
  • Ability to open UDP port 51820

Install WireGuard on the VPS

bashVPS
sudo apt update
sudo apt install -y wireguard qrencode

Create server keys

bashVPS
sudo mkdir -p /etc/wireguard
cd /etc/wireguard
sudo umask 077
sudo wg genkey | sudo tee server_private.key | sudo wg pubkey | sudo tee server_public.key

Create the server config

Create /etc/wireguard/wg0.conf:

conf/etc/wireguard/wg0.conf
[Interface]
Address = 10.20.0.1/24
ListenPort = 51820
PrivateKey = <SERVER_PRIVATE_KEY>

PostUp = iptables -A FORWARD -i wg0 -j ACCEPT
PostUp = iptables -A FORWARD -o wg0 -j ACCEPT
PostUp = iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

PostDown = iptables -D FORWARD -i wg0 -j ACCEPT
PostDown = iptables -D FORWARD -o wg0 -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

Replace <SERVER_PRIVATE_KEY> with the contents of the private key file.

Enable IP forwarding

Edit /etc/sysctl.conf and add or uncomment:

conf/etc/sysctl.conf
net.ipv4.ip_forward=1

Then apply it:

bashVPS
sudo sysctl -p

Start the VPN service

bashVPS
sudo wg-quick up wg0
sudo systemctl enable wg-quick@wg0

Open the firewall

If you are using UFW:

bashVPS
sudo ufw allow 51820/udp
sudo ufw allow OpenSSH
sudo ufw enable

If your cloud provider has firewall rules, allow UDP 51820 from the internet.

05

Configure the homelab host as a WireGuard client

On the homelab server, generate a client key pair:

bashhomelab
sudo mkdir -p /etc/wireguard
cd /etc/wireguard
sudo umask 077
sudo wg genkey | sudo tee homelab_private.key | sudo wg pubkey | sudo tee homelab_public.key

Create the homelab client config

Create /etc/wireguard/wg0.conf on the homelab host:

conf/etc/wireguard/wg0.conf
[Interface]
Address = 10.20.0.2/24
PrivateKey = <HOMELAB_PRIVATE_KEY>
DNS = 10.20.0.1

[Peer]
PublicKey = <VPS_PUBLIC_KEY>
Endpoint = <VPS_PUBLIC_IP>:51820
AllowedIPs = 10.20.0.0/24, 192.168.1.0/24
PersistentKeepalive = 25

Replace the placeholders with your actual values:

  • <HOMELAB_PRIVATE_KEY> from homelab_private.key
  • <VPS_PUBLIC_KEY> from the VPS server_public.key file
  • <VPS_PUBLIC_IP> with the VPS public IP address

Add the client to the VPS config

On the VPS, edit /etc/wireguard/wg0.conf and add:

conf/etc/wireguard/wg0.conf
[Peer]
PublicKey = <HOMELAB_PUBLIC_KEY>
AllowedIPs = 10.20.0.2/32

Then reload the VPS WireGuard config:

bashVPS
sudo wg syncconf wg0 <(wg-quick strip wg0)

Start the homelab client

bashhomelab
sudo wg-quick up wg0
sudo systemctl enable wg-quick@wg0

Test the tunnel

From the homelab host:

bashhomelab
wg
ping 10.20.0.1

From the VPS, check that the peer is connected:

bashVPS
sudo wg
06

Configure the mobile phone as a WireGuard client

Use the official WireGuard app on Android or iPhone.

Mobile client config example

confphone
[Interface]
Address = 10.20.0.3/24
PrivateKey = <PHONE_PRIVATE_KEY>
DNS = 10.20.0.1

[Peer]
PublicKey = <VPS_PUBLIC_KEY>
Endpoint = <VPS_PUBLIC_IP>:51820
AllowedIPs = 10.20.0.0/24, 192.168.1.0/24
PersistentKeepalive = 25

Add the phone peer to the VPS config

On the VPS, add another peer:

conf/etc/wireguard/wg0.conf
[Peer]
PublicKey = <PHONE_PUBLIC_KEY>
AllowedIPs = 10.20.0.3/32

Then reload the VPN:

bashVPS
sudo wg syncconf wg0 <(wg-quick strip wg0)

Notes for mobile access

  • If you want the phone to use the VPN for all traffic, use AllowedIPs = 0.0.0.0/0 instead of only the homelab network
  • If you only want to reach your homelab, keep the LAN subnet in AllowedIPs
07

Accessing services after setup

Once the tunnel is up, you can reach your homelab services through the VPN.

  • SSH: ssh user@10.20.0.2
  • Home Assistant: http://10.20.0.2:8123
  • Internal web app: http://192.168.1.50

If you are connecting from the phone, the phone will use the VPN address for the host and the server will see the connection as coming from the VPS network.

08

Common troubleshooting

? I cannot connect to the VPS

  • Make sure UDP 51820 is open on the VPS firewall and cloud provider firewall
  • Confirm the VPS is listening with sudo wg
  • Check that the endpoint is correct

? The homelab host cannot reach the VPS

  • Verify the peer config is correct
  • Confirm the WireGuard service is running on both sides
  • Check that the private and public keys are matched

? The phone can connect but cannot reach LAN services

  • Ensure the homelab host is routing traffic correctly
  • Confirm the VPS has IP forwarding enabled
  • Make sure the firewall allows forwarding traffic
  • Check that AllowedIPs includes your LAN subnet such as 192.168.1.0/24

? ZeroTier shows connected but cannot reach services

  • Confirm the device is authorized in the ZeroTier network
  • Check whether the host or router is actually routing traffic to the LAN
  • Make sure the service is listening on the correct interface and port
09

Recommendation

If you want the least effort, use ZeroTier. If you want the most control and a fully self-hosted setup, use WireGuard with a VPS.

For most people, the recommended order is:

  1. Start with ZeroTier for quick access
  2. Move to WireGuard if you want stronger self-hosting and flexibility
10

Useful security notes

Keep in mind across all methods

  • Prefer SSH keys over passwords
  • Use MFA wherever possible
  • Restrict access to only the devices you need
  • Keep your OS, Docker containers, and reverse proxy updated
  • Do not expose admin panels directly to the internet without a VPN or auth layer