Running Claude Code safely on remote Linux

Field notes from a real deployment (DigitalOcean US droplet + browser remote desktop + Claude Desktop). Goal: use Claude Desktop / Claude Code from a browser on a Linux box you control in the US, with Chinese input, file upload, audio, and an HTTPS portal. Dated 2026-09-13 · Target OS: Ubuntu 24.04 LTS


0. What you end up with#

CapabilityNotes
US VPSDigitalOcean Droplet, billed monthly
Graphical desktopTigerVNC + XFCE (stable for Claude Desktop) / Plasma (optional)
Browser entryPassword portal at https://wi.ci (Cloudflare Tunnel; 3389/5901 stay closed)
Two remote pathsnoVNC (VNC desktop) · Guacamole + audio (xrdp/RDP)
ClaudeClaude Desktop on Linux, signed in; CLI / projects still work on the desktop
Chinese inputFcitx5 Pinyin, toggle with Ctrl+Space
File transferPortal “Files” drop zone → desktop Inbox
Security baselineNon-root daily user, key login, UFW, secrets never in the doc

1. Why do it this way#

  • Claude Desktop (and some of its features) is sensitive to network region. A US VPS plus a local browser is more controllable than an unstable direct connection from your laptop.
  • Do not expose VNC/RDP ports to the public internet. Put the desktop behind HTTPS with Cloudflare Tunnel (or an SSH tunnel).
  • Day-to-day work runs as a low-privilege user desk. Use root only for packages and system config.
  • Passwords and tokens live in a secrets file on the server, or in a password manager on your laptop. Never put them in a tutorial repo or a copy of a chat that can be forwarded.

2. Buy and initialise DigitalOcean#

2.1 Sizing#

  • Size: 2 vCPU / 4 GB RAM (Claude Desktop plus a browser is memory-hungry; smaller boxes OOM)
  • OS: Ubuntu 24.04 LTS x64
  • Region: United States (e.g. NYC3)
  • Budget: around $24/month (subject to DigitalOcean’s pricing)
  • Billing: register with an email; pay however your account allows (card / Alipay, etc.)

2.2 Create the Droplet#

  1. Sign in to DigitalOcean.
  2. Create → Droplets → pick region, Ubuntu 24.04, 2C/4G.
  3. Prefer SSH Key auth. If you must start with a password, switch to keys immediately and disable password login.
  4. Hostname example: claude-code-us.
  5. After create, record the public IP and any initial root password — only in an encrypted store on your machine.

2.3 First login from your laptop#

ssh root@YOUR_DROPLET_IP

Do this next:

apt update && apt -y upgrade
timedatectl set-timezone Asia/Shanghai   # or keep UTC
adduser desk
usermod -aG sudo desk
## Give desk a login password (can match the VNC password so the keyring unlocks)

Generate a key locally if you do not have one, then install the public key:

## on your laptop
ssh-copy-id -i ~/.ssh/id_ed25519.pub desk@YOUR_DROPLET_IP

Suggested /etc/ssh/sshd_config on the server:

PermitRootLogin prohibit-password
PasswordAuthentication no
PubkeyAuthentication yes

Then:

systemctl reload ssh

UFW baseline (allow SSH first, then enable):

ufw allow OpenSSH
ufw enable
## With Cloudflare Tunnel you usually never open 5901/3389/8080 to the world

3. Graphical desktop and TigerVNC#

3.1 Desktop environment#

What actually worked:

  • XFCE: light, stable, Claude Desktop windows render (use this as the noVNC default).
  • KDE Plasma 5: nicer looking, but Electron (Claude Desktop) under VNC/Plasma has shown InputOnly / invisible windows. Keep it as a spare; do not make it the Claude daily driver.

Install example (you can install both and switch):

apt install -y xfce4 xfce4-goodies
## optional:
apt install -y kde-plasma-desktop

3.2 TigerVNC (loopback only)#

apt install -y tigervnc-standalone-server tigervnc-common
sudo -u desk vncpasswd          # set the VNC password

Key points for ~desk/.vnc/xstartup:

  • unset DBUS_SESSION_BUS_ADDRESS then dbus-launch
  • Export IME environment (see section 8)
  • exec startxfce4 (or Plasma’s startplasma-x11)

Start (display :1 → port 5901):

sudo -u desk vncserver :1 -geometry 1920x1080 -depth 24

Security: VNC listens on localhost only. The public path is Tunnel / SSH forward.

ssh -L 5901:127.0.0.1:5901 desk@YOUR_DROPLET_IP
## then point a local VNC client at 127.0.0.1:5901

3.3 Prevent sleep / lock (required on a remote box)#

Otherwise the browser session suddenly “locks / goes black”:

  • systemd: mask sleep.target suspend.target hibernate.target
  • Plasma: disable Autolock in ~/.config/kscreenlockerrc
  • Put xset s off -dpms in the session startup script

4. Install Claude Desktop (Linux)#

  1. Install Claude Desktop the way Anthropic currently documents for Linux (apt package or the current official method).
  2. Launch it as desk on the graphical desktop and complete login.
  3. A desktop shortcut start-claude-desktop.sh that forces DISPLAY=:1 helps.

Caveats:

  • 4 GB of RAM is tight: few Chrome tabs; do not stack several Electron apps.
  • If it “starts but you cannot see the window” on Plasma: switch back to XFCE and launch Claude there.
  • You can disable the KDE Wallet prompt (kwalletrcEnabled=false); Claude may fall back to plaintext session storage. That is a trade-off.
  • GNOME Keyring / login password matching the desk password means fewer keyring interruptions.

Claude Code CLI (optional, complementary to Desktop):

## Install Node / the claude CLI from the current official docs
## Use it in a desktop terminal. Do not write API keys into world-readable files

5. Web remote-desktop portal (noVNC + upload)#

5.1 Components#

  • websockify: turn 5901 into a WebSocket
  • noVNC: VNC in the browser
  • Small Flask portal: login, resolution, language, file upload, mode switch
  • nginx: reverse-proxy local ports
  • cloudflared: Cloudflare Tunnel → local nginx

Typical local ports (127.0.0.1 only):

ServicePort
Portal Flask8081
nginx (Tunnel target)8080
VNC5901
Guacamole Tomcat8085
guacd4822
xrdp3389 (localhost only)

5.2 File upload (Inbox)#

  • Server directory example: /home/desk/Desktop/Inbox
  • The portal exposes drag-and-drop upload; the UI can be a floating “Files” panel on the right.

5.3 Cloudflare Tunnel + domain#

  1. Point a domain (example wi.ci) at Cloudflare DNS.
  2. Install cloudflared, create a Tunnel, Ingress:
ingress:
  - hostname: wi.ci
    service: http://127.0.0.1:8080
  - service: http_status:404
  1. Add a portal password of its own (better if it differs from the VNC password).
  2. Check: https://wi.ci → log in → noVNC shows the desktop.

6. Guacamole + xrdp (browser remote with audio)#

6.1 Why Guacamole as well#

  • noVNC’s audio path is weak or needs an extra WebSocket.
  • Guacamole speaks RDP (xrdp) and, with PipeWire / xrdp-sink, can play sound in the browser.

Note: Guacamole/RDP is a separate desktop session (e.g. display :10), not the same noVNC screen.

6.2 Install notes#

  1. Install xrdp / xorgxrdp; desk must be allowed to log in.
  2. Deploy Guacamole + guacd + PostgreSQL with Docker Compose.
  3. nginx reverse-proxies /guacamole/ and upgrades WebSocket.
  4. UFW must allow the Docker bridge to reach host guacd:4822 (otherwise you sit on Waiting / Bad gateway):
ufw allow from 172.16.0.0/12 to any port 4822
  1. RDP audio: build/install pulseaudio-module-xrdp or the PipeWire xrdp module; in the session PULSE_SINK=xrdp-sink.
  2. Example Guacamole connection: 127.0.0.1:3389, user desk, enable-audio=true, server-layout=en-us-qwerty.

6.3 How the portal connects#

  • Dropdown: Guacamole+audio / noVNC
  • The Guacamole iframe needs tabindex plus a click to focus, or the portal steals keyboard events.
  • Get English typing working first, then turn on the Chinese IME (next section).

6.4 Paths that were removed#

  • RustDesk: dropped to avoid extra ports and upkeep (your threat model may differ).
  • A separate “RDP client” entry can be merged into Guacamole so users have fewer choices.

7. Resolution, language, and portal UX#

  • Resolution dropdown: call xrandr / a script to change VNC geometry.
  • Language: portal UI zh/en toggle.
  • Fullscreen, open in a new tab, log out.
  • Favicon and a compact top bar, so the desktop keeps vertical space.

8. Chinese IME (Fcitx5 Pinyin)#

8.1 Install#

apt install -y fcitx5 fcitx5-chinese-addons fcitx5-frontend-gtk3 \
  fcitx5-frontend-gtk4 fcitx5-frontend-qt5 fonts-noto-cjk fonts-noto-cjk-extra

8.2 Configuration rules#

  • Default English keyboard, ActiveByDefault=False.
  • Toggle: Ctrl + Space → Pinyin; again to return to English.
  • Environment variables (in ~/.xsession, VNC xstartup, ~/.profile):
export GTK_IM_MODULE=fcitx
export QT_IM_MODULE=fcitx
export XMODIFIERS=@im=fcitx
  • At session start: fcitx5 -d --replace

8.3 Interaction with Guacamole#

  • The IME process once swallowed every keypress → English stopped working too.
  • Fix order: first make sure English works when Pinyin is off via Ctrl+Space, then teach the Chinese toggle.
  • If English dies again: Ctrl+Space back to English, or reconnect Guacamole.

9. Secure-operation checklist (treat as mandatory)#

  1. Do not open 5901 / 3389 / 8080 / 4822 on the public internet. Only 22 (or a moved SSH port) plus Cloudflare.
  2. SSH key login, password login off; root has no password login.
  3. Portal password is not a throwaway; better if it differs from VNC.
  4. Secrets path examples (mode 600, readable only by root/desk):

    • /root/secrets/desk-portal-password.txt
    • /root/secrets/desk-rdp-password.txt
    • /root/secrets/guacamole-admin.txt
  5. Regular apt upgrade; watch Claude Desktop and kernel updates.
  6. Snapshot: take a DigitalOcean Snapshot before large changes.
  7. Do not post cookies, API keys, or desktop recordings in public places.
  8. Memory alert: free -h. On OOM, close browser tabs / restart the desktop session first.

10. Daily use#

  1. Open https://your-domain → enter the portal password.
  2. Pick a connection:

    • noVNC: daily desktop, Claude Desktop (XFCE)
    • Guacamole+audio: when you need system sound
  3. Click the desktop area so keyboard focus is remote.
  4. Chinese: Ctrl+Space.
  5. Files: portal “Files” → drop into Inbox.
  6. Leave: portal “Log out”. Closing the browser tab is not a lock screen.

Renewal reminder: put Droplet billing and the Claude subscription on a calendar / assistant reminder (e.g. a fixed day each month).


11. Troubleshooting#

SymptomLikely causeFix
Portal 502cloudflared / origin downsystemctl restart cloudflared nginx desk-portal
Guacamole Waiting / Bad gatewayUFW blocking Docker→4822Allow 172.16.0.0/12 → 4822
Guacamole black screenPlasma compositor / dead sessionKWIN_COMPOSE=N; reconnect; or use noVNC
Keyboard deadiframe unfocused / IME swallowing keysClick desktop; Ctrl+Space; check fcitx
Claude started, invisiblePlasma + ElectronSwitch to XFCE; clear Singleton lock; restart
Sudden lock screenPlasma autolock / sleepDisable Autolock; mask sleep targets
No soundnot using xrdp-sink / audio offGuacamole mode + PipeWire xrdp module
Stutter / killed processes4G RAM fullFewer tabs; restart the VNC session

12. Switching desktops (notes)#

Keep switch scripts on the server (example paths):

  • /home/desk/bin/use-xfce — XFCE for noVNC (recommended for Claude)
  • /home/desk/bin/use-plasma — back to Plasma (test Claude yourself)

After changing ~/.vnc/xstartup:

sudo -u desk vncserver -kill :1
sudo -u desk vncserver :1 -geometry 1920x1080 -depth 24

xrdp/Guacamole sessions read ~/.xsession; reconnect Guacamole to pick up changes.


13. Suggested paths and service names#

/opt/desk-portal/app.py          # portal
/opt/guacamole/                  # Guacamole stack
/home/desk/.vnc/                 # VNC config
/home/desk/.xsession             # xrdp session
/home/desk/Desktop/Inbox         # uploads
/root/secrets/                   # passwords and tokens (never commit)

Common systemd units:

  • desk-portal.service
  • desk-websockify.service
  • desk-audio.service (if you enable noVNC audio)
  • cloudflared.service
  • xrdp / xrdp-sesman

14. Shortest path from zero#

  1. Buy a DO US 2C/4G Ubuntu 24.04 droplet
  2. SSH keys + UFW + user desk
  3. XFCE + TigerVNC (localhost)
  4. Install Claude Desktop and sign in on the desktop
  5. Portal + noVNC + upload
  6. Cloudflare Tunnel bound to a domain over HTTPS
  7. (Optional) Guacamole + xrdp + audio + UFW for Docker→guacd
  8. Disable sleep / autolock
  9. Fcitx5 Pinyin, Ctrl+Space
  10. Take a Snapshot; set renewal reminders

15. Disclaimer#

  • Cloud-vendor TOS and Claude/Anthropic terms win; region and compliance are yours.
  • This tutorial is system administration and remote desktop on a VPS you own. It does not teach bypassing anyone’s security or billing.
  • Hostnames, IPs, and paths here come from one deployment. Replace them with yours.

Appendix A. Snapshot of this deployment (optional)#

ItemValue
Hostnameclaude-code-us
OSUbuntu 24.04
Size2C / 4GB / NYC
Portal domain examplewi.ci
noVNC desktopXFCE (stable for Claude)
GuacamolePlasma + xrdp (audio)
IMEFcitx5 Pinyin

End of the public notes. Keep passwords, Tunnel IDs, and billing email in a private notebook.