I Spent Hours Googling Port Forwarding. Then I Found Cloudflare Tunnel

Published: (January 11, 2026 at 04:06 AM EST)
3 min read
Source: Dev.to

Source: Dev.to

Cover image for I Spent Hours Googling Port Forwarding. Then I Found Cloudflare Tunnel

I have this internal service running on a server behind NAT. Private IP, no public access. The usual nightmare.

My ISP doesn’t give me a static IP. My router’s port‑forwarding UI looks like it was designed in 2003. And every time I finally get it working, my IP changes and everything breaks.

Then I found Cloudflare Tunnel. It took me 10 minutes to expose my service to the internet with a custom domain. No port forwarding. No static IP needed. Free.

Here’s exactly how I did it.

The Problem

I had a service running on 192.168.39.231:8088. HTTPS with a self‑signed cert. I needed to access it from anywhere, ideally at a nice domain like myapp.mydomain.com.

The traditional approach:

  • Get a static IP (costs money)
  • Forward ports on your router (pain in the ass)
  • Set up dynamic DNS (another thing to maintain)
  • Deal with SSL certs (Let’s Encrypt works but still annoying)

Or just use Cloudflare Tunnel.

Quick Tunnel (The Fast Way)

If you just want to test something quick, there’s a zero‑config option:

cloudflared tunnel --url https://192.168.39.231:8088 --no-tls-verify

Cloudflared gives you a random URL like alice-ion-married-knights.trycloudflare.com. Your service is now public.

The --no-tls-verify flag is important if your origin has a self‑signed cert. Without it, cloudflared refuses to connect because it can’t verify the certificate.

Random URLs aren’t ideal, so let’s set up a proper custom domain.

Named Tunnel (The Right Way)

You need a Cloudflare account and your domain added to Cloudflare.

Step 1: Login

cloudflared tunnel login

A browser window opens; authenticate. Cloudflared downloads a cert to ~/.cloudflared/cert.pem.

Step 2: Create the tunnel

cloudflared tunnel create my-app

Output example:

Tunnel credentials written to /root/.cloudflared/8a0b7c44-4677-421e-810b-f5e6de9d0555.json
Created tunnel my-app with id 8a0b7c44-4677-421e-810b-f5e6de9d0555

Save that tunnel ID; you’ll need it later.

Step 3: Route your domain

cloudflared tunnel route dns my-app app.yourdomain.com

This creates a CNAME record in Cloudflare pointing your subdomain to the tunnel.

Step 4: Create the config file

Create ~/.cloudflared/config.yml:

tunnel: my-app
credentials-file: /root/.cloudflared/8a0b7c44-4677-421e-810b-f5e6de9d0555.json

ingress:
  - hostname: app.yourdomain.com
    service: https://192.168.39.231:8088
    originRequest:
      noTLSVerify: true
  - service: http_status:404

Replace the tunnel ID and hostname with your own values. The noTLSVerify: true line is the config‑file equivalent of --no-tls-verify and is required for self‑signed certificates. The final ingress rule catches everything else and returns a 404; it’s mandatory.

Step 5: Run the tunnel

cloudflared tunnel run my-app

Your service is now live at https://app.yourdomain.com.

Common Issues I Hit

“Unable to reach the origin service”

Your service isn’t running, or cloudflared can’t reach it. Test locally:

curl -k https://192.168.39.231:8088

If curl can’t reach it, cloudflared won’t be able to either.

“tls: failed to verify certificate”

Your origin uses a self‑signed cert. Add --no-tls-verify for quick tunnels or noTLSVerify: true in the config for named tunnels.

“credentials file doesn’t exist”

You likely forgot to replace the placeholder path in config.yml with the actual credentials file created in Step 2. Ensure the path matches exactly.

Running as a Service

You probably don’t want to keep a terminal open forever. Install cloudflared as a system service:

cloudflared service install
systemctl start cloudflared
systemctl enable cloudflared

Now it runs on boot and restarts automatically if it crashes.

Why This Is Better

  • No port‑forwarding headaches
  • No static IP needed
  • No dynamic DNS maintenance
  • Free SSL from Cloudflare
  • Works behind strict NATs and firewalls
  • The tunnel connects outbound, so it works even when inbound ports are blocked

I should have found this years ago.

The Bottom Line

If you’re exposing internal services to the internet the old way, stop. Cloudflare Tunnel takes about 10 minutes to set up and just works.

The quick tunnel is great for testing. Named tunnels with custom domains are what you want for anything production‑grade.

What internal services are you exposing? Feel free to share—I’m curious what others are running through tunnels.

Back to Blog

Related posts

Read more »

Hello, Newbie Here.

Hi! I'm falling back into the realm of S.T.E.M. I enjoy learning about energy systems, science, technology, engineering, and math as well. One of the projects I...