The Fastest Way to Host Multiple Websites with One Cloudflare Tunnel#
I wanted to host my portfolio website as fast as possible without dealing with networking complexity. Turns out, you can deploy multiple websites and route different domains to each using one Cloudflare tunnel and simple kubectl commands.
The Idea#
Instead of setting up reverse proxies, port forwarding, and SSL certificates, use Cloudflare Tunnels to connect your Kubernetes services outbound to Cloudflare’s network. One tunnel can handle multiple domains pointing to different services.
Quick Setup#
Step 1: Create the Tunnel#
cloudflared tunnel create my-websites
Copy the tunnel token from the output and store it securely.
Step 2: Deploy the Tunnel#
Deploy cloudflared with the token from the secret:
export TUNNEL_TOKEN="your-token-here"
kubectl run cloudflare-tunnel \
--image=cloudflare/cloudflared:latest \
--env="TUNNEL_TOKEN=$TUNNEL_TOKEN" \
-- tunnel run --token "$TUNNEL_TOKEN"
Step 3: Deploy Your Websites#
Deploy a portfolio site:
kubectl run portfolio --image=nginx --port=80
kubectl expose pod portfolio --port=80
Deploy a blog:
kubectl run blog --image=httpd --port=80
kubectl expose pod blog --port=80
The kubectl expose command automatically creates a ClusterIP service that makes your pod reachable from within the cluster.
Step 4: Configure Domain Routes#
In your Cloudflare dashboard, configure the tunnel to route different domains:
myportfolio.com→http://portfolio.default.svc.cluster.local:80blog.myportfolio.com→http://blog.default.svc.cluster.local:80
That’s it. Two different websites, one tunnel, deployed in record time.
The Magic: Multiple Domains, One Tunnel#
The key insight is that one Cloudflare tunnel can route traffic to multiple Kubernetes services based on the hostname. Each service you create with kubectl expose gets its own DNS name in the cluster (servicename.namespace.svc.cluster.local).
So you can have:
# Deploy different apps
kubectl run portfolio --image=nginx --port=80
kubectl expose pod portfolio --port=80
kubectl run blog --image=ghost --port=2368
kubectl expose pod blog --port=2368
All through the same tunnel deployment.
Adding New Sites#
Want to add another website? It’s one command:
kubectl run newsite --image=nginx --port=80
kubectl expose pod newsite --port=80
Then add newsite.yourdomain.com → http://newsite.default.svc.cluster.local:80 in your Cloudflare tunnel configuration.
Why This Works So Well#
- kubectl run + expose creates everything you need - Pod + Service in two commands
- Kubernetes service discovery - Services are automatically reachable via DNS
- One tunnel routes everywhere - Cloudflare handles routing based on hostname
- No networking complexity - Everything stays internal to the cluster
- Automatic SSL - Cloudflare manages certificates for all domains
Debugging#
Check if your tunnel is running:
kubectl logs pod/cloudflare-tunnel
List your services:
kubectl get services
Test service connectivity:
kubectl port-forward service/portfolio 8080:80
curl localhost:8080
The Bottom Line#
This approach eliminates all the traditional hosting complexity:
- No reverse proxy configuration
- No SSL certificate management
- No port forwarding
- No load balancer setup
Just run your apps with kubectl, expose them as services, and route domains through one tunnel. Perfect for quickly hosting portfolios, side projects, or any collection of web applications.
The best part? Adding a new site is literally two kubectl commands and updating one configuration in Cloudflare.