I’ve helped several people investigate VPS breaches, and almost every time the root cause was the same: their web service was directly exposed to the public internet with no real protection. Tools like AI Agents are especially risky because they can execute code, call APIs, and access files. If someone unauthorized gets in, the damage can be serious.
Cloudflare Tunnel solves this problem neatly. Instead of opening ports on your VPS, the server actively creates an outbound connection to Cloudflare. Users then access your service through your domain. No inbound ports need to be exposed at all.
How It Works
Traditional way: User → Your Server IP:Port → Service
With Cloudflare Tunnel: User → Cloudflare → Encrypted Tunnel → Your Local Service
Your VPS firewall can block all inbound traffic except SSH. Your real server IP stays hidden, and scanners won’t find any open ports.
Prerequisites
Before starting, make sure of three things:
- Hermes (or whatever service you want to expose) is already installed and running on the VPS
- You have a domain name added to Cloudflare (DNS managed by Cloudflare)
- You have a Cloudflare account
Assuming Hermes is running locally at http://localhost:3000, we’ll expose it safely at https://ai.yourdomain.com.
Setup Steps
Install cloudflared:
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared-linux-amd64.deb
cloudflared --version
Log in to your Cloudflare account (it will open a browser link for authorization):
cloudflared tunnel login
Create a new tunnel (name can be anything):
cloudflared tunnel create hermes-tunnel
This will give you a Tunnel ID and create a JSON credential file in ~/.cloudflared/. Note the file path.
Route your subdomain to the tunnel:
cloudflared tunnel route dns hermes-tunnel ai.yourdomain.com
Create the configuration file:
nano ~/.cloudflared/config.yml
Add the following content (replace the credentials path with your actual file):
tunnel: hermes-tunnel
credentials-file: /root/.cloudflared/your-tunnel-id.json
ingress:
- hostname: ai.yourdomain.com
service: http://localhost:3000
- service: http_status:404
Validate the config:
cloudflared tunnel ingress validate
Test the tunnel:
cloudflared tunnel run hermes-tunnel
Open https://ai.yourdomain.com in your browser. If you see the Hermes interface, it’s working.
Set It to Start Automatically
Once everything is working, set it up as a systemd service so it runs in the background and survives reboots:
sudo cloudflared service install
sudo systemctl enable cloudflared
sudo systemctl start cloudflared
sudo systemctl status cloudflared
Security Hardening (Do This!)
After the tunnel is running, lock down your VPS by blocking all unnecessary inbound ports:
sudo ufw default deny incoming
sudo ufw allow 22/tcp # Keep SSH open
sudo ufw enable
sudo ufw status
Now only SSH is exposed. Hermes’ port 3000 is completely invisible from the outside — scanners will find nothing.
For even stronger protection, enable Cloudflare Zero Trust. Go to your Cloudflare dashboard → Zero Trust → Access → Applications, add your domain ai.yourdomain.com, and create an access policy. You can require login via Google, GitHub, or email. Only authorized people can reach the page.
With this setup (Tunnel + Zero Trust + UFW blocking everything except SSH), even if someone knows your domain, they can’t access anything without passing authentication, and your real VPS IP stays hidden.
Common Issues & Troubleshooting
Domain times out after starting the tunnel:
Check that the local address and port in config.yml are correct. Verify Hermes is actually running:
curl http://localhost:3000
If this returns content, the problem is with the tunnel config. If it refuses to connect, Hermes isn’t running properly.
View logs:
sudo journalctl -u cloudflared -f
Credential file not found:
Double-check the path in config.yml matches the actual file location:
ls ~/.cloudflared/
The JSON file should be there, named after your Tunnel ID.
Performance Impact
Cloudflare Tunnel adds roughly 20–50ms of extra latency because requests go through Cloudflare’s nearest edge node first. For dashboard access or API calls, this delay is barely noticeable.
The basic Tunnel feature is completely free, and Zero Trust has a generous free tier — more than enough for personal use.
This combination (Cloudflare Tunnel + Zero Trust + strict UFW rules) is currently one of the best and simplest ways to securely self-host AI tools in 2026. It’s much safer than opening ports with Basic Auth, and once set up, it requires almost no maintenance.