Skip to content

doable-cli: Operator TUI

doable is a Rust terminal UI that operators run from their own machine to provision fresh Doable servers and manage existing ones. It is the interactive replacement for running server-setup.sh by hand over SSH.

Screenshot: doable-cli (TODO)


What it is

Mode Command When to use
Interactive picker doable (no subcommand) First time; lets you choose a mode with arrow keys
Fresh server install doable install ... Provisioning a brand-new VPS
Manage local server doable admin On the server itself, or via SSH + --database-url
Manage remote server doable admin --remote user@host From your laptop, tunnelling DB access over SSH

The binary is named doable and ships at doable-cli/ in the monorepo (version 0.3.0, MIT licensed).


Install

Download the latest release for your OS from the GitHub Releases page and put it somewhere on your PATH:

# example: adjust OS/arch and version
curl -L https://github.com/doable-me/doable/releases/latest/download/doable-linux-x86_64 \
  -o ~/.local/bin/doable
chmod +x ~/.local/bin/doable

Build from source

You need Rust >= 1.80 and a working ssh binary on PATH (macOS/Linux ship one; Windows users can use Git for Windows or WSL).

cd doable-cli
cargo build --release
# binary at target/release/doable

Demo mode (no real server needed)

doable install --host demo --user demo --env-name demo \
               --ssh-key /dev/null --demo

This replays a canned provisioning session so you can explore the TUI without touching a server.


Provision a fresh server

Prerequisites

  • A clean Ubuntu 22.04 or 24.04 VPS with SSH access.
  • Your SSH public key installed on the server (~/.ssh/authorized_keys).
  • A Cloudflare account + a domain pointed at Cloudflare (for the tunnel step).
doable install \
  --host 203.0.113.10 \
  --user ubuntu \
  --env-name myorg \
  --ssh-key ~/.ssh/id_ed25519

The TUI opens and walks through 15 phases, showing live streaming output on the right and a colour-coded phase list on the left:

┌──────────────────────────────────────────────────────────────────────┐
│ Doable Installer │ host: 203.0.113.10   user: ubuntu  env: myorg    │
│                  │ elapsed: 03:21                                    │
├────────────────────┬─────────────────────────────────────────────────┤
│ Phases (4/15)      │ Setup output                                    │
│  ✅  1 Preflight    │ ════════ Phase 4/15: PostgreSQL 16 + ext.      │
│  ✅  2 System pkgs  │   apt-get update                                │
│  ✅  3 Node 22+pnpm │   installing postgresql-16 ...                  │
│  🔄  4 PostgreSQL   │   creating role doable ...                      │
│  ⏳  5 Caddy        │   running migrations ...                        │
│  ⏳  6 Puppeteer    │                                                  │
│  ⏳  7 Repo clone   │                                                  │
│  ⏳  ... 15         │                                                  │
├────────────────────┴─────────────────────────────────────────────────┤
│ q=quit  l=toggle log filter  r=retry phase  p=pause                  │
└──────────────────────────────────────────────────────────────────────┘

The 15 phases (mirrors setup-server-v3.sh):

  1. Preflight checks (OS version, disk space, SSH connectivity)
  2. System packages (curl, git, build-essential, tmux, fail2ban, ufw)
  3. Node.js 22 + pnpm
  4. PostgreSQL 16 + pgvector + pgcrypto + pg_trgm extensions + migrations
  5. Caddy (reverse proxy, auto-SSL, binds to 127.0.0.1)
  6. Puppeteer / Chromium dependencies (thumbnail generation)
  7. Repo clone / pull to /root/doable
  8. pnpm install + initial build
  9. .env generation (JWT_SECRET, ENCRYPTION_KEY, DB password; all random)
  10. UFW firewall (deny-all + allow SSH)
  11. Swap file (2 GB)
  12. Cloudflare Tunnel login + tunnel creation
  13. Cloudflare DNS records + Caddyfile
  14. systemd units (doable.service, cloudflared.service)
  15. tmux session (api, web, ws windows) + smoke test

Unattended / CI mode

DOABLE_HOST=203.0.113.10 \
DOABLE_USER=ubuntu \
DOABLE_ENV_NAME=myorg \
DOABLE_SSH_KEY=$HOME/.ssh/id_ed25519 \
DOABLE_NON_INTERACTIVE=1 \
  doable install

Key bindings during install

Key Action
q / Esc / Ctrl-C Quit

| l | Toggle log filter (errors only) | | r | Flag current phase for retry | | p | Pause auto-scroll |


Manage an existing host

Local (run on the server)

doable admin

Reads DATABASE_URL from /opt/doable/.env automatically.

Remote (from your laptop)

doable admin --remote [email protected] --ssh-key ~/.ssh/id_ed25519

The TUI opens an SSH tunnel to the server and proxies the PostgreSQL connection through it; no extra port needs to be open.

doable admin --remote [email protected] --print-db-url   # full postgres URL
doable admin --remote [email protected] --print-db-pass  # password only

Useful for piping into psql, DBeaver, or other tools.


Admin screens

Once in doable admin you get a full-screen management TUI with these sections:

  • Users & Admins: toggle platform-admin flag, view last login, force logout
  • Feature Flags: flip feature flags on/off per workspace or globally
  • Members & Roles: manage workspace membership and roles, reset MFA
  • AI Settings: per-workspace model enforcement and provider configuration
  • Server Config: edit live server files (Linux only):
    • Squid allowlist (/etc/squid/squid.conf): add/remove egress hostnames
    • cloudflared ingress (/etc/cloudflared/config.yml): manage tunnel routes
    • API .env: edit DOABLE_* / proxy / NODE_ENV knobs
    • systemd hardening (read-only view)

Inside Server Config: 1-4 switch tabs, Enter edits, a adds, d deletes, A applies pending changes (with confirmation), R reloads from disk.

sudoers fragment required for Server Config writes

File writes and service reloads are mediated through sudo. Install the bundled fragment once on each server:

sudo install -m 0440 doable-cli/sudoers/90-doable-admin /etc/sudoers.d/
sudo visudo -c

Comparison with the /admin web panel

doable admin TUI /admin web panel
Who uses it Server operators (SSH access) Platform admins (browser, admin role in the app)
Connection SSH / local process HTTPS via Cloudflare Tunnel
Can edit server files Yes No
Can manage users/roles Yes Yes
Requires DB access Yes (direct) No (uses app API)
Works when app is down Yes No

Use the TUI when you need low-level server control or when the web app is unreachable. Use the /admin panel for day-to-day user and workspace management.


Network safety

The installer uploads setup-server-v3.sh, which binds all services to 127.0.0.1 and exposes them only via Cloudflare Tunnel. No port is reachable from the public internet after provisioning completes. See Bare-metal deployment for the full network diagram.