Recently, when I needed to make an internal API of a production ERP accessible from the outside, the idea of opening a port in the firewall made me uncomfortable. Exposing a service to the internet using traditional methods typically requires opening specific ports in the firewall and configuring a reverse proxy, which increases the potential attack surface and leaves you directly vulnerable to threats like DDoS. This is precisely where Cloudflare Tunnel eliminates these problems by offering an outbound-only solution for securely publishing self-hosted services.
Cloudflare Tunnel creates an encrypted tunnel from your server to the Cloudflare network, allowing you to securely expose your services to the internet without opening any inbound ports. This keeps your server’s IP address hidden, protects it from direct attacks, and allows you to benefit from Cloudflare’s extensive security layers (DDoS protection, WAF, authentication). In this post, drawing from my own experiences, I will detail how we set up and configured Cloudflare Tunnel and the five fundamental steps involved in this process.
What is Cloudflare Tunnel and Why Should We Use It?
Cloudflare Tunnel is a Zero Trust service that establishes a persistent, encrypted connection from your server to the Cloudflare network via a lightweight agent called cloudflared running on your server. Unlike traditional approaches, you don’t need to open any inbound ports in your server’s firewall; all traffic is routed through this tunnel via Cloudflare’s global network.
This approach offers significant security advantages, especially for those publishing services on their home servers or internal infrastructure. Your server’s real IP address is hidden, you are protected from direct DDoS attacks or port scans, and you automatically benefit from additional Cloudflare security features like WAF (Web Application Firewall). When I chose this method to make a client’s internal application externally accessible without a VPN and without opening firewall ports, I was quite impressed by the simplicity of the setup and the security it provided.
graph TD; A["User"] --> B["Cloudflare Edge"]; B --> C["Cloudflare Tunnel"]; C --> D["cloudflared agent (on server)"]; D --> E["Self-Hosted Service"];
The diagram above illustrates the basic working principle of Cloudflare Tunnel. Requests from the user first reach Cloudflare’s global edge servers, from there they are forwarded via the secure tunnel to the cloudflared agent, which then finally delivers them to your local service. This flow optimizes performance and activates security layers.
How to Get Started with Cloudflare Tunnel Setup?
The first step to using Cloudflare Tunnel is to install the cloudflared agent on your server and connect it to your Cloudflare account. This agent is the critical component that creates the tunnel and routes incoming requests to the correct services. Since I generally work on Linux servers, I will provide installation steps based on Ubuntu/Debian-based systems, but cloudflared is supported on almost all popular operating systems.
First, you need to download the cloudflared binary from the official Cloudflare repository and install it on your system:
# First, add the Cloudflare GPG key
curl -fsSL https://pkg.cloudflare.com/cloudflare-req.gpg | sudo gpg --dearmor -o /usr/share/keyrings/cloudflare-archive-keyring.gpg
# Then, add the Cloudflare repository to the sources.list.d directory
echo "deb [signed-by=/usr/share/keyrings/cloudflare-archive-keyring.gpg] https://pkg.cloudflare.com/cloudflared $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/cloudflared.list
# Update the package list and install cloudflared
sudo apt update
sudo apt install cloudflared
Once the installation is complete, you need to authenticate cloudflared with your Cloudflare account. This process is done via a browser and downloads the necessary credentials to manage your tunnel.
cloudflared tunnel login
This command will provide you with a URL and ask you to open it in your browser to log in to your Cloudflare account. After a successful login, a certificate file named cert.pem will be created, and your cloudflared agent will be associated with your Cloudflare account.
How to Create a New Cloudflare Tunnel and Define Services?
After installing the cloudflared agent and authenticating it, you are now ready to create your first tunnel. Creating a tunnel essentially means defining a persistent connection point on the Cloudflare network and specifying which services will be published through this tunnel.
First, create your tunnel and give it a name:
cloudflared tunnel create my-erp-tunnel
This command will generate a unique UUID (Universally Unique Identifier) and an authentication key for the tunnel. Note down the UUID provided in the output, as this is the unique identifier for your tunnel.
Now we need to create a configuration file (config.yml) for this tunnel. This file defines which domain names the tunnel will be accessible through and which local services incoming requests to these domain names will be routed to. I generally prefer to create a configuration file in the /etc/cloudflared/ directory.
# /etc/cloudflared/config.yml
tunnel: <TUNNEL_UUID> # The UUID you got from the create command above
credentials-file: /root/.cloudflared/<TUNNEL_UUID>.json # Authentication file
ingress:
- hostname: erp.example.com
service: http://localhost:8000 # My local ERP API
- hostname: dashboard.example.com
service: http://localhost:3000 # Local admin panel
- service: http_status:404 # Return 404 for other undefined requests
In this config.yml file, you should replace <TUNNEL_UUID> with your tunnel’s UUID and <TUNNEL_UUID>.json with the name of your authentication file. The ingress section determines how incoming requests will be routed. Here, I defined that requests coming to erp.example.com will be routed to the service on port localhost:8000, and requests to dashboard.example.com will be routed to the service on port localhost:3000. The final service: http_status:404 rule acts as a fallback for requests that do not match any other rule.
After saving the configuration file, you need to create CNAME records for erp.example.com and dashboard.example.com in your Cloudflare DNS panel and point these records to your tunnel. These records should point as CNAME to the cfargotunnel.com address associated with your tunnel’s UUID (e.g., erp.example.com CNAME <TUNNEL_UUID>.cfargotunnel.com).
Finally, we need to run the cloudflared tunnel as a systemd service so that it automatically starts when the server reboots and runs continuously in the background.
# Create the systemd service file
sudo nano /etc/systemd/system/[email protected]
Edit the content as follows:
[Unit]
Description=Cloudflared Tunnel %i
After=network-online.target
[Service]
ExecStart=/usr/bin/cloudflared tunnel --config /etc/cloudflared/config.yml run %i
Restart=on-failure
RestartSec=5s
User=root # or another user
Group=root # or another group
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
NoNewPrivileges=yes
StandardOutput=journal
StandardError=journal
SyslogIdentifier=cloudflared-%i
[Install]
WantedBy=multi-user.target
After saving the service file, update systemd and start the service:
sudo systemctl daemon-reload
sudo systemctl enable [email protected]
sudo systemctl start [email protected]
You can check the tunnel’s status and logs with the command journalctl -u [email protected]. Once the tunnel starts successfully, you will be able to access your local services via the specified domain names. I had published the backend of my own side product’s financial calculators this way some time ago and saw how simple and secure the setup was.
Tunnel Configuration for SSH and Other TCP Services
Cloudflare Tunnel can be used not only for HTTP/S services but also for SSH, RDP, or any TCP service. This is particularly useful when you want to securely access your servers remotely. In the config.yml file, in addition to ingress rules, we can use the tunnel command for ssh.
For SSH access, we can update the config.yml file as follows:
# /etc/cloudflared/config.yml (continued)
# ... existing ingress rules ...
- service: ssh://localhost:22 # For SSH service
hostname: ssh.example.com
originRequest:
noTLSVerify: true # Local SSH service usually doesn't use TLS
Then, don’t forget to create a CNAME record for ssh.example.com in the Cloudflare panel. Afterwards, to use this tunnel from your SSH client, you can add a configuration like the following to your ~/.ssh/config file:
Host ssh.example.com
ProxyCommand /usr/local/bin/cloudflared access ssh --hostname %h
With this configuration, when you run the ssh ssh.example.com command, your SSH traffic will be securely routed through the Cloudflare Tunnel. This offers a great alternative to traditional VPN connections and extends Zero Trust principles to your SSH access.
What are the Security Benefits of Cloudflare Tunnel?
Using Cloudflare Tunnel provides a host of benefits that significantly enhance the security posture of your self-hosted services. These benefits create a layered defense mechanism that would be difficult or costly to achieve with traditional methods.
- No Inbound Ports, Reduced Attack Surface: Since no inbound ports are opened on your server, potential attackers cannot directly target your server’s IP address. Your server becomes much more secure against port scans, weak password SSH attempts, or unknown vulnerabilities. When I set up a similar structure to protect the backend API of my own Android spam blocker application, I experienced the peace of mind that comes from working on a server closed to the outside world.
- Origin IP Hiding: Since your services are published through Cloudflare, your server’s real IP address is not exposed to the internet. This makes targeted attacks and information gathering attempts more difficult.
- DDoS and Bot Protection: All traffic passes through the Cloudflare network, so you automatically benefit from Cloudflare’s extensive DDoS protection and bot management systems. This is vital for high-traffic applications or services with potential attack risks.
- Web Application Firewall (WAF): For HTTP/S traffic, Cloudflare WAF provides protection against common web attacks such as SQL injection and XSS. This helps to close potential security vulnerabilities in your application.
- Authentication and Authorization (Cloudflare Access): With Cloudflare Access, you can restrict access to services published through the tunnel on a per-user basis. For example, by integrating with Identity Providers (IdPs) like Google Workspace, Okta, or Azure AD, you can allow access only to specific users or groups. This is an excellent security layer for internal tools or admin panels. We have implemented such authentication mechanisms using JWT and OAuth2 patterns in multiple projects.
- Traffic Encryption: All traffic between the
cloudflaredagent and Cloudflare Edge is encrypted with TLS. This ensures the security of your data during transmission.
The combination of these benefits transforms Cloudflare Tunnel from just an access solution for self-hosted services into a cornerstone of a comprehensive security strategy.
What are the Challenges and Trade-offs When Using Cloudflare Tunnel?
While Cloudflare Tunnel offers many advantages, like any technology, it also has its unique challenges and trade-offs. By considering these points, you can make the right decision for your project.
- Vendor Lock-in: When you use Cloudflare Tunnel, you become tied to the Cloudflare ecosystem. Many components, from DNS management to tunnel configuration, become dependent on Cloudflare. This can make switching to a different provider difficult or incur additional costs in the long run. I generally prefer to use open-source and flexible solutions in infrastructure as much as possible, but the ease and security offered by Cloudflare sometimes make this “lock-in” risk worth taking.
- Performance Impact: Traffic traveling from your server to the Cloudflare network and then to the user adds an extra “hop” compared to a traditional direct connection. While this impact is negligible in most cases, it should be considered for applications requiring ultra-low latency. Thanks to Cloudflare’s extensive network, this latency is usually minimized, but it is still a factor.
- Reliability of the
cloudflaredAgent: Although thecloudflaredagent generally runs stably, it can stop unexpectedly due to resource limitations (CPU, memory) or network issues on your server. In one project, when thecloudflaredservice unexpectedly stopped, I realized once again how important it is to correctly configure thesystemdunit with parameters likeRestart=on-failureandRestartSec. There were even cases where it was OOM-killed, socgrouplimits might need to be adjusted. - Debugging Complexity: Troubleshooting can be a bit more complex compared to traditional setups. It can take time to pinpoint whether the error is in the tunnel itself, at the Cloudflare Edge, or in the backend service. Carefully examining
journalctloutputs and logs in the Cloudflare dashboard is critically important in this process. - Free Tier Limits: While Cloudflare’s free tier is sufficient for many users, there may be certain traffic or feature limits. For scenarios requiring more advanced security features (e.g., more comprehensive WAF rules) or higher bandwidth, upgrading to paid plans may be necessary.
Knowing these challenges and trade-offs helps you use Cloudflare Tunnel strategically. Like any tool, it provides the greatest benefit when used in the right scenario and with the right expectations.
How Do We Monitor and Manage the Tunnel Infrastructure?
Setting up a Cloudflare Tunnel is just the beginning; the real challenge is ensuring it runs stably and securely. Effectively monitoring and managing your tunnel infrastructure is vital for proactively detecting potential issues and preventing service outages.
-
Following
cloudflaredLogs: Thecloudflaredagent generates important logs while it’s running. These logs contain valuable information about the tunnel’s status, incoming requests, error messages, and connection problems. When running it as asystemdservice, we can easily follow the logs viajournalctl:journalctl -u [email protected] -fThis command shows the live log stream of the tunnel and allows us to intervene quickly in case of any anomaly. Last month, I saw from
journalctloutputs thatcloudflaredwasOOM-killedon a VPS, and then I solved the problem by adjusting thecgroupmemory limits. -
Monitoring via Cloudflare Dashboard: The Cloudflare panel provides a central interface for managing your tunnels and monitoring their status. From here, you can see if your tunnels are active, review traffic statistics, and manage Access policies. The dashboard is particularly useful for providing an overview when you have multiple tunnels.
-
Automatic Update Strategies: The
cloudflaredagent is updated from time to time with new features or security patches. Regularly applying these updates improves both the performance and security of your tunnel.cloudflaredversions installed using package managers likeaptoryumcan be included in the system’s normal update flow. However, sometimes manual control and testing, especially in production environments, is a safer approach.sudo apt update && sudo apt upgrade cloudflared -
Multiple Agents for High Availability: To reduce the risk of a single
cloudflaredagent failing for critical services, you can run multiplecloudflaredagents on different servers for the same tunnel. Cloudflare automatically load balances between these agents as long as the tunnel UUID is the same. This ensures that your service remains accessible even if one agent goes offline. Using this structure for the ERP’s API in a production environment provided us with great peace of mind regarding service continuity. -
Health Checks and Alerts: To monitor the health of services published through the tunnel and receive alerts for potential issues, you can integrate Cloudflare’s health check features or external monitoring tools like Prometheus/Grafana. This informs you if the backend service becomes inaccessible, even if the tunnel itself is running smoothly.
These management and monitoring practices ensure that your Cloudflare Tunnel setup not only works but is also reliable and sustainable.
Conclusion
Cloudflare Tunnel offers a powerful and practical solution for anyone looking to securely expose self-hosted services to the internet. It eliminates the security risks associated with traditional port-opening methods while allowing you to benefit from Cloudflare’s extensive security and performance features. As I’ve seen from my own experiences, Cloudflare Tunnel becomes an indispensable tool, especially for implementing Zero Trust principles, reducing the attack surface, and simplifying remote access processes.
The simplicity of its setup, flexible configuration options, and the layered security benefits it provides make it attractive for both small personal projects and large enterprise applications. Of course, like any technology, it has its trade-offs and management requirements; however, when these steps are correctly applied, you can significantly enhance the security of your self-hosted infrastructure and lighten your operational load. The next step would be to further restrict access to services published through these tunnels with Cloudflare Access and add an authentication layer.