Skip to content

My Process (Cloudflare Tunnel Setup)

AJprogramming123 edited this page Jun 20, 2025 · 6 revisions

My Process (Cloudflare Tunnel Setup):


1.)

So, after setting up my isolated user on my Raspberry Pi, I made sure that the user could only interact with Docker and only expose traffic through port 80. This is part of my security model: even if an intruder manages to reach the Pi or container somehow, that user has zero sudo/root permissions, and no way to break outside of the Docker ecosystem. It's literally only there to run containers and start the Cloudflare tunnel. That's it. Nothing else.


2.)

Why did I even use Cloudflare Tunnel?

Because I’m running a physical backend server (the Pi), and this method is honestly better and more modern than opening ports through the router. Port forwarding exposes your internal network, and if someone gets in through that port. But a Cloudflare tunnel does the opposite — it creates an outbound connection from your Pi to Cloudflare's edge, so no open ports at all on the network. The tunnel proxies the traffic back inward to your container like a reverse proxy.

Bonus:

  • It gives free HTTPS.
  • It hides my home IP address.
  • Doesn’t affect my home network or NAT settings at all.

I’m also running:

  • Tailscale (mesh VPN) to restrict access to only specific devices.
  • Fail2Ban just in case anything goes wrong with that.

Security always comes first in anything I build.


3.)

I installed Cloudflare’s daemon — this is what creates and manages the tunnel.

The package is called cloudflared:

sudo apt install cloudflared -y

This is the actual connector. It’s what keeps the tunnel alive. Once installed, the first command you run is:

cloudflared tunnel login

That opens a browser window, logs you into Cloudflare, and lets you pick the domain you want to use (mine is partagoemailbreach.xyz). This is what authorizes your device to manage tunnels for your domain.

BUT — here's where I hit a wall: Cloudflare wanted me to either pay for a personal domain plan or bring my own domain. So I bought one from Namecheap, and when I added it into Cloudflare, they gave me 2 nameservers to add into my Namecheap settings. After I updated the nameservers in Namecheap, Cloudflare was able to take control of the DNS. That was the verification step.


4.)

Once that was complete, the command:

cloudflared tunnel create emailbreach-tunnel

Did two things:

  • Gave me a tunnel credentials file: it looks like <tunnel-id>.json, and lives in ~/.cloudflared/
  • Gave me a tunnel hostname like emailbreach.cfargotunnel.com (Cloudflare generated)

Also at this point I had a file called cert.pem saved automatically after login — that’s proof this Pi is allowed to create/manage tunnels.


5.)

Next step was setting up the actual routing using a YAML config file:

sudo nano ~/.cloudflared/config.yml

Here’s what I wrote:

tunnel: emailbreach-tunnel
credentials-file: /home/pi/.cloudflared/<tunnel-id>.json

ingress:
  - hostname: www.partagoemailbreach.xyz
    service: http://localhost:____
  - service: http_status:404

How i found it

This config means:

  • When someone visits my domain (www.partagoemailbreach.xyz), it’s routed into my local container running on port 8080.
  • Any unmatched request returns a 404.

At this point, my tunnel was active.

And to make sure it always runs on boot:

sudo cloudflared service install

That sets it up as a systemd service. Done.


DNS Stuff I Had to Do (With Namecheap + Cloudflare)

Once I had the domain (partagoemailbreach.xyz) from Namecheap, I had to:

  1. Log into Namecheap → manage domain → set Custom Nameservers.

  2. Paste the two nameservers Cloudflare gave me when I added the domain to my Cloudflare dashboard.

    • Like kevin.ns.cloudflare.com and tori.ns.cloudflare.com.

Once I did that, Cloudflare became the DNS manager.

Then I went into Cloudflare’s DNS tab and added a CNAME record:

Field Value
Type CNAME
Name www
Target emailbreach.cfargotunnel.com
Proxy Status Proxied (orange cloud)

This maps www.partagoemailbreach.xyz to the tunnel’s hostname.

Docs: https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/routing-to-tunnel/dns/


Docker Architecture Issue (ARM64 vs ARM32) — Figuring That Out

So here’s the thing. I was building Docker images for my Flask app and Nginx setup, and I noticed some images would fail or throw warnings when I pulled them.

It was something like:

no matching manifest for linux/arm64 in the manifest list entries

That’s when I realized that even though the Raspberry Pi 4/5 is 64-bit hardware, Docker wasn’t defaulting to arm64. Instead, it wanted arm32 (armv7) images.

So I ran this test to find out what worked:

docker pull --platform linux/arm/v7 busybox
docker run --rm busybox uname -m

That gave me:

armv7l

(https://stackoverflow.com/questions/78637225/can-i-build-arm32-docker-files-with-dockerhub#:~:text=Note%20I%20am,linux/arm/v7) Then I tested 64-bit:

docker pull --platform linux/arm64 busybox
docker run --rm busybox uname -m

If that command fails or gives you errors, then Docker isn’t ready for 64-bit containers on your Pi setup (because of the OS). My Pi runs Raspberry Pi OS Lite which is 32-bit even if the CPU is 64-bit.

So I stuck with arm32v7 builds.


GitHub Actions Fix

Since I now knew I had to build arm32v7 images for both my Flask app and Nginx container, I added this to my GitHub Actions build workflow:

platforms: linux/arm/v7

This forces Docker Buildx to create a 32-bit compatible image that runs fine on my Pi.

Clone this wiki locally