Hosting external services By Chad Tomlinson on 04-Oct-2025 in homelab

Once again the biannual change in internet service supplier forced me to adapt the techniques used to make self hosted applications available on the internet. Previously I’ve used Dynamic DNS (DDNS), a service that automatically updates my domains DNS records to direct external traffic to little Raspberry Pi server. However the new Sky Max Hub is easily the least homelab friendly router I’ve ever had.

The Sky Max Hub

The Sky router has a justified reputation for being awkward to forward traffic from external connections for a number of reasons.

Opting for remote router management via the My Sky App, only a limited number of buggy options are exposed, making it difficult to manage.

The hub often fails to correctly identify connected devices, and the limited feature set makes it impossible to reference them, and thus impossible to reliably forward traffic.

Additionally, Sky are pushing IPV6, so without an external IPV4 to IPV6 service it’s near impossible to forward the bulk of internet traffic which uses IPV4 to the router.

Cloudflare Tunnels

To bypass these routing issues I opted to use Cloudflare Tunnels, a clever way to securely expose your local or private services to the internet—without ever opening inbound firewall ports or juggling messy port forwarding.

Instead of making your server directly reachable via DNS/DDNS settings, you install a lightweight agent called cloudflared onto the server. The agent creates an outbound-only, encrypted connection to Cloudflare’s global edge network.

Making a service available is as simple as configuring a new tunnel rule, and with Cloudflare acting as the nameserver, it can automatically create and manage the DNS rules.

However it’s not perfect for self-hosted, it only supports public HTTP and/or HTTPS traffic, so isn’t suitable for exposing SSH, FTP, databases or anything else that isn’t a website.

The Quadlet

Containers are king, and Quadlet’s running on Podman my chosen method of deployment, offering lightweight, reliable but disposable application hosting.

The cloudflared container requires minimal configuration, below is the container file I use.

# /home/chad/.config/containers/systemd/cloudflared.container
[Unit]
containerAfter=local-fs.target

[Container]
Image=docker://docker.io/cloudflare/cloudflared:latest
Exec=tunnel --loglevel debug --no-autoupdate run --token ${TOKEN}

[Service]
EnvironmentFile=/home/chad/.config/containers/systemd/cloudflared.env
Restart=always
TimeoutStartSec=900  

[Install]
WantedBy=multi-user.target default.target

For management purposes I keep the Cloudflare Tunnel API token in an enironmental file.

# /home/chad/.config/containers/systemd/cloudflared.env
TOKEN=CLOUDFLARE-TUNNEL-API-TOKEN
Profile image

Chad Tomlinson

Assistant Manager, Warehouse/IT Admin & Support

A warehouse manager, whom for over 20 years has collaborated with production and accounts to maintain just-in-time stock, whilst overseeing daily operations.

Channelling the inner geek, I've serve as an IT administrator, cooperating with senior management, whilst providing support internally for staff, and externally for clients.

Husband to my soulmate, father to two beautiful girls, domesitc challenges are limiting, but I still find time for gaming, Star Citizen being my focus, whilst dreaming of Warhammer 40k battles.