cloudflared (Cloudflare's tunnel client) as an SSH ProxyCommand so that every connection is transparently redirected through the tunnel.example.com).cloudflared installed on your local machine (the one you're connecting from).cloudflaredInstall the latest cloudflared client on your workstation. Below are the quick methods for Windows, macOS, and Linux:
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
brew install cloudflare/cloudflare/cloudflared
# or download the .deb/.rpm package, or use the static binary
cloudflared --version
Tip: The examples below assume
cloudflaredis 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 seecloudflared.
Skip this if you already have a working tunnel and Access policy for SSH. Quick overview:
cloudflared on the server and connect it as a tunnel.ssh://localhost:22 (or whatever port your SSH daemon listens on).ssh.example.com). Choose SSH as the application type.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 tcpneeds a proper SSH‑type Access app.
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]
Nobody wants to type that monster command every time. Edit your SSH config file:
~/.ssh/configC:\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.
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
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.| 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. |
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! 🔐