npx skills add ...
npx skills add dawiddutoit/custom-claude --skill cloudflare-tunnel-setup
Sets up a new Cloudflare Tunnel from scratch for secure remote access to home network services. Use when creating a new tunnel, replacing an expired tunnel token, or setting up remote access for a fresh installation. Triggers on "setup cloudflare tunnel", "create tunnel", "new tunnel token", "configure remote access", "cloudflare tunnel from scratch", or "tunnel not configured". Works with .env, docker-compose.yml, and Cloudflare Zero Trust.
npx skills add dawiddutoit/custom-claude --skill cloudflare-tunnel-setup
Interactive guide for setting up a new Cloudflare Tunnel from scratch.
Run this skill when you need to:
Minimum requirements: Cloudflare account, domain on Cloudflare, Docker installed.
Explicit Triggers:
Implicit Triggers:
Debugging Triggers:
Step 1: Verify .env file exists
If missing, create from example:
Step 2: Check if CLOUDFLARE_TUNNEL_TOKEN exists
Possible outcomes:
Step 3: Verify docker-compose has cloudflared service
If cloudflared service is missing, it needs to be added. See references/reference.md for service definition.
Provide these instructions to the user:
--token)Token format: Base64-encoded JSON containing Account ID, Tunnel ID, and Secret.
Step 1: Check current token status
Step 2: Add or update token
If line exists, update it. If not, add it.
Use the Edit tool to update .env:
CLOUDFLARE_TUNNEL_TOKEN= lineValidate token format:
Step 1: Restart the container
Or if container doesn't exist yet:
Step 2: Check container is running
Expected output:
Step 3: Check logs for successful connection
Look for these success indicators:
4 registered connections = healthy tunnel (2 connections per Cloudflare edge location)
If errors appear:
token is invalid: Token was copied incorrectly or expiredalready registered: Another instance using same token (stop other instances)network error: Check internet connectivityAfter tunnel is connected, configure services in Cloudflare dashboard:
Example hostnames:
| Service | Subdomain | URL |
|---|---|---|
| Pi-hole | pihole | pihole:80 |
| Webhook | webhook | webhook:9000 |
| Jaeger | jaeger | 192.168.68.135:16686 |
URL patterns:
container:port (e.g., pihole:80)host-ip:port (e.g., 192.168.68.135:16686)device-ip:port (e.g., 192.168.68.105:80)Important: Use HTTP (not HTTPS) for backends. Do NOT use host.docker.internal on Linux.
Step 1: Verify tunnel is registered
Expected: 4 "Registered tunnel connection" messages
Step 2: Check tunnel status in dashboard
Step 3: Test external access (from mobile data or external network)
Step 4: Run diagnostic script (optional)
| File | Purpose |
|---|---|
references/reference.md | Docker-compose service definition, token format details |
examples/examples.md | Example configurations for common setups |
Success:
Partial Success:
Failure Indicators:
Environment:
.env file in project rootAccounts/Access:
Tools needed:
host.docker.internal on Linux hosts./scripts/cf-tunnel-config.sh configure to update ingress via APIconfigure-google-oauth skill after tunnel setuptroubleshoot-tunnel-connectivity skill handles issues with running tunnels*grep -A 10 "cloudflared:" /home/dawiddutoit/projects/network/docker-compose.ymlgrep "CLOUDFLARE_TUNNEL_TOKEN" /home/dawiddutoit/projects/network/.env# If line exists, use sed to replace
# If not, append to file
# The token should look like:
# CLOUDFLARE_TUNNEL_TOKEN=eyJhIjoiYWJjZDEyMzQ...# Token should be base64 decodable
TUNNEL_TOKEN=$(grep "CLOUDFLARE_TUNNEL_TOKEN=" /home/dawiddutoit/projects/network/.env | cut -d'=' -f2)
echo "$TUNNEL_TOKEN" | base64 -d 2>/dev/null | python3 -c "import sys, json; d=json.load(sys.stdin); print('Valid token for account:', d.get('a', 'unknown'))"cd /home/dawiddutoit/projects/network && docker compose restart cloudflaredcd /home/dawiddutoit/projects/network && docker compose up -d cloudflareddocker ps | grep cloudflaredCONTAINER ID IMAGE STATUS NAMES
abc123... cloudflare/cloudflared:latest Up X seconds cloudflareddocker logs cloudflared --tail 30INF Registered tunnel connection connIndex=0 location=...
INF Registered tunnel connection connIndex=1 location=...
INF Registered tunnel connection connIndex=2 location=...
INF Registered tunnel connection connIndex=3 location=...docker logs cloudflared 2>&1 | grep -E "Registered tunnel|connIndex"Go to: https://one.dash.cloudflare.com
Navigate to: Access -> Tunnels
Status should show: "HEALTHY" with green indicator# From a device NOT on home network:
curl -I https://pihole.temet.ai
# Expected: HTTP 302 (redirect to Cloudflare Access) or HTTP 200 (if no auth)./scripts/cf-tunnel-config.sh show