Skip to content
The 31 guidesFREN中文
Guides
Part 3 · guide 4 of 4 Level: Intermediate Reading time: 15 min Platforms: Linux

Cloudflare Tunnel: expose things cleanly

Put a service online on your own domain, over HTTPS, without opening a single port on your router. The tunnel goes out from your home, it doesn't come in.

In this guide
  1. 01The thing that changes everything: the tunnel goes out, it doesn’t come in
  2. 02The named tunnel, the method that lasts
  3. 03A thing that’s exposed is a thing that’s public
  4. 04The express tunnel, for a five-minute demo
  5. 05Frequently asked questions

In short

Cloudflare Tunnel puts an app from your mini-PC online on your own domain, over HTTPS, without opening a port on your router or revealing your IP address: the cloudflared program opens an outbound connection to Cloudflare, and public traffic comes back down that tunnel. You need a domain managed by Cloudflare, and the free plan is enough. Keep it for web apps meant for the public, protect the rest with Cloudflare Access, and leave SSH, Ollama or a database on Tailscale.

Do this first: Tailscale: your private networkSecuring access

Tailscale solves one problem: you, from your devices, reach your machine from anywhere, privately. Perfect for working. But sometimes you want the opposite: for the public to reach an app you’ve just set up. A demo to show a colleague, a dashboard for the team, a page you want to share with a simple link. Tailscale can’t do that, it’s private by nature.

The classic answer is port forwarding on the router. It’s fragile (your IP changes, the router reboots, the config breaks), and above all it exposes your home’s IP address to the whole world. Bad idea. Cloudflare Tunnel solves all of this in a smarter way.

The thing that changes everything: the tunnel goes out, it doesn’t come in

Here’s the idea to keep firmly in mind. A small program, cloudflared, runs on your mini-PC and opens a connection toward Cloudflare, just like your browser opens a connection toward a site. The public traffic that arrives at myapp.your-domain.com then comes back down through that same tunnel to your local app.

The concrete consequences, and they’re beautiful:

  • No port open on your router. Nothing to configure on the Freebox/Livebox side.
  • Your home IP stays hidden. The world sees Cloudflare, never your address.
  • Free, automatic HTTPS. The certificate is managed by Cloudflare.
  • DDoS protection included, because everything goes through their network first.

The named tunnel, the method that lasts

There’s an express tunnel (we’ll come back to it at the end), but for a service that needs to last over time, you create a named tunnel. It survives reboots, keeps the same config, and plugs in cleanly as a system service. Here’s the full procedure, from the command line, with a config written in a file you can reread and version.

0 of 6 steps done Your ticks stay in this browser.

  1. Install cloudflared on the mini-PC

    We go through Cloudflare’s official apt repository, to get updates automatically:

    # Add Cloudflare's GPG key
    sudo mkdir -p --mode=0755 /usr/share/keyrings
    curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg \
      | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
    # Add the repository
    echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared any main" \
      | sudo tee /etc/apt/sources.list.d/cloudflared.list
    # Install
    sudo apt update && sudo apt install cloudflared
    
  2. Connect cloudflared to your account

    cloudflared tunnel login
    

    This opens your browser. You choose the domain to authorize, and Cloudflare drops a certificate into ~/.cloudflared/. That’s what proves this tunnel has the right to act on your domain.

  3. Create the named tunnel

    cloudflared tunnel create mini
    

    This creates a tunnel called mini and writes a credentials file in JSON (something like ~/.cloudflared/<a-long-id>.json). Note the identifier shown: we need it right after.

  4. Write the config file

    Create ~/.cloudflared/config.yml. It’s the one that says: “traffic from the mini tunnel arriving at such-and-such domain goes to such-and-such local service.”

    tunnel: <your-tunnel-id>
    credentials-file: /home/your-user/.cloudflared/<your-tunnel-id>.json
    
    ingress:
      # myapp.your-domain.com → the app running locally on port 8099
      - hostname: myapp.your-domain.com
        service: http://localhost:8099
      # Everything else gets a 404, required at the end of the list
      - service: http_status:404
    

    The ingress block reads top to bottom. The last line http_status:404 is a required catch-all: without it, cloudflared refuses to start. You can add other hostname entries above it to expose several apps through the same tunnel.

  5. Route the DNS

    cloudflared tunnel route dns mini myapp.your-domain.com
    

    This command creates the DNS record at Cloudflare that points your subdomain to the tunnel. Once per hostname.

  6. Test, then install as a service

    Run the tunnel by hand to check that everything answers:

    cloudflared tunnel run mini
    

    Open https://myapp.your-domain.com in a browser. If your local app responds, you’ve won. Stop it with Ctrl+C, then install it as a service so it survives reboots:

    # With sudo, ~ means /root: so give the full path to your config
    sudo cloudflared --config /home/your-user/.cloudflared/config.yml service install
    # Start the service and check that it's running
    sudo systemctl start cloudflared
    systemctl status cloudflared
    

    That’s the classic trap: run with sudo but without --config, cloudflared looks for its config in root’s folder and finds nothing. After each change to config.yml, a sudo systemctl restart cloudflared applies it.

A thing that’s exposed is a thing that’s public

Let’s be clear about the risk, because it’s real. As soon as you route a hostname, anyone on the Internet can knock at that door. So:

  • Put authentication in front of anything sensitive. Cloudflare Access can filter by email (only the accounts you authorize get through), it’s free for a small group (the free Zero Trust plan goes up to 50 users) and it saves you from exposing an admin dashboard to all comers.
  • Never tunnel your raw services: SSH, the Ollama API (port 11434), a database. Those stay on Tailscale, full stop. Cloudflare Tunnel is for web apps meant to be public.

The mental rule: Tailscale for you, Cloudflare Tunnel for the world. Before exposing anything, take a pass through Securing access to know what to lock down.

The express tunnel, for a five-minute demo

Don’t need a permanent tunnel? One command, no config, no domain:

cloudflared tunnel --url http://localhost:8099

Cloudflare spits out a random trycloudflare.com URL you can share right away. Ideal for showing something to a colleague in a meeting. But it’s ephemeral: the URL changes every launch and disappears when you stop the command. Cloudflare keeps this mode for testing and demos, with no uptime guarantee (its docs). For a service meant to stick around, go back to the named tunnel above.

Frequently asked questions

Can I use Cloudflare Tunnel without a domain name?

Yes, for a quick demo. The command cloudflared tunnel --url http://localhost:8099 gives you a random trycloudflare.com address you can share right away. It is short-lived: it changes every time you run it and disappears when you stop the command, and Cloudflare reserves this mode for testing, with no uptime guarantee. For a service meant to last, you need a domain and a named tunnel.

How do I hand my domain name over to Cloudflare?

Buy the domain from any registrar, or from Cloudflare directly; a .com costs around ten euros a year. Then point its nameservers to Cloudflare, a guided step in their dashboard that takes about ten minutes. Once the domain is active on their side, you can create the tunnel.

Should I create the tunnel from the command line or from the Cloudflare dashboard?

Both work. From the dashboard, you declare the tunnel and its addresses with the mouse, then copy an install command carrying a token onto the mini-PC, but the configuration then lives at Cloudflare. From the command line, it sits in a config.yml file on your machine, which you can reread and keep under version control.

Can I expose several apps through a single Cloudflare tunnel?

Yes. In the ingress block of the config.yml file, add one hostname entry per app, each pointing to its local port, above the final http_status:404 line. That last line is mandatory: without it, cloudflared refuses to start. Each new subdomain is routed once with cloudflared tunnel route dns.

Why can't cloudflared find its configuration once installed as a service?

When run with sudo, cloudflared looks for its configuration in root's folder and finds nothing. So you have to give it the full path to the file at install time, with sudo cloudflared --config /home/your-user/.cloudflared/config.yml service install. After each change to config.yml, sudo systemctl restart cloudflared applies it.

Terms in this guide: TailscaleIP addressCloudflare TunnelTerminal (command line)SSHOllamaAPI

Spotted a mistake?

A command stopped working, a price changed?

Tools change every month. Tell me what is wrong in this chapter and I will fix it and update its date.

Only the page, your message and the optional contact are kept. Nothing else.

Guide 18 of 31 · part 3 no guides read yet Open the list of guides