Skip to main content

Cloudflare Tunnel Setup Guide

Purpose: Professional internet access with custom domains
Audience: Users wanting production-ready setup with own domains
Time Required: 15-20 minutes
Prerequisites: Working cluster with Traefik ingress

🚀 Quick Summary

Transform your local cluster from http://service.localhost to https://service.yourcompany.com with enterprise-grade security. Uses your Cloudflare-managed domain to provide global CDN, DDoS protection, and professional appearance.

✅ Prerequisites

Before starting, ensure you have:

  • Kubernetes cluster running (Rancher Desktop or similar)
  • Traefik ingress controller deployed
  • Services accessible locally (e.g., http://whoami.localhost)
  • Domain already added to Cloudflare (e.g., urbalurba.no)
  • Access to provision-host container
  • Logged into Cloudflare dashboard before running setup

⚠️ CRITICAL: You MUST be logged into dash.cloudflare.com before running the setup script!

🔄 How Cloudflare Tunnel Works

The Cloudflare tunnel creates a secure outbound connection from your cluster to Cloudflare's edge:

Internet → Cloudflare Edge → Tunnel → Traefik → Your Services

Key Benefits:

  • No port forwarding or firewall configuration needed
  • Automatic SSL/TLS certificates
  • DDoS protection and global CDN
  • Works behind NAT/firewalls

📋 Script Overview

Three scripts manage the complete tunnel lifecycle:

ScriptPurposeWhen to UseParameters
820-cloudflare-tunnel-setup.shCreates tunnel & configures DNSFirst time setup<domain> required
821-cloudflare-tunnel-deploy.shDeploys tunnel to KubernetesAfter setup or updatesNone (auto-detects)
822-cloudflare-tunnel-delete.shRemoves tunnel completelyClean up / start overNone (auto-detects)

🚀 Quick Start Guide

Step 1: Create Tunnel and Configure DNS

# Inside provision-host container
docker exec -it provision-host bash
cd /mnt/urbalurbadisk

# Create tunnel (interactive - will open browser for auth)
./networking/cloudflare/820-cloudflare-tunnel-setup.sh urbalurba.no

What happens:

  • Checks if tunnel already exists (smart detection)
  • Opens browser for Cloudflare authentication (see authentication steps below)
  • Creates tunnel with unique credentials
  • Configures DNS: urbalurba.no AND *.urbalurba.no → tunnel
  • Stores credentials for persistence
  • Updates kubernetes-secrets.yml with tunnel credentials

Browser Authentication Process

When the script runs, you'll need to complete a 2-step browser authentication:

Step 1: Select Domain Zone

  • A browser URL will appear in the terminal - click or copy it to your browser
  • You'll see "Authorize Cloudflare Tunnel" page with all your domains
  • ACTION: Click on the row for your specific domain (e.g., urbalurba.no)
  • All domains should show "Active" status with green checkmarks

Step 2: Authorize Tunnel Creation

  • You'll see a confirmation dialog: "Authorize Tunnel for [your-domain]"
  • Message: "To finish configuring Tunnel for your zone, click Authorize below"
  • ACTION: Click the blue "Authorize" button (NOT "Cancel")

Step 3: Success Confirmation

  • You'll see a "Success" page
  • Message: "Cloudflared has installed a certificate allowing your origin to create a Tunnel on this zone"
  • ACTION: Close the browser window and return to the terminal

⚠️ Important: You must complete BOTH browser steps (select domain AND authorize) or you'll get "Unauthorized" errors. The authentication link has a timeout, so complete it quickly.

Step 2: Deploy Tunnel to Kubernetes

# Deploy to current cluster (no parameters needed)
./networking/cloudflare/821-cloudflare-tunnel-deploy.sh

What happens:

  • Creates Kubernetes secret with credentials
  • Deploys tunnel connector pod
  • Routes traffic to Traefik ingress
  • Establishes connection to Cloudflare edge

Step 3: Root Domain Configuration (Automatic)

The setup script now automatically configures both:

  • Root domain: urbalurba.no → tunnel
  • Wildcard subdomains: *.urbalurba.no → tunnel

No manual configuration needed! Both domains are set up automatically during the tunnel creation process.

Note: If you have Cloudflare Workers intercepting the root domain, you may need to:

  • Check Workers & Pages → Remove any custom domains
  • Check Workers Routes → Delete routes for your domain

Step 4: Verify Setup

# Test both root domain and subdomain routing
curl https://urbalurba.no
curl https://test.urbalurba.no
curl https://whoami.urbalurba.no
curl https://openwebui.urbalurba.no

Both root domain and subdomains should work automatically!

⚠️ Authentication Note: If you want to protect services with Authentik authentication on external domains, see docs/rules-ingress-traefik.md section "External Domain Authentication Limitations" for important manual configuration requirements.

🗑️ Complete Cleanup

To completely remove a tunnel and start over:

# Delete everything (no parameters needed)
./networking/cloudflare/822-cloudflare-tunnel-delete.sh

What gets deleted:

  • Kubernetes deployment, configmap, and secrets
  • Cloudflare tunnel
  • Local configuration files
  • TODO: Cloudflare DNS routes (you must do it manually )
  • TODO: Cloudflare API tokens (you must do it manually )

🔧 Troubleshooting

Common Issues and Solutions

ProblemCauseSolution
"Worker is Running!" on root domainCloudflare Worker intercepting trafficCheck Workers & Pages for custom domains, remove Worker routes
502 Bad GatewayTunnel can't reach serviceVerify Traefik is running, check tunnel logs
DNS_PROBE_FINISHED_NXDOMAINMissing DNS recordRun setup script or manually add CNAME in Cloudflare DNS
Tunnel pod not startingMissing credentialsRe-run setup script to generate credentials
Certificate error during setupNot logged into CloudflareLogin to dash.cloudflare.com first
"Cannot have more than 50 tokens"Too many API tokens createdClean up unused tokens (see below)
REST API unauthorized errorsIncomplete browser authenticationComplete BOTH steps: select domain AND click Authorize
Authentication timeoutTook too long to complete browser stepsRun script again for fresh link, complete quickly
Wrong domain selectedMultiple domains in accountEnsure you click the correct domain row that matches script parameter
Permission denied errorsFile ownership issuesScript now automatically fixes ownership using docker exec -u root
"Unauthorized: Failed to get tunnel"Credentials mismatchScript now properly updates both Kubernetes secret and ConfigMap

Cleaning Up API Tokens (50 Token Limit)

Cloudflare has a limit of 50 API tokens per account. Each tunnel creation attempt generates a new token, so repeated testing can hit this limit.

To clean up unused tokens:

  1. Go to https://dash.cloudflare.com/profile/api-tokens
  2. Look for tokens with names like:
    • cloudflared-* (from tunnel creation attempts)
    • Old/duplicate tokens from testing
    • Tokens you no longer use
  3. Click the "Delete" button (trash icon) next to each unused token
  4. Confirm the deletion

Prevention tips:

  • Use 822-cloudflare-tunnel-delete.sh to properly clean up tunnels
  • Avoid repeatedly running setup without proper cleanup
  • Delete test tunnels when done testing

Checking Tunnel Status

# View tunnel pod status
kubectl get pods -n default -l app=cloudflared

# Check tunnel logs
kubectl logs -n default -l app=cloudflared --tail=50

# Verify DNS records in Cloudflare Dashboard
# DNS → Records → Look for CNAME entries pointing to .cfargotunnel.com

Important Paths

FilePathPurpose
Certificate/mnt/urbalurbadisk/cloudflare/cloudflare-certificate.pemGlobal Cloudflare auth (created during browser auth)
Credentials/mnt/urbalurbadisk/cloudflare/cloudflare-tunnel.jsonTunnel-specific secrets (encrypted)
Config/mnt/urbalurbadisk/cloudflare/cloudflare-tunnel-config.ymlTunnel configuration
Manifest/mnt/urbalurbadisk/manifests/cloudflare-tunnel-manifest.yamlK8s deployment

⚠️ Security Note: Never share the certificate or credential files. They provide access to your Cloudflare account and tunnel.

🏗️ Architecture

Traffic Flow

User Request → Cloudflare Edge → Tunnel Pod → Traefik → Service

Components

  • Cloudflare Edge: Global CDN and security layer
  • Tunnel Connector: Pod running cloudflared in your cluster
  • Traefik: Ingress controller routing to services
  • Services: Your applications with IngressRoute definitions

DNS Configuration

  • Root domain: urbalurba.no → tunnel (automatically configured)
  • Wildcard: *.urbalurba.no → All subdomains route to tunnel
  • Proxied: Orange cloud enabled for CDN and security

📚 Additional Resources