Self-host part 2: Connecting a domain
Part 2 of self-hosting and how to set up a secure tunnel between your domain and Raspberry Pi.
The previous episode set up the Raspberry Pi with Docker and got it ready for the web apps we want to host. This step is optional and depends on if you want to access the services outside your network. It also connects with a domain name, making it easier to access than an IP address.
I bought my domain from Cloudflare and have been more than happy with the admin dashboard and features for direct email and alike. One of these features is to offer a secure tunnel to a home server for free, saving the hassle and security issues of opening router ports or configuring fiddly reverse-proxy software.
cloudflared is a lightweight daemon that runs alongside Docker creating a secure out-going only connection to Cloudflare's network. Traffic is routed securely to your local services without exposing a single port on your router.
Part 1: Create the Tunnel in Cloudflare Zero Trust
First, we need to create the tunnel credentials within Cloudflare.
- Head over to the Cloudflare Zero Trust Dashboard
- Navigate to Networks > Tunnels and click Create a tunnel
- Select Cloudflared as the connector type and give your tunnel a friendly name (e.g.,
raspberrypi-homelab). - On the installation screen, choose Docker as your operating environment.
- In the generated command box, locate the long string of characters after
--token. Copy that token ready for the next step.
Part 2: Set Up Docker Compose
Instead of running a manual docker run command, using docker-compose ensures your tunnel automatically starts whenever your Raspberry Pi boots up.
- SSH into your Raspberry Pi and create a directory for your tunnel:
mkdir -p ~/cloudflared
cd ~/cloudflared
- To keep sensitive credentials out of your configuration files, create a
.envfile for your token:
nano .env
- Paste your Cloudflare tunnel token into the file and save:
TUNNEL_TOKEN=ey...your_token_here_from_Step_1
- Next, create your
docker-compose.ymlfile:
nano docker-compose.yml
- Paste the following service configuration:
cloudflared:
image: cloudflare/cloudflared:latest
container_name: cloudflared
restart: unless-stopped
environment:
- TUNNEL_TOKEN=${TUNNEL_TOKEN_FROM_PART_1}
command: tunnel --no-autoupdate run```
Part 3: Route Traffic via Public Hostnames
Now that the tunnel connector is ready, tell Cloudflare where to route traffic when someone hits your domain.
- Back in the Cloudflare dashboard, head to the Public Hostname tab for your new tunnel and click Add a public hostname
- Subdomain and domain: Choose the subdomain (e.g.,
dashboardorrss) and select your domain name - Service Details:
- Type:
HTTP(orHTTPSif your local app enforces TLS) - URL: Point to your service (e.g.,
192.168.1.50:8080orcontainer_name:8080)
- Type:
- Save the hostname
Part 4: Fire It Up!
- With your configuration in place, spin up the container on your Pi:
docker compose up -d
- Check the logs to verify that the connector established outbound connections:
docker logs -f cloudflared
If you see messages showing connections established to Cloudflare’s edge locations, you're good to go! Navigate to [https://subdomain.yourdomain.com](https://subdomain.yourdomain.com) from your phone or any external network—no open ports, no port forwarding, and full HTTPS encryption handled seamlessly by Cloudflare.