Pull ttyd/zellij/clide-launcher scripts into deploy/ so the web access layer lives with the project. Zellij is configured in locked mode with a bare layout so it only provides session persistence without intercepting keys or showing UI. Remove Ctrl+G goto-line binding from Clide to avoid conflict with Zellij's unlock key. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
4.5 KiB
Web Deployment
Clide runs in a browser via a three-layer stack:
Browser (code.schweitz.net)
└─ ttyd (web terminal server, port 8888)
└─ zellij (session persistence only)
└─ clide (Textual TUI)
└─ claude code (embedded PTY)
Components
| Layer | Purpose | Config |
|---|---|---|
| ttyd | Serves terminal over WebSocket | systemd service on port 8888 |
| zellij | Session reconnection (detach/reattach) | Locked mode, bare layout, no UI |
| clide | TUI IDE wrapper around Claude Code | Zellij's default shell |
Installation
From the clide project root:
sudo bash deploy/install-clide-web.sh
This installs:
ttydbinary to/usr/local/bin/zellijbinary to/usr/local/bin/clide-launcherscript to/usr/local/bin/- Zellij config to
~/.config/zellij/(locked mode + bare layout) clide-web.servicesystemd unit- Enables and starts the service
Reverse Proxy
For external access, configure your reverse proxy (e.g., Nginx Proxy Manager) to:
- Proxy
code.schweitz.net→localhost:8888 - Enable WebSocket support (required for ttyd)
Architecture
ttyd
Web terminal server. Runs clide-launcher for each browser connection.
Service: /etc/systemd/system/clide-web.service
Key flags:
-p 8888— port-W— writable (allows input)-a— allows URL arguments (passes?project=Xto the launcher)-t fontSize=14— terminal font size
clide-launcher
Entry point script at /usr/local/bin/clide-launcher. Handles:
- Project selection — parses
?project=NAMEfrom the URL - Session management — creates or reattaches to a Zellij session named
clide-<project> - Fallback UI — shows a project selector if no project specified
URL patterns:
code.schweitz.net— shows project selectorcode.schweitz.net?project=clide— opens/attaches to the clide project
Zellij
Used only for session persistence (reconnecting after browser close/refresh). All UI features are disabled.
Config: deploy/zellij/config.kdl
Key settings:
default_mode "locked"— all keys pass through to Clide exceptCtrl+Gdefault_layout "bare"— no tab bar, no status barpane_frames false— no pane bordersdefault_shell— points to the clide binaryshow_startup_tips false
Layout: deploy/zellij/bare.kdl — single pane, zero chrome.
Keybinding Layering
Since the stack is deeply nested, keybindings are carefully layered:
| Key | Layer | Action |
|---|---|---|
Ctrl+G |
Zellij | Unlock Zellij (only key Zellij captures in locked mode) |
Ctrl+Q |
Clide | Quit Clide |
Ctrl+B |
Clide | Toggle sidebar |
Ctrl+P |
Clide | Quick open |
Ctrl+S |
Clide | Save file |
| All others | Clide → Claude | Pass through to Clide, then to Claude Code |
To detach a session (e.g., before service restart):
Ctrl+G— unlock ZellijCtrl+O— session moded— detach
Or just close the browser tab — Zellij detaches automatically.
Operations
Service Management
# Status
systemctl status clide-web
# Restart (disconnects all sessions)
sudo systemctl restart clide-web
# Logs
journalctl -u clide-web -f
Session Management
# List sessions
zellij list-sessions
# Kill stuck sessions
zellij delete-all-sessions --force --yes
# Clear serialized session cache (if ghost sessions persist)
rm -rf ~/.cache/zellij/*/session_info/clide-*
Troubleshooting
Service stuck in deactivating: A child process (usually claude) didn't respond to SIGTERM.
sudo systemctl kill -s SIGKILL clide-web
sudo systemctl start clide-web
Old sessions ignore config changes: Zellij serializes sessions. Delete them and restart:
zellij delete-all-sessions --force --yes
rm -rf ~/.cache/zellij/*/session_info/clide-*
sudo systemctl restart clide-web
Keys not reaching Clide: Zellij may be in normal mode. Press Ctrl+G to toggle back to locked mode. The status bar being visible is a sign you're unlocked (bare layout hides it in locked mode).
Files
deploy/
├── install-clide-web.sh # Installation script (run with sudo)
├── clide-launcher # Session launcher (ttyd → zellij → clide)
├── clide-web.service # systemd unit file
└── zellij/
├── config.kdl # Zellij config (locked mode, no UI)
└── bare.kdl # Bare layout (single pane, no chrome)