How to restrict SSH access to Cloudflare Tunnel only?

What is the name of the domain?

What is the issue you’re encountering

I want to only allow SSH access to my Vultr server through Cloudflare Tunnel, but the only way to allow access is to allowlist my client IP address in the firewall

What steps have you taken to resolve the issue?

Hi there, I am having an issue with securing SSH to my Vultr server. I have nginx running on the server, which is currently just displaying a test HTML page. I have restricted access to the site to only allow Cloudflare traffic through the Vultr firewall web interface, and this works as expected. Cloudflare is my DNS provider and the site can only be accessed by going to the root domain name, the actual server IP blocks non-Cloudflare traffic.

I wanted to use Cloudflare Tunnel to allow SSH to the server. I created a tunnel in the dashboard (so, remotely-managed?) and installed the connector on my Debian server, and verified that the system service was running. The public hostname is set as using “ssh.myexampledomain.com”, with the service type as SSH and URL as localhost:22. I also setup an Access Application and Group so that I could enable web rendering and only allow my admin email. While the web rendering portal opens, I get an error and cannot access SSH on my server: “Unable to connect to origin. Please confirm that the tunnel is set up correctly and the origin is healthy.”

The only workaround I have found so far is to allowlist my client IP address in the Vultr firewall for SSH, and change the public hostname of my tunnel from localhost to the server IP address, even though the Tunnel is running as a system service on the server. This allows me to use SSH by authenticating in the browser rendered terminal, as I want. However, an IP allowlist isn’t ideal for my needs since I use a commercial VPN. Plus, since my IP address is allowlisted for SSH, I can just connect to the server directly by IP address and skip Cloudflare Tunnel altogether, which makes the tunnel seem pointless.

I think I am doing something wrong, since the documentation I have found so far makes no mention of needing to create an inbound firewall rule to access the tunnel, yet that is the only way I have gotten this to work so far. I was wondering if anyone has any idea of where I went wrong?

To summarize, this is what I did:
1: Created web server and restrict inbound access to only allow Cloudflare traffic (with exception of SSH which allows both Cloudflare and my client IP address)
2: Created Cloudflare Tunnel online in the Zero Access dashboard
2.1: Set a public hostname to use “ssh.” subdomain (looks like CNAME was automatically created?)
2.2: Set the service as ssh://localhost:22
3: Installed/ran cloudflared connector on Debian server
4: Configured access group and self-hosted application for access to the “ssh.” subdomain
5: Unable to connect to server via SSH

To somewhat resolve the issue:
1: Changed Cloudflare Tunnel service to ssh://:22
2: Make sure SSH traffic from my client IP address is allowed through firewall
3: Able to connect to server via Tunnel and regular SSH, but I want to only allow Tunnel SSH traffic

You do not mention installing Cloudflared on the client anywhere - did you do that?

1 Like

Yes, I installed cloudflared on my client device. I didn’t think it was relevant since I am mostly interested in using the browser rendered terminal, but the problems were the same trying from client terminal: can’t connect by SSH when the public hostname service is set as localhost

Ok, I misread part of your initial post.

Is the SSH service listening on localhost? It sounds like your SSHD is only listening on your external IP address.

Reinstall of cloudflared on the server plus recreating the tunnel in the dashboard seems to have fixed the issue I was having.

I did decide to check and my /etc/ssh/sshd_config doesn’t have any ListenAddress set, nor did I ever change it, so I don’t think that should have been the issue. In fact, I followed the exact same instructions as the first time around, so I must have missed something or followed the steps incorrectly at one point.