Hosting Web Apps with Cloudflare Tunnel

Using Cloudflare Tunnels as an ingress for you web app

Hosting Websites

How can we host our apps on the internet without thinking about IP address, DNS records, exposing ports, TLS certificates, etc.?

While all of these things can be tricky to set up, let's see how Cloudflare Tunnels can help us with some of these points of difficulty.


The Problem

I've got a basic Docker container running on a computer in my own network, which I want to expose to the internet. It's based on this Dockerfile:


FROM nginx
COPY . /usr/share/nginx/html

Before I even spin up a container from this image, I'd be dead in the water if I didn't have a static IP address. I could use something like Dynamic DNS, but that is awkward. I don't want to muck about with the crontab or a daemon in order to keep the DNS up-to-date.

Even if we got past that, or just acquired a static IP address, we'd still have a few problems:

  • I have to open ports on my router to forward traffic to my server
  • I have to figure out how to acquire a TLS certificate and attach it to my webserver
  • I have to keep paying for my static IP address
  • Hope I don't become victim of a DDoS attack
  • Being comfortable that my IP is publicly known and exposed

Enter Cloudflare

Specifically, enter Cloudflare Tunnel.

Cloudflare Tunnel, as the name suggests, is a Tunnelling software that effectively allows us to easily set up a secure channel of communication between our server and Cloudflare's network.

We'll configure the tunnel as an ingress, routing traffic to our website, through Cloudflare's network. This is made really easy, and we don't even need to create a single DNS record for this - CF manages that for us.

Assuming we are already using Cloudflare as our DNS server, the rest will be easy.

The daemon, cloudflared, is super simple and easy to get up and running. Once we create the tunnel on the Cloudflare Zero Trust dashboard, we'll add the service to our Docker Compose file, and then take a break, because we're basically done.


services:
  mycrapwebsite:
    # ...
    expose:
      - "80"

  cloudflared:
    image: cloudflare/cloudflared:latest
    environment:
      - TUNNEL_TOKEN=<your-token-can-go-here>
    command: tunnel --no-autoupdate run
    restart: unless-stopped

Actually, we're not done yet. We need to tell Cloudflare a couple of things:

  • Which domain we want traffic to be routed for
  • Which internal docker compose service we want that traffic routed to

The Cloudflare UI makes this rather easy, just edit the tunnel and add a new public hostname like this:

This can also be managed locally using cloudflared if you don't want to use the dashboard, or have a lot of public hostnames that need routing.

Now, we are done. Behind the scenes Cloudflare created the relevant DNS record for us in proxy mode which basically means that all traffic to that domain will enter in to Cloudflare's network using their IP address and TLS certificates. Their internal infrastructure will route the traffic in to our internal Docker network.

Notice that we didn't use a www subdomain, we are using the domain apex in this example, and being able to attach a CNAME to it is another feature provided by Cloudflare, called CNAME Flattening.

At this point, Cloudflare has handled the DNS for us, we are using their infrastructure to terminate TLS, we did not have to expose any ports or think about IP addresses, and our website is accessible on the internet. On top of that, we also gain other features like DDoS protection and a Web Application Firewall (WAF).

This is all available (at the time of writing), on the free plan, which is quite incredible.


To Recap

We were able to get a website on the internet without thinking about IP addresses, DNS records, TLS certs, port forwarding/security, firewalls, or anything else. The list of things we needed to care about were these:

  • Docker and Docker Compose
    • for simply configuring the services on our host machine
  • Cloudflare Tunnel needs to know about
    • which domain we want traffic to be routed for
    • which internal docker compose service we want that traffic routed to

We've come a long way since the dawn of the world-wide-web. It's pretty great to get tools for free which can do performance optimization, provide security, scalability, and simplicity as a feature. Not all apps require a highly sophisticated amalgamation of services and tooling in front of them. Some of them do though, and you can still use Cloudflare Tunnels for them!


Tunnels Aren't For Everything

Not all traffic types are supported. I tried to host a private container registry behind a tunnel and it seems the traffic was blocked by Cloudflare. Their ToS says this:

Use of the Services for serving video or a disproportionate percentage of pictures, audio files, or other non-HTML content is prohibited

Also, since the TLS connection between the client and Cloudflare is terminated in their own infrastructure, CF can effectively sniff all of the traffic between the client and your own web server. You'll have to decide for yourself if this is okay.

Published on 19 Jul 2024, by Kyle.