knowledge-base/network/cf-tunnel-ssh.md

4.6 KiB

Cloudflare Tunnel — Dev Container SSH Access

Overview

CF Tunnel SSH provides local VS Code / terminal access to dev containers for developers who want to use their own tooling instead of the browser IDE.

This is a power-user feature, not zero-install. It requires cloudflared installed on the developer's local machine. The browser IDE remains the zero-install option for all developers.


Install Requirement Clarification

cloudflared is required on both sides — but they do different things:

Side Role
Bastion VM cloudflared runs as a persistent service maintaining the outbound tunnel to Cloudflare
Developer's local machine cloudflared acts as an SSH ProxyCommand — routes SSH through Cloudflare instead of directly to the IP

The dev container (LXC) only needs sshd running. It does not need cloudflared.

Without the ProxyCommand on the client, SSH goes directly to the raw IP and gets rejected. You will see:

kex_exchange_identification: Connection closed by remote host

This means cloudflared is not being invoked — SSH is bypassing Cloudflare entirely.


Architecture

Developer laptop (cloudflared as ProxyCommand)
  ↓ ssh dev-6070.zerolaghub.dev
Cloudflare edge
  ↓ CF Tunnel (persistent service on bastion)
Bastion VM (private IP, no public exposure)
  ↓ SSH proxy jump
Dev container (10.100.x.x — just needs sshd)

Zero-Install vs Power-User Access

Access Method Install Required Use Case
Browser IDE (dev-<vmid>.zerolaghub.dev) Nothing All developers — zero friction
CF Tunnel SSH cloudflared on local machine Power users wanting local VS Code or terminal

The browser IDE is the primary access method. CF Tunnel SSH is optional and for developers who specifically want local tool integration.


Current State

  • CF Tunnel created and connected to bastion VM
  • Cloudflare Zero Trust free plan active (up to 50 users)
  • Tunnel SSH hostname mapping not yet configured in Zero Trust dashboard
  • Bastion SSH proxy jump config not yet done
  • Dev container SSH server not yet verified
  • Portal SSH config snippet not yet built

Remaining Steps

1. Configure tunnel ingress in Cloudflare Zero Trust dashboard

Zero Trust → Networks → Tunnels → your tunnel → Configure:

Add a public hostname:

  • Subdomain: * (wildcard)
  • Domain: zerolaghub.dev
  • Service type: SSH
  • URL: localhost:22

2. Configure bastion SSH for proxy jump

Edit /etc/ssh/sshd_config on the bastion:

AllowTcpForwarding yes
PermitOpen 10.100.0.0/24:22

Restart: systemctl restart sshd

3. Ensure dev containers have SSH running

Add to agent dev provisioning pipeline:

apt-get install -y openssh-server
systemctl enable ssh
systemctl start ssh

4. Developer one-time setup (power users only)

Install cloudflared on their local machine:

# macOS
brew install cloudflare/cloudflare/cloudflared

# Linux
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 \
  -o /usr/local/bin/cloudflared && chmod +x /usr/local/bin/cloudflared

# Windows — download from GitHub releases
# Termux — pkg install cloudflared

Add to ~/.ssh/config:

Host *.zerolaghub.dev
    ProxyCommand cloudflared access ssh --hostname %h
    User dev

Then: ssh dev-6070.zerolaghub.dev

Confirm it's working by looking for in -v output:

Executing proxy command: cloudflared access ssh --hostname dev-6070.zerolaghub.dev

Portal Integration (Future)

Show on the dev container page as an optional section:

Local VS Code Access (Advanced)
────────────────────────────────
Requires a one-time install of cloudflared on your machine.

1. Install: https://developers.cloudflare.com/cloudflared/install
2. Add to ~/.ssh/config:

   Host *.zerolaghub.dev
       ProxyCommand cloudflared access ssh --hostname %h
       User dev

3. Connect: ssh dev-6070.zerolaghub.dev
   Or open VS Code Remote Explorer and add this host.

Troubleshooting

Issue Likely Cause
kex_exchange_identification: Connection closed ProxyCommand not in SSH config — SSH going direct to IP
cloudflared: command not found cloudflared not installed on client machine
Connection refused SSH not running in container or bastion jump not configured
Permission denied SSH key not added to container's dev user
Tunnel not connecting cloudflared service not running on bastion — systemctl status cloudflared