Provides external access to homelab services without opening ports.
Overview
Cloudflare Tunnel creates a secure outbound connection from the homelab to Cloudflare's edge. External traffic comes through Cloudflare, then through the tunnel to internal services.
Container: CT 126 IP: 192.168.144.32 Purpose: External access routing
Source Code
Docker Compose & Install Script: github.com/opajanvv/homelab-docker/tree/main/tunnel
Local copy: ~/dev/homelab-docker/tunnel/
Deployment
# Clone LXC template
pct clone 902 126 --hostname cloudflared --full
pct set 126 --cores 1 --memory 512
pct set 126 -net0 name=eth0,bridge=vmbr0,firewall=1,gw=192.168.144.1,ip=192.168.144.32/23
pct set 126 -features nesting=1,keyctl=1
pct set 126 -onboot 1
# No data mount needed for tunnel
# Mount homelab-docker configs (shared from host)
pct set 126 -mp1 /home/jan/homelab-docker,mp=/opt/homelab-docker
# Deploy
pct start 126
pct exec 126 -- bash -c 'systemctl enable --now docker'
# Configs available via bind mount (no git clone needed)
pct exec 126 -- bash -c 'cd /opt/homelab-docker/tunnel && chmod +x install.sh && ./install.sh'
Configuration
Environment Variable:
TUNNEL_TOKEN- Cloudflare tunnel token (from Cloudflare dashboard)
Data Location:
- No persistent data needed
- Config stored in Cloudflare dashboard
Routing Configuration
Routes are configured in Cloudflare Zero Trust dashboard:
- Go to: Zero Trust → Networks → Tunnels
- Select your tunnel
- Add "Public Hostname" for each service
| Current Routes: | External URL | Internal Destination |
|---|---|---|
| https://tasks.janvv.nl | 192.168.144.60:1337 | |
| https://n8n.janvv.nl | 192.168.144.61:5678 | |
| https://opa.janvv.nl | 192.168.144.72:80 | |
| https://kijkdoos.janvv.nl | 192.168.144.100:8096 | |
| https://jokegoudriaan.nl | 192.168.144.70:80 | |
| https://kledingruil.jokegoudriaan.nl | 192.168.144.71:80 | |
| https://pgh.janvv.nl | 192.168.144.73:80 | |
| https://assistant.janvv.nl | 192.168.144.120:8123 | |
| https://photos.janvv.nl | 192.168.144.110:2283 | |
| https://pihole.janvv.nl | 192.168.144.20:80 | |
| https://proxmox.janvv.nl | 192.168.144.10:8006 | |
| https://status.janvv.nl | 192.168.144.25:80 | |
| https://sync.janvv.nl | 192.168.144.63:8384 | |
| https://ollama.janvv.nl | 192.168.144.62:11435 | |
| https://ai.janvv.nl | 192.168.144.62:8080 | |
| https://terminal.janvv.nl | 192.168.144.10:4711 |
Backup
No persistent data to backup. Tunnel routes are stored in Cloudflare.
Document: Keep a list of configured routes (as above) for reference.
Maintenance
Update:
pct exec 126 -- bash -c 'cd /opt/homelab-docker/tunnel && docker compose pull && docker compose up -d'
View logs:
pct exec 126 -- bash -c 'cd /opt/homelab-docker/tunnel && docker compose logs -f'
Check tunnel status: Cloudflare Zero Trust dashboard → Tunnels → Your tunnel
Adding a New Route
- Go to Cloudflare Zero Trust → Networks → Tunnels
- Select your tunnel
- Click "Public Hostname"
- Add:
- Subdomain/domain
- Service type: HTTP
- URL:
http://<internal-ip>:<port>
- Save
Troubleshooting
Tunnel offline: Check container is running, check token is valid Route not working: Verify internal service is accessible from tunnel container