> ## Content Index
> Fetch the complete content index at: https://notes.d4rkcyber.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Cloudflare Tunnels
- URL: https://notes.d4rkcyber.com/cloudflare-tunnels/
- Published: 2026-06-02T00:00:00.000Z
- Updated: 2026-10-28T14:12:10.000Z
- Description: Using cloudflared to expose homelab services to the internet without opening any firewall ports. Free, reliable, and integrates cleanly with Cloudflare Access for an auth layer.
- Author: David Dami
- Tags: Infrastructure, cloudflare, tunnels, cloudflared, homelab, zero-trust

## What It Does

cloudflared runs on your server, creates an outbound connection to Cloudflare's edge, and routes traffic for configured hostnames through that connection. Your server needs zero inbound ports open — not even 80 or 443.

It's free, works behind CGNAT and strict firewalls, and SSL is handled automatically. For most homelab exposure use cases it's the quickest path from service to public URL.

## Installing cloudflared

```bash
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo gpg --dearmor -o /usr/share/keyrings/cloudflare-main.gpg
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared jammy main' | sudo tee /etc/apt/sources.list.d/cloudflared.list
sudo apt update && sudo apt install cloudflared

```

## Authenticating

```bash
cloudflared tunnel login

```

A browser window opens. Select your domain. cloudflared saves a cert to `~/.cloudflared/`.

## Creating a Tunnel

```bash
cloudflared tunnel create homelab

```

Note the tunnel ID in the output. cloudflared writes a credentials JSON to `~/.cloudflared/`.

## Config File

Create `~/.cloudflared/config.yml`:

```yaml
tunnel: <your-tunnel-id>
credentials-file: /root/.cloudflared/<tunnel-id>.json

ingress:
  - hostname: app.yourdomain.com
    service: http://localhost:8080
  - hostname: notes.yourdomain.com
    service: http://localhost:3000
  - service: http_status:404

```

The catch-all entry at the bottom is required — cloudflared returns 404 for any hostname that doesn't match.

## Creating DNS Records

```bash
cloudflared tunnel route dns homelab app.yourdomain.com
cloudflared tunnel route dns homelab notes.yourdomain.com

```

This creates CNAME records pointing to the tunnel endpoint in Cloudflare DNS.

## Running as a Service

```bash
sudo cloudflared service install
sudo systemctl start cloudflared
sudo systemctl enable cloudflared

```

## Docker Version

If you prefer keeping it in a container:

```yaml
services:
  cloudflared:
    image: cloudflare/cloudflared:latest
    command: tunnel --no-autoupdate run
    environment:
      - TUNNEL_TOKEN=your_tunnel_token
    restart: unless-stopped

```

The token-based approach is cleaner for Docker — no credential file mounts needed. Get the token from the Cloudflare Zero Trust dashboard under Tunnels.

## Adding Auth with Cloudflare Access

For services I want protected behind a login (Grafana, internal dashboards, anything without solid built-in auth):

1. Zero Trust → Access → Applications → Add
2. Select the hostname
3. Configure a policy — email OTP, GitHub, Google, etc.

Users hit the service URL, get the Cloudflare Access login page, authenticate, and then land on the app. Clean layer of auth without touching the app itself.

## When I Use This vs Pangolin

Cloudflare Tunnels is my default for services I want publicly accessible and don't mind routing through Cloudflare. For anything where I want the full infrastructure chain under my own control — or when I need access management features that Cloudflare Access doesn't cover — I use Pangolin instead.