DocHub
Step-by-step guide for setting up browser-based SSH with Cloudflare Tunnel and tmux

Developer Remote Terminal Setup Guide

This guide sets up browser-based SSH access to your development machine, allowing you to use a terminal from your phone or any browser while simultaneously working on the machine itself. Both sessions share the same tmux session in real time.

What You Get

  • A persistent tmux session (claude) that survives reboots
  • Browser-based SSH via Cloudflare Tunnel (no port forwarding, no VPN)
  • Simultaneous multi-device access (laptop + phone see the same terminal)
  • Cloudflare Access authentication (one-time login, 30-day session)
  • Everything auto-starts on boot via systemd

Prerequisites

Requirement Details
OS Ubuntu 22.04+ (other Linux distros with minor adjustments)
Sudo access Required for installing packages and configuring SSH
Cloudflare account With a domain managed by Cloudflare DNS
Email access For Cloudflare One-Time Pin authentication

Architecture

Phone Browser ──► Cloudflare Access (OTP auth)
                      │
                      ▼
                 Cloudflare Edge
                      │
                      ▼ (encrypted tunnel)
                 cloudflared daemon (your machine)
                      │
                      ▼
                 SSH server (localhost:22)
                      │
                      ▼
                 tmux session "claude"
                      ▲
                      │
Laptop Terminal ──────┘ (tmux attach -t claude)

No ports are opened on your machine. The cloudflared daemon maintains an outbound connection to Cloudflare’s edge network. Cloudflare Access handles authentication before any traffic reaches your SSH server.


Step 1: Gather Information

Before starting, collect the following. You will need to provide these to Claude Code or fill them into the setup script.

Item How to Get It Example
Your Linux username Run whoami dev-user
Subdomain for SSH Choose one on your Cloudflare domain ssh.example.com
Cloudflare email The email you log into Cloudflare with you@example.com
Cloudflare Account ID Cloudflare dashboard sidebar → Account ID 896d...23eb
Cloudflare API token See Step 2 vaym93...GLNO

Step 2: Create a Cloudflare API Token

Claude Code needs API access to configure Cloudflare Access for you.

  1. Go to https://dash.cloudflare.com/profile/api-tokens
  2. Click “Create Token”“Create Custom Token”
  3. Configure:
Setting Value
Token name Claude CLI
Permissions
Account > Access: Apps and Policies Edit
Account > Access: Service Tokens Edit
Zone > DNS Edit
Account Resources Include > All accounts (or your specific account)
Zone Resources Include > Specific zone > your domain
  1. Click “Continue to summary”“Create Token”
  2. Copy the token (shown only once) and provide it to Claude Code

Step 3: Run the Setup Script

Claude Code will generate a setup script customized for your machine. Run it with sudo:

sudo bash ~/setup-remote-terminal.sh

The script performs these phases automatically:

Phase 1: Install Packages

Package Purpose
tmux Terminal multiplexer for shared sessions
openssh-server SSH server for incoming connections
cloudflared Cloudflare Tunnel daemon

Phase 2: Enable SSH Server

Starts and enables the SSH server via systemd.

Phase 3: Authenticate Cloudflared

Interactive step — a browser window opens (or a URL is displayed) for you to log into Cloudflare and authorize the tunnel. Select your domain’s zone when prompted.

This creates ~/.cloudflared/cert.pem which authorizes tunnel creation on your account.

Phase 4: Create Tunnel and DNS Route

  • Creates a named tunnel (e.g., laptop-ssh)
  • Writes ~/.cloudflared/config.yml pointing your subdomain to ssh://localhost:22
  • Creates a DNS CNAME record for your subdomain

Phase 5: Create Systemd Services

Two services are created and enabled:

Service Purpose
cloudflared-tunnel.service Runs the tunnel, auto-restarts on failure
tmux-claude.service Creates the claude tmux session on boot

Phase 6: Configure tmux

Writes ~/.tmux.conf with multi-client settings:

Setting Purpose
mouse on Mouse support in terminal
history-limit 50000 Large scrollback buffer
aggressive-resize on Multiple clients at different screen sizes

Step 4: Cloudflare Access Configuration

Claude Code uses the API token from Step 2 to configure Cloudflare Access:

  1. Creates an Access Application for your subdomain with type ssh (browser-rendered terminal)
  2. Creates an Access Policy allowing your Cloudflare email address
  3. Sets session duration to 30 days (authenticate once per month per device)
  4. Generates an SSH Certificate Authority for passwordless login (optional)

If Claude Code doesn’t have API access, these can be configured manually in the Cloudflare Zero Trust dashboard:

  1. Go to https://one.dash.cloudflare.comAccessApplications
  2. Click “Add an application”“Self-hosted”
  3. Set application name, domain (your subdomain), type = SSH
  4. Add a policy: Action = Allow, Include = your email
  5. Set session duration to 720 hours (30 days)
  6. Under Additional settings, enable Browser rendering = SSH

Step 5: SSH Authentication

When connecting via the browser terminal, you need to authenticate to the SSH server. Two options:

Option A: Password Authentication (Simple)

Set a password for your user:

sudo passwd your-username

When the browser terminal asks for User and Password, enter your Linux username and password. This is the simplest approach — Cloudflare Access is the real security layer.

Claude Code can set up Cloudflare short-lived certificates so the browser terminal logs you in automatically after Cloudflare authentication. After the one-time OTP (cached 30 days), no further credentials are needed.

How it works: Cloudflare Access issues a short-lived SSH certificate when you authenticate. The SSH server trusts Cloudflare’s CA and maps the certificate principal (your email) to your Linux user.

Setup steps:

  1. Fetch the CA public key from the Access app API:

    curl -s -H "Authorization: Bearer $CF_ACCESS_API_TOKEN" \
      "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/apps/$APP_ID/ca" \
      | python3 -c "import sys,json; print(json.load(sys.stdin)['result']['public_key'])" \
      > /etc/ssh/cf_ca.pub
    
  2. Create a principals file listing allowed Cloudflare emails:

    echo "your-cloudflare-email@example.com" > /etc/ssh/cf_principals
    
  3. Add to /etc/ssh/sshd_config:

    PubkeyAuthentication yes
    TrustedUserCAKeys /etc/ssh/cf_ca.pub
    
    Match User your-username
      AuthorizedPrincipalsFile /etc/ssh/cf_principals
    
  4. Restart SSH:

    sudo systemctl restart ssh
    

The Match User block ensures the certificate auth only applies to your user, and the principals file controls which Cloudflare emails can log in as that user.


Daily Usage

From your laptop

Open any terminal and attach to the shared session:

tmux attach -t claude

From your phone (or any browser)

  1. Open https://your-subdomain.example.com
  2. First time (or every 30 days): authenticate with your email via OTP
  3. If using short-lived certificates: SSH login is automatic (no password) If using password auth: enter your Linux username and password
  4. Run: tmux attach -t claude

Both devices now see the same terminal session. Type on one, it appears on the other.

Critical Rule: Never Detach Others

Always use:

tmux attach -t claude        # Correct — joins without detaching others

Never use:

tmux attach -d -t claude     # WRONG — detaches all other clients

The -d flag kicks everyone else off the session.

Phone Display Tips

The Cloudflare browser terminal may render with large text on mobile. To adjust:

  • Use your browser’s zoom controls (Chrome menu → zoom percentage)
  • Enable “Desktop site” mode in your mobile browser
  • Reduce text scaling in browser accessibility settings

Service Management

# Check status of all services
systemctl status cloudflared-tunnel tmux-claude ssh

# Restart the tunnel (if connection drops)
sudo systemctl restart cloudflared-tunnel

# Restart the tmux session (creates a fresh session)
sudo systemctl restart tmux-claude

# View tunnel logs
journalctl -u cloudflared-tunnel -f

# List who's attached to the session
tmux list-clients -t claude

After a Reboot

All services auto-start via systemd. Allow ~30 seconds for the tunnel to reconnect. Verify:

systemctl is-active cloudflared-tunnel ssh tmux-claude

All three should report active.

Troubleshooting

Problem Solution
Browser shows “connection refused” Check tunnel: systemctl status cloudflared-tunnel
Tunnel service won’t start Check credentials: ls ~/.cloudflared/*.json
tmux session doesn’t exist Restart: sudo systemctl restart tmux-claude
“Session expired” on phone Re-authenticate with OTP (every 30 days)
SSH asks for password after cert setup Check /etc/ssh/cf_principals has your Cloudflare email
Large text on phone Use browser zoom controls, not pinch-to-zoom
Can’t see other device’s typing Both must run tmux attach -t claude (same session name)
DNS not resolving Wait 5 minutes for DNS propagation, or check cloudflared tunnel route dns

Security Model

Layer Protection
Cloudflare Access Only authenticated emails can reach the SSH server
SSH authentication Password or certificate required even after Cloudflare auth
No open ports Tunnel is outbound-only — no firewall ports exposed
30-day sessions Periodic re-authentication required
tmux isolation Session runs as your user, not root

The Cloudflare tunnel means your SSH server is never directly exposed to the internet. All traffic routes through Cloudflare’s network, which handles DDoS protection, authentication, and TLS termination.