Remote instances & headless server
Run Qalatra Server on a Linux box and connect desktop clients over HTTPS.
Qalatra can run as a server/client system. The desktop app still feels local, but the data path can go through Qalatra Server: an authenticated HTTP API that owns SQLite, MCP, background workers, agent jobs, attachments, backups, tokens, and encryption key access.
What changes
- Local desktop: Electron starts a local Qalatra Server and connects to it over the same API path remote clients use.
- Remote server: a Linux user service runs Qalatra without the Electron UI.
- Instances: Settings → Instances stores server URLs and bearer tokens so the desktop app can switch between local and remote data sources.
- MCP: the server starts MCP locally, but MCP is not exposed publicly.
Trust model
Use separate channels for operator access and the Qalatra API.
| Channel | Example | Cloudflare Access | Auth owner |
|---|---|---|---|
| Operator access | SSH, noVNC, admin desktop | On | Cloudflare Access + SSH keys |
| Qalatra API | api.example.com | Off | Qalatra bearer tokens |
Linux headless install
Run the installer as the normal Linux user that should own Qalatra. Do not run it with sudo.
export QALATRA_TUNNEL_HOSTNAME=api.example.com curl -fsSL https://raw.githubusercontent.com/pirateandfox/qalatra/develop/scripts/bootstrap-linux-server.sh | bash
The bootstrap script:
- clones or updates Qalatra in
~/qalatra - installs dependencies without Electron postinstall rebuilds
- rebuilds native modules for system Node
- installs and starts
qalatra-server.service - creates or reuses a Cloudflare Tunnel named
qalatra-api - routes the API hostname to
127.0.0.1:3456 - installs and starts
qalatra-cloudflared.service
Reboot survival
loginctl enable-linger "$USER" systemctl --user status qalatra-server.service --no-pager -l systemctl --user status qalatra-cloudflared.service --no-pager -l
Smoke tests
On the Linux server:
curl -fsS http://127.0.0.1:3456/health TOKEN=$(cat ~/.local/share/qalatra/db/admin-token.txt) curl -fsS \ -H "Authorization: Bearer $TOKEN" \ http://127.0.0.1:3456/api/instance
From another machine, test the public API hostname:
curl -fsS \ -H "Authorization: Bearer $TOKEN" \ https://api.example.com/api/instance
Connect desktop to a remote server
Settings -> Instances -> Add Server URL: https://api.example.com Token: contents of ~/.local/share/qalatra/db/admin-token.txt from the Linux server
Prefer creating a dedicated expiring token for each client, then revoking the bootstrap token when it is no longer needed.
MCP stays local
Qalatra Server starts MCP locally at http://127.0.0.1:3457/mcp. If Claude Code is running on the Linux machine, configure that local URL. Do not expose port 3457 through Cloudflare Tunnel.
Troubleshooting
API is not healthy
systemctl --user status qalatra-server.service --no-pager -l journalctl --user -u qalatra-server.service -n 160 --no-pager
Tunnel routes to the wrong service
cat ~/.config/qalatra/cloudflared/config.yml cloudflared tunnel info qalatra-api dig +short CNAME api.example.com
Native module ABI errors
cd ~/qalatra npm run rebuild:node systemctl --user restart qalatra-server.service