Note: Since this guide was written, Cloudflare added GUI tunnel management. See their blog post, Ridiculously easy to use Tunnels, for more info.
Let's say you have a website running locally that you want to make publicly accessible. Pretty straightforward, right? Open up ports 80 / 443, maybe set up a reverse proxy, and add an A record pointing to your IP. Job done. Your site is online. Unfortunately, you’ve also made yourself a target by advertising your IP and opening your ports.
It will probably be fine. Keep your packages up to date, perhaps isolate the server with a hypervisor / VLAN / DMZ, and you’d have to be super unlucky to have an attacker find a way into your internal network. But traditional setups like this are difficult to set up for beginners, often require a fair bit of dedicated resources, and are time consuming to maintain.
What if you could get a website or other service online in seconds, without opening ports or worrying about inbound traffic at all, without configuring SSL, and without sacrificing performance? That’s exactly what Cloudflare Tunnel does. We use it for many of our websites, which allows us to close all ports on our servers and prevent direct attacks on our IPs.
If you’re interested in trying it out, just follow along below and you’ll be up and running in no time. This guide assumes your domain is using Cloudflare nameservers and is configurable through the Cloudflare dashboard.
1. Install the cloudflared daemon
Linux / Windows
Debian / Ubuntu install commands below. If you’re on a different system, check the downloads page for the correct install file or build from source.
# Debian / Ubuntu amd64
wget -q https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb && dpkg -i cloudflared-linux-amd64.deb
# Debian / Ubuntu arm64
wget -q https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64.deb && dpkg -i cloudflared-linux-arm64.deb
macOS
brew install cloudflare/cloudflare/cloudflared
Docker
While there is a docker image, we don’t recommend going this route. You then need to create a new container for every running service, instead of just controlling ingress options in a single configuration file.
2. Authenticate with your Cloudflare account
This command will generate a link which will take you to your cloudflare account. Then select one of your domains. Don’t worry about selecting all of them as the tunnel will work across multiple domains regardless.
cloudflared tunnel login
3. Create a tunnel
While it’s possible to run multiple tunnels for multiple services, one tunnel is really all you need. In this example we’ll name our tunnel main
.
cloudflared tunnel create main
4. Create a configuration file
You should now have a .cloudflared
directory in your home folder with two files: cert.pem
and <UUID>.json
. Make note of the generated UUID and create a configuration file in the same folder called config.yml
. This is where your ingress rules are managed.
tunnel: 6ff42ae2-765d-4adf-8112-31c55c1551ef
credentials-file: /root/.cloudflared/6ff42ae2-765d-4adf-8112-31c55c1551ef.json
ingress:
# Rules map traffic from a hostname to a local service:
- hostname: example.com
service: http://localhost:8000
# Rules can match the request's path to a regular expression:
- hostname: static.example.com
path: /*.(jpg|png|css|js)
service: http://localhost:8001
# Rules can match the request's hostname to a wildcard character:
- hostname: "*.example.com"
service: http://localhost:8002
# If your service uses self-signed SSL, set noTLSVerify
- hostname: secure.example.net
service: https://localhost:8003
originRequest:
noTLSVerify: true
# Last line is a catch-all rule:
- service: http_status:404
Replace the UUID in the example with your own, as well as the /root
folder if you’re not running as the root user. There are other supported protocols and more configuration options, which you can find in the official documentation. When you’re done, validate your rules with cloudflared tunnel ingress validate
.
5. Run as a service
This is optional. You can start and stop tunnels manually if you want to share something temporarily, but for anything more permanent you should run as a service.
When you install the service, your configuration file in ~/.cloudflared/
should be copied to /etc/cloudflared/
. In my experience that isn’t always the case (possibly due to using a .yaml
extension instead of .yml
), but if your settings don’t pick up, check the file and symlink your home folder version to the /etc/cloudflared/
directory.
Linux
# Install service
cloudflared service install
# Start service
systemctl start cloudflared
# Enable at startup
systemctl enable cloudflared
macOS
cloudflared service install
Windows
6. Route domain to tunnel
Add a CNAME record to point traffic to your tunnel. Recalling that we named our tunnel main
, the command for this is:
cloudflared tunnel route dns main <hostname>
If you didn’t choose the zone you’re trying to create a record for when you ran cloudflared tunnel login
, this may try to create a subdomain on the wrong zone. In that case, just manually enter the CNAME record pointing to <UUID>.cfargotunnel.com
.
And that’s it! Your service should be on the internet and available to anyone with a connection.
To add another service, update your configuration file and restart cloudflared:
systemctl restart cloudflared
Odds & Ends
Please remember that SSH port forwarding and VPNs exist, and you don’t necessarily need to make services on remote machines public in order to use them.
While Cloudflare Tunnel can protect your machine from direct attacks, it doesn’t magically fix security flaws in your shared service. A vulnerable application is a vulnerable application.
If you need greater access control, Cloudflare Access is fairly easy to set up on services using Cloudflare Tunnel.