In the past few months, I have been interested in making a small home lab, trying out some self-hosted services on my Raspberry Pi 4, and occasionally hosting some of my projects. Some of the most popular self-hosted applications that I use are:

  • Nextcloud - Alternative to Cloud Storage Services
  • Jellyfin - A Home Media Server with awesome features
  • A Visual Studio Code Server

But to do all of this and access my applications remotely, I need

  • A public IP address
  • A server in the cloud or at home

Using a Public IP address is very risky. Without a good network and firewall setup, I could expose my home network to malicious hackers and make my home network compromised and vulnerable. This is not a safe option.

How about renting a VPS from an online Cloud Provider? that could be an option, but to host Nextcloud and Jellyfin Instances, which have high storage and RAM requirements, this gets expensive really quick, not to mention that the basic servers don’t have enough computer power to transcode the video files on the fly. Paying large sums of money for Hobby and Fun Projects doesn’t sound very good, does it?

Many of the Homelabs that are generally set up are based on an old retired computer or a Raspberry Pi, which are dedicated to running such instances; but we need a public IP to access the services hosted on our local network remotely.

Sometimes we would like to expose just one service or share access to an application with our friend or colleague for demo and testing purposes. But… can we do it?

Cloudflare Tunnels makes it possible to expose our applications in our local network to be connected from a public DNS record linked to our domain.

How do they work?

Cloudflare tunnels work by installing an application / Cloudflare service called Cloudflared; this service creates a reverse tunnel that communicates with the Cloudflare Servers and connects with the nearest Cloudflare Datacenter. This establishes a secure connection between Cloudflare and our local machine. Now our device can communicate with Cloudflare, let’s create a tunnel and expose a test application to the public internet. This image explains how tunnels work.

Cloudflare Tunnels

How to use CloudFlare Tunnels

We can use tunnels to direct HTTP RDP SSH and SMB traffic from our applications via the tunnel; this is helpful when you need to have remote access to your system and expose a SAMBA Share, which is some of the common use cases. In this blog post, we are going to expose an NGINX server for demo purposes

To follow along with me, you need to do the following.

  • A domain registered to you or have access to
  • Change Nameservers from your domain registrar to Cloudflare
  • In Zero Trust Portal, verify your account using a valid credit card

Cloudflared Install and Setup

Cloudflared can be installed in two ways

  • Via the Dashboard
  • Via the Command Line

The dashboard method is easy, we create a tunnel in the portal, and the website provides us with the commands to install and set up the Cloudflared service on our machine; if we set up a tunnel via the CLI, it can be configured through CLI only, and not via the Dashboard, we can migrate the CLI config to the Dashboard if we wish to.

Installing Cloudflared

Cloudflared is available for the following Operating Systems and Platforms.

  • Linux
  • Docker
  • Windows
  • MacOS

For Linux, the following Architectures are supported.

  • amd64/x86-64
  • x86 (32 Bit)
  • ARM (32 Bit)
  • ARM64

Use the following command to install Cloudflared. replace $ARCH with the arch of your current system

wget -q https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-{$ARCH}.deb && dpkg -i cloudflared-linux-{$ARCH}.deb

Authenticate Cloudflared

Cloudflared is now installed and must be linked with our account by authenticating our installation. Ensure you are logged into your Cloudflare account in your default browser.

cloudflared tunnel login

Authorize the domain you wish to use in the browser for tunnels; after the login, the credentials are installed at /home/kalyan/.cloudflared/

The output should be similar to

A browser window should have opened at the following URL:

https://dash.cloudflare.com/argotunnel?aud=&callback=https%3A%2F%2Flogin.cloudflareaccess.org%<STRING>

If the browser failed to open, please visit the URL above directly in your browser.
2023-05-20T13:55:25Z INF Waiting for login...
You have successfully logged in.
If you wish to copy your credentials to a server, they have been saved to:
/home/kalyan/.cloudflared/cert.pem

Create a Test Application (NGINX)

To verify that the tunnel can route our local application traffic, we can use a simple web server like NGINX, as it has a default webpage on page load. Specifically, a docker container will be created with an NGINX image, and ports will be mapped on the host machine to the docker container.

To install docker if not already installed.

sudo apt update && sudo apt install docker.io

To create an NGINX docker container

docker run --name tunnel-nginx -p 5000:80 --detach nginx:latest

This command will pull the nginx:latest image if it does not exist locally, names the container nginx-tunnel, maps the host port 5000 to port 80 of the container, and runs in detach mode (background).

The output should be similar to

Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
9e3ea8720c6d: Already exists
bf36b6466679: Pull complete
15a97cf85bb8: Pull complete
9c2d6be5a61d: Pull complete
6b7e4a5c7c7a: Pull complete
8db4caa19df8: Pull complete
Digest: sha256:480868e8c8c797794257e2abd88d0f9a8809b2fe956cbfbc05dcc0bca1f7cd43
Status: Downloaded newer image for nginx:latest
f1dcf6b38cdef4a4bda91ef6eb99f9223c7c7b7cd3e0a431ffcd17601be5f425

Check for running docker containers using the command docker ps or `docker ps -a’ for all running and stopped containers.

CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS                                   NAMES
f1dcf6b38cde   nginx:latest   "/docker-entrypoint.…"   2 minutes ago   Up 2 minutes   0.0.0.0:5000->80/tcp, :::5000->80/tcp   nginx-tunnel

Let’s verify if we can access the nginx server from http://localhost:5000

We now have a simple web server running at port 5000; let’s route the traffic from this application using tunnels.

Tunnel Creation and Configuration

Let’s create our first tunnel using the following command.

cloudflared tunnel create nginx-tunnel

The output should be similar to

Tunnel credentials written to /home/kalyan/.cloudflared/25848586-e508-42f8-be78-84e13328fa46.json. cloudflared chose this file based on where your origin certificate was found. Keep this file secret. To revoke these credentials, delete the tunnel.

Created tunnel nginx-tunnel with id 25848586-e508-42f8-be78-84e13328fa46

Let’s configure the tunnel by creating a configuration file nginx-tunnel.yml at /home/$USER/.cloudflared/ directory and add the following lines, replace <UUID> with from the previous command output, replace <domain> with your domain.

---
tunnel: {UUID}
credentials-file: /home/{USER}/.cloudflared/{UUID}.json
ingress:
  - hostname: tunnel.<domain>
    service: http://localhost:5000
  - service: http_status:404

Our tunnel is now created, now we need a public DNS record that can point to our application through the tunnel; this can be done via the CLI where Cloudflare automatically makes a DNS record for us and points to towards a cfargotunnel.com subdomain created for our tunnel.

cloudflared tunnel route dns nginx-tunnel tunnel.<domain>

Our tunnel is now ready and configured. Let’s run the tunnel!!

Run the tunnel

Cloudflared needs to know the config that has to be used; our config is located at /home/{USER}/.cloudflared/{tunnel-name}.yaml

Let’s pass this path to the tunnel by using the flag –config

cloudflared tunnel --config /home/$USER/.cloudflared/{tunnel-name}.yaml

The Nginx server at tunnel.<domain> should now be accessible from the public internet; let’s verify if we can connect to our local Nginx server via Cloudflare Tunnels.

It works, we were able to send a request to our nginx server over the public internet through Cloudflare tunnels.

Conclusion

We successfully exposed our simple web application to the internet using Cloudflare tunnels securely via a public DNS record. Our use case of tunnels was very basic; Cloudflare tunnels have many advanced uses; you can also expose a private network using Cloudflare WARP and Cloudflare Access using Tunnels. You are now ready to host your applications and access them remotely. I hope this post helped make in making your first Cloudflare Tunnel

Visit Cloudflare Zero Trust to learn more about Cloudflare Tunnel.

Thank you for reading

~ Kalyan Mudumby