Architecture

Nexus is four clients and one optional backend. The clients talk directly to your hosts over LAN or Tailscale. The backend adds owner-only remote access through Cloudflare without opening inbound ports.

Components

Component Runs on Source Role
Nexus for iPhone iPhone, iPad (iOS 17+) NexusiOS App/ Mobile client
Nexus Desktop NixOS / Linux NexusNix IDE, agents, infrastructure
Nexus Desktop Windows 10/11 NexusWindows IDE, agents, infrastructure
Nexus Online Cloudflare Worker NexusOnline Landing page and read-only web client
nexus-gateway Worker Cloudflare NexusiOS cloudflare/ Fixed-route front door for the apps
Nexus gateway Debian, 127.0.0.1:8787 NexusiOS gateway/ Identity, permissions, AI, SSH relay, search, sync
cloudflared Debian Cloudflare Outbound-only tunnel to Workers VPC
Agent orchestrator Debian, 127.0.0.1:8897 NexusiOS agent-orchestrator/ Durable agent runs, approvals, context
Workspace agent Debian and NixOS, 127.0.0.1:8896 NexusiOS workspace-agent/ Read-only workspace bridge
nexus-ro Debian NexusNix crates/nexus-ro SSH forced command, read-only catalog
NexusAI PS5, :8081 and :8082 ljcatherine/NexusAI Local LLM inference and model control

Request paths

Direct (no backend)

App ──SSH (pinned host key)──► host on LAN / Tailscale
App ──HTTP(S)──► AI endpoint on a private address

Each app stores its own devices, endpoints and keys. Nothing goes through Cloudflare.

Through the gateway

App ──HTTPS──► Cloudflare Access (Managed OAuth, PKCE)
             ──► nexus-gateway Worker (checks ctx.access, fixed routes)
             ──► Workers VPC service ──► cloudflared on Debian
             ──► gateway 127.0.0.1:8787 (verifies Cf-Access-Jwt-Assertion, permissions)
             ──► PS5 :8081 / :8082, orchestrator :8897, SSH targets, search

Nexus Online

Browser ──► Cloudflare Access (/app, /api only)
        ──► nexus-online Worker (verifies the Access JWT itself, route allowlist)
        ──► same Workers VPC service ──► gateway

Nexus Online sits in the same Access application as the gateway Worker, so the gateway accepts its tokens without any change on Debian.

SSH relay

App ──WebSocket /v1/ssh/{alias}──► Worker ──► gateway
gateway ──SSH (server-held Ed25519 key, strict known_hosts)──► target alias

The app pins the relay’s own SSH host key and sends no client key. Targets are fixed aliases in NEXUS_SSH_TARGETS_JSON; callers can’t pick a host or user.

Desktop to Debian

Desktop ──SSH, forced command──► nexus-ro (read-only catalog)

Ports

Port Bound to Service
22 LAN, Tailscale OpenSSH (key-only after hardening)
8787 127.0.0.1 Nexus gateway
8896 127.0.0.1 Workspace agent
8897 127.0.0.1 Agent orchestrator
8080 127.0.0.1 Minecraft panel (optional)
8081 PS5 LAN NexusAI llama-server
8082 PS5 LAN, opt-in NexusAI model-control API
7844/udp outbound cloudflared QUIC to Cloudflare

Nothing listens publicly. Never port-forward any of these.

Data and credentials

Where What
iOS Keychain SSH keys, host pins, API and OAuth tokens, OTP secret
Windows Credential Manager / Linux Secret Service API keys, SSH passphrases, app-lock secret
Debian nexus.env (0600) Gateway policy, upstream tokens, encryption key
Debian gateway SSH directory (0600) Relay host key, upstream key, known_hosts
PS5 nexus-control.token (0600) SHA-256 of the control token, never the token
Cloudflare runtime variables Access AUD tag and owner email (identifiers, not secrets)

Edit this page on GitHub ↗