Access your servers securely through Cloudflare’s Zero Trust network without exposing SSH ports or setting up VPNs.
Overview
Cloudflare Tunnel (formerly Argo Tunnel) provides secure remote access to your servers without opening firewall ports or exposing SSH to the internet. It creates an encrypted tunnel between your server and Cloudflare’s network, accessible only via Cloudflare Access authentication.
Benefits:
- No port forwarding required
- No public IP needed
- Built-in DDoS protection
- Cloudflare Access authentication
- Short-lived certificates for enhanced security
Prerequisites
- Cloudflare account (free tier works)
- Domain configured on Cloudflare
- Server with Cloudflare Access configured for SSH
- Linux or macOS client (Windows with WSL2 also works)
Quick Start: One-Liner Setup
For Linux clients, use this automated setup script:
bash <(curl -sfL https://gist.githubusercontent.com/n0k0m3/89ffc6a463a007d79fc4b234c58bf77a/raw/280291bb2edb2f271914838e07cc9af81c3567b8/setup-cf-tunnel.sh)
Prompts:
- Enter the domain name/host name of the tunnel:
server.example.com - Enter the username for the server:
your_username
Example output:
Enter the domain name/host name of the tunnel: subdomain.example.com
Enter the username for the server: your_username
Installing cloudflared, input sudo password when asked...
Generating ssh config for the tunnel...
Setting up done, use "ssh your_username@subdomain.example.com" to login
Manual Setup: Linux
Step 1: Install cloudflared
curl -sfL https://gist.githubusercontent.com/n0k0m3/49b26f4359a70d2f36e5a263b3dd5f24/raw/037e5f38fd027012bb0aa5f12d1d6fb2bdd59ca8/install-cloudflared.sh | sh
Or manual install:
# Debian/Ubuntu
wget -q https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared-linux-amd64.deb
# Arch Linux
yay -S cloudflared
# Other distributions (manual)
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64
chmod +x cloudflared-linux-amd64
sudo mv cloudflared-linux-amd64 /usr/local/bin/cloudflared
Step 2: Generate SSH Config
Replace <hostname> with your server’s domain:
cloudflared access ssh-config --hostname <hostname> --short-lived-cert
Example command:
cloudflared access ssh-config --hostname server.example.com --short-lived-cert
Sample output:
Host server.example.com
ProxyCommand bash -c '/usr/bin/cloudflared access ssh-gen --hostname %h; ssh -tt %r@cfpipe-server.example.com >&2 <&1'
Host cfpipe-server.example.com
HostName server.example.com
ProxyCommand /usr/bin/cloudflared access ssh --hostname %h
IdentityFile ~/.cloudflared/server.example.com-cf_key
CertificateFile ~/.cloudflared/server.example.com-cf_key-cert.pub
Step 3: Add Config to SSH
Copy the generated output to ~/.ssh/config:
cloudflared access ssh-config --hostname server.example.com --short-lived-cert >> ~/.ssh/config
Or manually edit:
nano ~/.ssh/config
# Paste the generated config
Step 4: Connect
ssh your_username@server.example.com
What happens:
cloudflaredrequests a short-lived certificate from Cloudflare Access- Your browser opens for authentication (first time only)
- After auth, a temporary SSH certificate is generated
- SSH connection is established through the Cloudflare tunnel
Manual Setup: Windows
Recommendation: Use WSL2 and follow the Linux instructions above for the best experience.
If you must use native Windows:
Step 1: Download cloudflared
Download from GitHub Releases:
Place in a permanent location (e.g., C:\Program Files\cloudflared\)
Step 2: Configure SSH
Add to C:\Users\<username>\.ssh\config:
Host cfpipe-<hostname>
HostName <hostname>
ProxyCommand C:\path\to\cloudflared.exe access ssh --hostname <hostname>
IdentityFile "C:\Users\<username>\.cloudflared\<hostname>-cf_key"
CertificateFile "C:\Users\<username>\.cloudflared\<hostname>-cf_key-cert.pub"
Replace:
<hostname>with your server domain (e.g.,server.example.com)C:\path\to\cloudflared.exewith actual path to cloudflared
Step 3: Connect
cmd /c "C:\path\to\cloudflared.exe access ssh-gen --hostname <hostname> && ssh -tt <username>@cfpipe-<hostname>"
Bonus: Setting Static IP on Server
If your server needs a static IP instead of DHCP, configure with netplan.
Find Current Network Info
# Find current IP and interface
ip a
# Find gateway
ip r
Configure Static IP
Edit netplan configuration:
sudo nano /etc/netplan/00-installer-config.yaml
Example configuration:
network:
ethernets:
eth0: # Replace with your interface name
dhcp4: no
addresses:
- 192.168.1.100/24 # Replace with desired static IP
routes:
- to: default
via: 192.168.1.1 # Replace with your gateway
nameservers:
addresses: [1.1.1.1, 1.0.0.1] # Cloudflare DNS
version: 2
Apply changes:
sudo netplan apply
Revert to DHCP:
network:
ethernets:
eth0:
dhcp4: true
version: 2
Troubleshooting
Issue: Browser doesn’t open for authentication
Cause: Headless server or SSH session without display
Fix: Copy the authentication URL and open it in a browser on your local machine:
Please complete authentication in your browser at:
https://example.cloudflareaccess.com/cdn-cgi/access/login/...
Issue: Certificate expired
Symptoms: SSH fails with “permission denied” after previously working
Cause: Short-lived certificates expire (typically after 24 hours)
Fix: Reconnect - cloudflared will automatically request a new certificate:
ssh your_username@server.example.com
Issue: cloudflared not found
Cause: Binary not in PATH
Fix for Linux:
# Check if installed
which cloudflared
# If not in PATH, add to ~/.bashrc or ~/.zshrc
export PATH="$PATH:/usr/local/bin"
source ~/.bashrc
Fix for Windows: Use full path to cloudflared.exe in SSH config
Issue: Connection timeout
Possible causes:
- Cloudflare Tunnel not configured on server
- Server
cloudflareddaemon not running - Cloudflare Access policy blocking connection
Check server-side:
# On the server
sudo systemctl status cloudflared
sudo journalctl -u cloudflared -f
Advanced: Multiple Servers
Add multiple servers to ~/.ssh/config:
# Server 1
Host server1.example.com
ProxyCommand bash -c '/usr/bin/cloudflared access ssh-gen --hostname %h; ssh -tt %r@cfpipe-server1.example.com >&2 <&1'
Host cfpipe-server1.example.com
HostName server1.example.com
ProxyCommand /usr/bin/cloudflared access ssh --hostname %h
IdentityFile ~/.cloudflared/server1.example.com-cf_key
CertificateFile ~/.cloudflared/server1.example.com-cf_key-cert.pub
# Server 2
Host server2.example.com
ProxyCommand bash -c '/usr/bin/cloudflared access ssh-gen --hostname %h; ssh -tt %r@cfpipe-server2.example.com >&2 <&1'
Host cfpipe-server2.example.com
HostName server2.example.com
ProxyCommand /usr/bin/cloudflared access ssh --hostname %h
IdentityFile ~/.cloudflared/server2.example.com-cf_key
CertificateFile ~/.cloudflared/server2.example.com-cf_key-cert.pub
Connect to any server:
ssh user@server1.example.com
ssh user@server2.example.com
Security Benefits
- No exposed SSH ports - Server SSH port doesn’t need to be publicly accessible
- Authentication via Cloudflare Access - Add Google Workspace, GitHub, or other SSO providers
- Short-lived certificates - Certificates expire automatically, limiting exposure window
- Audit logging - Cloudflare Access logs all authentication attempts
- DDoS protection - Cloudflare’s network protects against DDoS attacks
References
Created: 2025-12-02 Tested On: Ubuntu 22.04+, Arch Linux, macOS, Windows 11 (WSL2)