Documentation menu
Deploy / v0.1

Install a customer-hosted server

Verify the offline release, install the core server on one Linux machine, create the first administrator, enroll an endpoint and ask it a question.

Reviewed September 27, 2026 · Current implementation

What this installs

The package installs the console, the Query API, the MCP service, the relay, the application database and a local TLS proxy on one dedicated Linux x86-64 server. Endpoints are installed separately from their own signed artifact. Retention, compute and inference roles are absent, and none is needed to install or start the server.

1. Prepare the host

  • A dedicated Linux x86-64 virtual machine. See Deployment profiles for the starting footprint.
  • The operating system, service manager, application database, TLS proxy and bootstrap runtime at the exact package versions pinned in the signed release, installed from verified offline platform media. The installer checks every pinned version and never downloads a package.
  • The application database listening only on localhost, with local administrator access for the operating system's database account.
  • No other web server on TCP 443.
  • A local DNS entry or host mapping for your console name, for example recursift.customer.example, on every client and endpoint, and accurate local time. No public DNS or external time service is needed.
  • A server certificate for that name from your certificate authority, or from a private certificate authority whose private key stays on a protected administration machine, never on the server. Put server.crt (with any intermediates), server.key and ca.crt in one directory.

2. Stage the release and keys

Copy the four signed artifact sets to a staging directory that only root or the operator can write. Keep every file in each set. The console set pins your public HTTPS origin, because the origin is a build input.

Release layout
media/
  webapp/  manifest.json, manifest.sig, composition.json, console bundle, runtime, SBOMs, notices
  api/     manifest.json, manifest.sig, API, MCP and admin binaries, migration, SBOMs, notices
  relay/   manifest.json, manifest.sig, relay binaries, SBOMs, notices
  agent/   manifest.json, manifest.sig, endpoint executable, install contract, SBOM, notices

Put webapp.pub, api.pub, relay.pub and agent.pub in a separate keys directory. Obtain them from Recursift's authenticated release records and compare their fingerprints out of band. A key that arrives only beside the artifacts is not a trust root. Never put a private signing key on the server.

3. Verify without changing the host

Run the read-only check first. It needs neither root nor a network connection. Run it with the installer tools and runtime from independently trusted media; never run a downloaded verifier to judge that same download.

Terminal
bash deploy/customer/install.sh --dry-run --artifacts /media/recursift \
  --keys /trusted/recursift-keys

Success prints Verified four artifact sets, the composition hash and No optional roles, then Dry run: signatures, hashes, versions, required files and targets verified. No host changes. The check fails on a bad signature, an extra, missing or altered file, a symbolic link, a version other than the one pinned in the composition, a binary for a target other than Linux x86-64, or any optional role.

4. Install

Terminal
sudo bash deploy/customer/install.sh --artifacts /media/recursift \
  --keys /trusted/recursift-keys --origin https://recursift.customer.example \
  --tls /secure/recursift-tls

In order, the installer:

  • Verifies all four artifact sets and confirms that --origin matches the origin signed into the release.
  • Confirms Linux x86-64, the required system commands, and the exact platform package and runtime versions.
  • Refuses to continue if any Recursift state, application directory, database or database role already exists, or if the database listens beyond localhost.
  • Checks that the certificate chains to ca.crt, matches the console name, and matches server.key.
  • Generates the secrets, freezes a root-owned copy of the release and verifies that copy again before running anything from it.
  • Confirms the local sign-in bootstrap is present, installs the service binaries, creates the database and its roles, applies the fresh schema baseline and the signed API migration, and records them in a schema ledger.
  • Creates one service account per service with no login shell, installs the service units, writes the proxy configuration for the validated console name, and maps that name to loopback on the server.
  • Starts the services, waits up to 60 seconds for each health check, checks the console through TLS, then records the installed release.

Success ends with Core server services are healthy. Identity and endpoint enrollment remain explicit operator steps. Running the installer again with the same release prints This exact release is already installed. No schema changes. A failed install stops the services it started and keeps its partial state for diagnosis; do not run it again over that state.

Generated secrets

Secrets are generated with cryptographic randomness into mode 0600 files under /etc/recursift/customer: the console sign-in secret, the relay shared secret, the settings encryption key, the configuration signing key, and separate console and API database passwords. Each service reads only its own file. roles.sql holds the database role passwords for restore only.

Ports and accounts

ServiceListenerAccount
Local TLS proxyTCP 443, the only published portrecursift-proxy, with only the capability to bind port 443
ConsoleLoopback TCP 8080recursift-webapp; reads and writes application tables, no schema changes
Query APITCP 8081, localhost traffic onlyrecursift-api; restricted query database role
MCPTCP 8082, localhost traffic onlyrecursift-mcp; no database credential
RelayTCP 8083, localhost traffic onlyrecursift-relay; shared relay secret, no storage
Application databaseLoopback TCP 5432The operating system's database account

The proxy sends / to the console, /v1/ to the Query API, /mcp to MCP, and /ws to the relay. The four application services may exchange traffic only over loopback; confirm that restriction is active in the service logs and with an outbound-denial test. Configure the server firewall to allow TCP 443 and your management access only.

5. Check health

Terminal
systemctl status recursift-{webapp,api,mcp,relay,proxy}
curl --fail http://127.0.0.1:8080/api/health
curl --fail http://127.0.0.1:8081/health
curl --fail http://127.0.0.1:8082/health
curl --fail http://127.0.0.1:8083/health
curl --fail --cacert /etc/recursift/customer/tls/ca.crt \
  https://recursift.customer.example/api/health

The console and API checks include a database ping. The MCP and relay checks show only that the listener is up. Healthy listeners do not show that sign-in, enrollment or a query works; complete the steps below before calling the server ready.

6. Create the first administrator

Terminal
sudo bash deploy/customer/bootstrap-admin.sh --email admin@customer.example

This prints a one-time setup link. Open it privately in a browser that trusts your certificate authority and choose a password. Customer-hosted sign-in and recovery explains expiry, recovery and lockout.

7. Enroll an endpoint

Import ca.crt into the endpoint's trust store. In the local console, use Add agent to get a one-time enrollment token. In the customer profile, the enrollment command the console shows points at your own origin, and the relay address given to endpoints is wss:// followed by your console name and /ws. Do not use a public download link.

8. Issue an API key

API and MCP access need a customer mapping to the console owner and a scoped key, created with the verified admin utility at /opt/recursift/customer/recursift-admin. Give it the database administrator connection in ADMIN_DATABASE_URL for that one process only; never put it in a service's environment. The key is printed once.

Terminal • ADMIN_DATABASE_URL set for this process only
/opt/recursift/customer/recursift-admin -operation customer \
  -owner-user-id EXISTING_USER_ID -name 'Customer name'
/opt/recursift/customer/recursift-admin -operation key \
  -customer-id CUSTOMER_ID -name 'Local MCP' \
  -scopes agents:read,query:read,query:write -days 90

9. Ask a local question

The Query API and MCP service answer on your own origin: /v1 for the API and /mcp for MCP. Requests and responses follow the same contract as the hosted API; only the base address changes. Pass --cacert or install ca.crt so certificate verification stays on.

Terminal
export RECURSIFT_BASE="https://recursift.customer.example/v1"
export RECURSIFT_CA="/path/to/ca.crt"
curl --fail-with-body --cacert "$RECURSIFT_CA" "$RECURSIFT_BASE/me" \
  -H "Authorization: Bearer $RECURSIFT_API_KEY"
curl --fail-with-body --cacert "$RECURSIFT_CA" "$RECURSIFT_BASE/agents?limit=20" \
  -H "Authorization: Bearer $RECURSIFT_API_KEY"
curl --fail-with-body --cacert "$RECURSIFT_CA" "$RECURSIFT_BASE/queries" \
  -H "Authorization: Bearer $RECURSIFT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  --data "$(jq -n --arg id "$RECURSIFT_AGENT_ID" '{
    question: "What operating system are you running?",
    target: {agent_ids: [$id]},
    timeout_seconds: 120
  }')"
curl --fail-with-body --cacert "$RECURSIFT_CA" "$RECURSIFT_BASE/queries/$RECURSIFT_QUERY_ID" \
  -H "Authorization: Bearer $RECURSIFT_API_KEY"

Checked against OpenAPI 0.1.0 at api 92e785d: GET /me, GET /agents with limit, POST /queries with question, target.agent_ids and timeout_seconds and an optional Idempotency-Key header, and GET /queries/{id}. The POST returns 202 with a receipt; poll the query until it is complete, partial, timed_out or cancelled, as in Your first endpoint query.

What the customer profile turns off

DependencyCustomer profile
Hosted sign-in and email deliveryNot registered. Local sign-in only.
Web fonts from a remote hostOmitted; system fonts are used.
Remote model catalogs, completions and connection testsRoutes return 503; outbound calls are refused.
Vulnerability feed and discoveryNot scheduled and no feed token is set. Supply approved offline data separately before claiming current coverage.
Remote key management for stored provider secretsUnset; the generated local settings key is used.
Public download buttons and hosted legal linksNavigation only, not startup requests. Use verified offline media and your own legal material.
Package registriesBuild-side only. The installer resolves no dependencies.
DNS, time and certificatesYour own names, clock and certificate authority.

In the customer profile the console refuses outbound requests to anything other than its own origin and loopback, and answers optional inference, model-catalog and vulnerability-feed routes with 503 Optional services are unavailable in the customer core profile. The service manager also limits the application services to loopback traffic. The proxy does not write access logs.

Optional container composition

The package also includes a container composition that publishes only TCP 443, pulls nothing at startup and requires a digest for every image. It is an optional path, not the primary installer, and the backup and removal scripts do not target it.

Continue readingCustomer-hosted sign-in and recovery →