NX

How to SSH to a Remote Host Using Cloudflared Access

Tech Minute x/techminute ·
How to SSH to a Remote Host Using Cloudflared Access

How to SSH to a Remote Host Using Cloudflared Access

Cloudflare Access lets you protect internal services with Zero Trust policies. One of the most useful scenarios is SSH'ing into a server without exposing its real IP address to the public internet. In this guide, you'll learn how to set up a secure SSH connection via Cloudflare Tunnel and Access, all while using a friendly alias so you never need to remember the actual hostname.

Why Use Cloudflare Access for SSH?

  • No public IP – the server stays hidden behind Cloudflare's edge.
  • Identity‑aware proxy – only authenticated users (e.g., email‑based rules) reach the SSH port.
  • No open firewall ports – inbound SSH (port 22) can be closed entirely on the origin. We'll use cloudflared (Cloudflare's tunnel client) as an SSH ProxyCommand so that every connection is transparently redirected through the tunnel.

Prerequisites

  • Cloudflare account with a domain (e.g., example.com).
  • A server running SSH (any OS). It can be behind NAT or a firewall.
  • cloudflared installed on your local machine (the one you're connecting from).
  • An Access application configured for the SSH hostname (we'll cover this briefly).

Step 1 – Install cloudflared

Install the latest cloudflared client on your workstation. Below are the quick methods for Windows, macOS, and Linux:

Windows

Use winget (if available) or download the executable from the official downloads page:

winget install --id Cloudflare.cloudflared

By default the binary lands in C:\Program Files (x86)\cloudflared\cloudflared.exe. Add that folder to your PATH so you can run cloudflared from any terminal. Test with:

cloudflared --version

macOS / Linux

brew install cloudflare/cloudflare/cloudflared
# or download the .deb/.rpm package, or use the static binary
cloudflared --version

Tip: The examples below assume cloudflared is in your PATH. If you're on Windows and haven't added it yet, substitute the full path: "C:\Program Files (x86)\cloudflared\cloudflared.exe" wherever you see cloudflared.


Step 2 – Set Up a Cloudflare Tunnel and Access App

Skip this if you already have a working tunnel and Access policy for SSH. Quick overview:

  1. Install cloudflared on the server and connect it as a tunnel.
  2. Create a public hostname that points to ssh://localhost:22 (or whatever port your SSH daemon listens on).
  3. In the Zero Trust dashboard, create an Access application for that hostname (e.g., ssh.example.com). Choose SSH as the application type.
  4. Add a policy allowing your email address or identity provider group. For a full walkthrough, see Cloudflare's SSH tutorial. Once done, you'll have a secure hostname like ssh.example.com that no one can connect to without an authenticated Cloudflare Access session.

⚠️ Important: Make sure your Access application is created as SSH, not HTTP. The TCP proxy behaviour differs, and cloudflared access tcp needs a proper SSH‑type Access app.


Step 3 – Test the Connection Directly

Open a terminal on your local machine and try a one‑liner that uses cloudflared as the SSH proxy:

ssh -o "ProxyCommand=cloudflared access tcp --hostname %h" [email protected]

You'll see a browser window pop up for authentication (or a CLI link if cloudflared can't open a browser). After you authenticate, the SSH connection is established. If you get a shell, everything works. If you're on Windows and haven't added cloudflared to PATH, use the full path:

ssh -o "ProxyCommand=\"C:\Program Files (x86)\cloudflared\cloudflared.exe\" access tcp --hostname %h" [email protected]

Step 4 – Create an SSH Alias (Optional but Handy)

Nobody wants to type that monster command every time. Edit your SSH config file:

  • macOS/Linux: ~/.ssh/config
  • Windows: C:\Users\your-username\.ssh\config Add a block like this:
Host myserver
    HostName ssh.example.com
    User your-remote-username
    ProxyCommand cloudflared access tcp --hostname %h

Now you can connect with a short alias that hides the real hostname:

ssh myserver

Even better, you can define multiple aliases for different servers, all going through Access. The real hostname (ssh.example.com) never appears in your daily workflow.

Windows‑specific ProxyCommand

If cloudflared isn't globally accessible yet, replace the ProxyCommand line with the full path:

ProxyCommand "C:\Program Files (x86)\cloudflared\cloudflared.exe" access tcp --hostname %h

How It Works

When you run ssh myserver, SSH reads the config and executes the ProxyCommand: cloudflared access tcp --hostname %h (where %h is replaced by HostName). cloudflared creates a secure tunnel to Cloudflare's edge, handles the Access authentication (via browser or device login), and then pipes the raw SSH traffic through the tunnel to your server. From SSH's perspective, it's talking to a local proxy.

Troubleshooting

Problem Solution
"cloudflared: command not found" Make sure the binary is in your PATH or use the full path in your SSH config.
"Invalid SSH identification string" You're probably running cloudflared access tcp by itself in the terminal. Always use it inside ProxyCommand with ssh.
Connection hangs after authentication Check that your Access app type is set to SSH (not HTTP) and that the origin server's SSH daemon is actually listening on port 22.
Browser authentication fails Ensure your identity provider (e.g., Google Workspace, Okta) is correctly configured and your email is allowed by the Access policy.

Wrapping Up

You now have a fully private SSH setup that relies on identity, not network perimeters. By combining cloudflared, Cloudflare Access, and a simple SSH config alias, you can connect to any server with a short, memorable command — no real hostname ever exposed, and no ports left open to the internet. Happy secure shelling! 🔐

·