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.
- Go to https://dash.cloudflare.com/profile/api-tokens
- Click “Create Token” → “Create Custom Token”
- 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 |
- Click “Continue to summary” → “Create Token”
- 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.ymlpointing your subdomain tossh://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:
- Creates an Access Application for your subdomain with type
ssh(browser-rendered terminal) - Creates an Access Policy allowing your Cloudflare email address
- Sets session duration to 30 days (authenticate once per month per device)
- 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:
- Go to https://one.dash.cloudflare.com → Access → Applications
- Click “Add an application” → “Self-hosted”
- Set application name, domain (your subdomain), type = SSH
- Add a policy: Action = Allow, Include = your email
- Set session duration to 720 hours (30 days)
- 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.
Option B: Short-Lived Certificates (Passwordless — Recommended)
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:
-
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 -
Create a principals file listing allowed Cloudflare emails:
echo "your-cloudflare-email@example.com" > /etc/ssh/cf_principals -
Add to
/etc/ssh/sshd_config:PubkeyAuthentication yes TrustedUserCAKeys /etc/ssh/cf_ca.pub Match User your-username AuthorizedPrincipalsFile /etc/ssh/cf_principals -
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)
- Open
https://your-subdomain.example.com - First time (or every 30 days): authenticate with your email via OTP
- If using short-lived certificates: SSH login is automatic (no password) If using password auth: enter your Linux username and password
- 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.