Featured image of post Access Personal Website from Internet (3): Using Cloudflare Tunnel for Reverse Proxy

Access Personal Website from Internet (3): Using Cloudflare Tunnel for Reverse Proxy

This article introduces how to use Cloudflare Tunnel to access personal websites and services from the internet, providing a solution that does not rely on a public IP address or open ports.

Motivation

In order to access the websites and services I have set up on my personal server from the internet, my previous approach was:

  1. Use a Dynamic DNS (DDNS) service to bind my public IP address to a domain name.
  2. Then configure Nginx as a reverse proxy to point the domain name to the services on my server.
  3. Finally, use acme to obtain SSL certificates for HTTPS access.

Later, to containerize the reverse proxy, I switched to Traefik, which combined steps 2 and 3 into a more convenient solution. You can refer to my previous articles for these solutions:

These solutions were already quite effective, but they still relied on the stability of the public IP address and the openness of ports. If deployed in a corporate or school network environment, you might encounter issues with unstable IP addresses or blocked ports. For a long time, I thought this problem was difficult to solve.

Recently, I finally discovered a better solution: using Cloudflare Tunnel. This solution allows you to access your services from the internet without a public IP address, even if ports are blocked or your network is restricted by a firewall.

Prerequisites

Basic Concepts of Cloudflare Tunnel

Introduction

Cloudflare Tunnel (formerly known as Argo Tunnel) is a service provided by Cloudflare that allows you to expose your services to the internet without a public IP address. It works by running a lightweight proxy program on your server that forwards your services through Cloudflare’s network, enabling access from the internet.

How It Works

The working principle of Cloudflare Tunnel can be found in the official documentation. In simple terms, as long as your computer can access Cloudflare’s DNS servers, you can establish a tunnel from Cloudflare to your computer. After configuring your domain to resolve to this tunnel, Cloudflare will forward all requests for your domain through this tunnel to the computer connected to it. Similarly, your services on the computer can send responses back through this tunnel. This allows you to access your services from the internet without needing a public IP address or open ports, regardless of whether your network is restricted by a firewall.

When a user accesses a service on the internet, the process is as follows:

Cloudflare Tunnel Working Principle

  1. The user enters your domain in their browser, which resolves to Cloudflare’s DNS servers.
  2. Cloudflare’s servers forward the request to the Cloudflare Tunnel you established. This tunnel is maintained by the cloudflared program running on your computer.
  3. cloudflared forwards the request to your configured reverse proxy service (such as Traefik or Nginx).
  4. The reverse proxy service forwards the request to the specific service running on your computer (such as NextCloud, Jellyfin, etc.).
  5. The specific service processes the request and sends the response back through the reverse process to the user.

Using Cloudflare Tunnel

Enabling Cloudflare Zero Trust Service

Cloudflare Tunnel is part of the Cloudflare Zero Trust service, so you need to enable Cloudflare Zero Trust first.

Log in to your Cloudflare account, find “Zero Trust” in the left sidebar, and click to enter.

The first time you enable it, you will be prompted to choose a plan. The free plan is sufficient for personal users. Fill in your credit card information to enable it.

Creating a Tunnel

In the Zero Trust page, expand the left sidebar to find the Networks option, then click on Tunnels to open the Tunnels management page:

Cloudflare Tunnels

You can click the Create a tunnel button to create a new Tunnel, but it is not recommended to create it this way because you will need to transfer the configuration to your server later. Instead, we will create it directly on the server. The steps are as follows:

1. Install cloudflared on the Server

First, we need to install the cloudflared program on the server. cloudflared is a command-line tool provided by Cloudflare for creating and managing Cloudflare Tunnels. For specific installation methods, refer to the official documentation. Here are the basic installation commands:

1
2
3
4
5
6
7
8
# For Debian/Ubuntu
sudo apt-get install cloudflared

# For CentOS/RHEL
sudo yum install cloudflared

# For macOS
brew install cloudflared

2. Create a Tunnel on the Server

  1. After installing cloudflared, we first need to log in to your Cloudflare account on the server by running:

    1
    
    cloudflared tunnel login
    

    This will output a link that you need to copy and open in your browser to log in to your Cloudflare account. After logging in, you will be prompted to select the domain you want to bind to the Tunnel.

  2. Then, run the following command on the server to create a new Tunnel:

    1
    
    cloudflared tunnel create my-tunnel
    

    Replace my-tunnel with the name you want to give to your Tunnel. After running this command, it will output a Tunnel ID, which you should note down.

    At the same time, cloudflared will create a JSON file on your server that records this Tunnel, usually located in the ~/.cloudflared/ directory, with the filename being the Tunnel ID. This file is important as it contains the credentials needed to connect to this Tunnel.

  3. You can log in to the Cloudflare web interface to check if the Tunnel was created successfully. In the Zero Trust -> Networks -> Tunnels page, you should see the Tunnel you just created:

    Cloudflare Tunnel

    Note that at this point, we have only created the Tunnel but not connected it, so its status is inactive.

3. Connect the Tunnel

Here, I will explain how to connect the Tunnel using both Docker and K3s as examples.

Docker
  1. Prerequisites:

    This assumes that you have already installed Docker and Docker Compose, are using Traefik as a reverse proxy, and have created a shared network for all containers named traefik-net. For the specific process, refer to “Access Personal Website from Internet (2) - Traefik Reverse Proxy Configuration”.

  2. Create a cloudflared Container

    Create a new directory for the cloudflared configuration files:

    1
    
    mkdir -p ~/cloudflared
    

    Then create a Docker Compose file docker-compose.yml in this directory with the following content:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    version: '3.8'
    
    services:
      cloudflared:
        image: cloudflare/cloudflared:latest
        command: tunnel run my-tunnel
        restart: unless-stopped
        networks:
          - traefik-net
        volumes:
          - ~/.cloudflared:/etc/cloudflared
    
    networks:
      traefik-net:
        external: true
    

    Replace my-tunnel with the name of your Tunnel. This configuration will create a cloudflared container that runs your Tunnel and connects it to the traefik-net network.

  3. Start the cloudflared Container

    In the ~/cloudflared directory, run the following command to start the cloudflared container:

    1
    
    docker-compose up -d
    

    At this point, you can go back to the Zero Trust -> Networks -> Tunnels page and see that the status of the Tunnel has changed to active, indicating that the Tunnel is now connected:

    Cloudflare Tunnel Active

  4. Configure DNS Records

    Now that your Tunnel is active, you need to configure your DNS records to point to the Tunnel. Go back to the Cloudflare dashboard, and in the Zero Trust -> Networks -> Tunnels page, click on the Tunnel you just created.

    In the Tunnel details page, you will see a section for DNS. Here, you can add a new DNS record that points to your Tunnel. For example, you can create a CNAME record for myapp.example.com that points to my-tunnel.cloudflare.com.

    After adding the DNS record, it may take a few minutes for the changes to propagate.

  5. Test Access

    Now you can access your service through the domain name you configured. For example, if you set up a service at myapp.example.com, you can open this URL in your browser to access it.

K3s
  1. Prerequisites:

    This assumes that you have already installed K3s and are using Traefik as the Ingress Controller. For the specific process, refer to “Homelab (1): Building a Home Cluster with Kubernetes (K8s) or K3s”.

  2. Convert Tunnel Credentials to Secret

    When you created the Tunnel, Cloudflare generated a credentials file saved at ~/.cloudflared/<Tunnel ID>.json. We need to convert this file into a Kubernetes Secret.

    Run the following command on your server:

    1
    
    kubectl create secret generic cloudflared-credentials --from-file=credentials.json=<User Home Path>/.cloudflared/<Tunnel ID>.json
    

    Replace <User Home Path> with your user home directory path and <Tunnel ID> with the ID of the Tunnel you created earlier.

  3. Create cloudflared Deployment and Service

    The required manifest file is as follows:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: cloudflared
    spec:
      selector:
        matchLabels:
          app: cloudflared
      replicas: 1
      template:
        metadata:
          labels:
            app: cloudflared
        spec:
          containers:
          - name: cloudflared
            image: cloudflare/cloudflared:2025.5.0
            args:
            - tunnel
            - --config
            - /etc/cloudflared/config/config.yaml
            - run
            livenessProbe:
              httpGet:
                path: /ready
                port: 2000
              failureThreshold: 1
              initialDelaySeconds: 10
              periodSeconds: 10
            volumeMounts:
            - name: config
              mountPath: /etc/cloudflared/config
              readOnly: true
            - name: creds
              mountPath: /etc/cloudflared/creds
              readOnly: true
          volumes:
          - name: creds
            secret:
              secretName: li-tunnel-credentials
          - name: config
            configMap:
              name: cloudflared
              items:
              - key: config.yaml
                path: config.yaml
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: cloudflared
    data:
      config.yaml: |
        tunnel: li-tunnel
        credentials-file: /etc/cloudflared/creds/credentials.json
        metrics: 0.0.0.0:2000
        no-autoupdate: true
        ingress:
        - hostname: "*.jinli.li"
          service: http://traefik.kube-system.svc.cluster.local:80
        - service: http_status:404    
    

    The configurations in this manifest file are similar to those in the Docker Compose file, so I won’t elaborate on them here.

  4. Deploy cloudflared

    Save the above manifest file as cloudflared.yaml, and then run the following command on your server to deploy cloudflared:

    1
    
    kubectl apply -f cloudflared.yaml
    

    At this point, you can go to the Zero Trust -> Networks -> Tunnels page and see that the status of the Tunnel has changed to active, indicating that the Tunnel is now connected successfully.

    If it doesn’t show as active, you need to check whether cloudflared was deployed successfully.

  5. Configure DNS Records and Test Access

    These two steps are the same as in the Docker method (steps 3 and 4 above).

comments powered by Disqus