Install and activate Nook
A copy-safe path from Customer Portal registration to a healthy server, first local owner, and verified backup.
Before you begin
You need:
- a Customer Portal account with a self-host organization;
- an active paid self-host entitlement (the current preview may bypass payment processing);
- an Ubuntu Server 24.04 LTS x86_64 host that passed the planning checklist;
- root access, working DNS/TLS, and a maintenance window;
- the public API and admin HTTPS origins. An optional website origin is only a redirect alias to the admin address; it is not another application you must deploy.
- for calls, a dedicated LiveKit deployment with a public
wss://origin and reachable WebRTC media ports. LiveKit is a separate media authority; the Nook application installer does not silently create or expose one.
Use the commands shown in your Customer Portal. They are generated for the selected delivery mode and entitlement. The public blocks below explain and verify the workflow; they do not grant registry or license authority.
1. Create the commercial organization
- Open Create account → Self-hosted on the Nook landing page.
- Verify the email and protect the Customer Portal account with a passkey and recovery codes.
- Create the commercial organization. The creator becomes its primary owner.
- Add legal/billing details and request a connected or air-gapped entitlement.
- Select the entitlement before opening Install Nook.
This account is for ownership, licensing, releases, and support. It is not the local Nook account you will use to chat.
2. Generate the one-time installer
Select the entitlement in Customer Portal → Set up Nook, enter the distinct API and admin HTTPS origins and the instance name, and optionally add a website redirect alias. Then choose Generate install command. The Portal issues a short-lived, single-use download grant bound to that entitlement and exact signed installer artifact.
Before issuing the first grant, Portal saves one tenant-scoped, non-secret install intent for the
installation project and entitlement generation: exact release and artifact binding, public
origins, instance name, and TLS mode. A reload restores those values read-only. Generate a fresh
one-use grant to resume the same intent; Portal stores no grant plaintext. A changed value or
signed-artifact mismatch fails closed until an explicit entitlement rebind and project restart.
Initial connected-install and air-gapped artifact grants remain available in pending_activation,
active, grace, and restricted entitlement states so a restricted deployment can retrieve an
authorized recovery artifact. Connected update grants require active, grace, or restricted.
Revoked, expired, delivery-mode-changed, entitlement-generation-changed, or closed installation
project authority is rejected, including a grant that was issued before the change.
Copy the secure install command exactly as Customer Portal displays it; do not reconstruct it from
the downloaded archive. Copy the one-use grant separately and paste it only into the command’s
hidden prompt. The command passes the Portal-authorized SHA-256 and exact artifact size into a
trusted root shell. Root accepts only a canonical, credential-free HTTPS download URL, creates a
private disk-backed /var/tmp/nook-installer.* staging directory, and streams the response into a
new mode-0600 file opened with exclusive-create and no-follow protections. It enforces the exact
byte count and SHA-256 while streaming, removes a partial file on failure, rejects unsafe TAR
members, checks free space, and executes only the protected install-connected-bundle.sh. It never
executes a user-writable extracted script or puts the large bundle on /run tmpfs.
Portal and the release builder enforce the same outer boundary: at most 4 GiB, 512 regular-file or
directory entries, and 16 GiB of expanded content. A release that exceeds any boundary is rejected
before publication and cannot appear as an authorized installer.
For a clean install, the first disk gate is exact and artifact-specific. If / and /var/tmp are
the same filesystem, it requires 40 GiB of operational free space plus four times the installer
artifact’s displayed byte count. If they are separate, / must have 40 GiB free and /var/tmp
must have the four-times-artifact staging amount. After the protected download, the command checks
remaining space again using twice the verified expanded archive size. A retry may use a smaller
phase-specific reserve only when the root-owned pending-install authority proves the exact saved
transaction and locally retained artifacts; an unknown or inconsistent state fails closed. Before
any image import, the installed verifier measures Docker’s actual storage filesystem separately
from / and /var/tmp. A pre-image phase retains the full 40 GiB safety floor. A partially imported
phase derives the remaining unique archive and image-layer bytes from the signed plan, without
double-counting shared layers. The publisher admits only bundles whose remaining image bytes,
exact protected release-input snapshot (at most 16 GiB), and exact expanded inner release (at most
8 GiB) fit the same 40 GiB host contract. Once all four exact image IDs are present, release
installation still reserves the immutable snapshot bytes on /var/tmp and expanded bytes on the
actual /opt/nook/releases filesystem, plus the 2 GiB recovery floor. After release installation,
configuration, runtime, and ingress phases require only that floor. Requirements that share one
filesystem are combined only where simultaneous remaining
bytes require it.
A resume from the protected prepared checkpoint binds the immutable snapshot and expanded-release
sizes and checks /var/tmp plus the actual /opt/nook/releases filesystem before consuming the
replacement one-use download grant.
The flow keeps the one-use grant out of the HTTP request URL, command arguments, and ordinary access logs. Root starts curl with ambient configuration disabled, places the authorization header in a private curl configuration file, removes it after the download, and unsets the shell variable immediately. Do not save, reuse, or share the grant. If it expires or was consumed, generate a new command and grant in the Portal. Extraction and execution begin only after the protected stream matches the exact Portal binding.
3. Let the installer finish
The supported connected installer performs the complete initial server-side setup:
- verifies every file in the downloaded bundle;
- installs the included, release-bound
nookctlDebian package; - installs or verifies Docker Engine and Compose on supported Ubuntu Server;
- uses each signed OCI manifest to authorize and derive its exact local Docker image ID, then stages those IDs as the release override before Compose can use them;
- verifies and stages the signed Nook release;
- creates the mode-0600 configuration with generated secrets and the Portal-provided origins;
- enables the entitlement-bound central invitation relay without placing a Resend or relay bearer credential on the customer server;
- starts Nook and proves local API/admin health;
- installs Ubuntu’s Caddy package on a clean host, publishes the managed HTTPS/API/WebSocket/admin routes, and refuses to overwrite an existing unmanaged Caddy configuration.
Under the verified wrapper, these stages use the same supported nookctl prerequisites --install
and nookctl install implementations documented for release engineering; customers do not need to
assemble their arguments manually.
Before changing the host, it refuses any platform other than Ubuntu Server 24.04 LTS x86_64,
insufficient assigned memory or free disk, an unsynchronized clock, and an unrelated or mismatched
Nook installation. It does not require a manual release path, registry password, sudoedit, or
hidden environment-file changes. A successful run ends with
Nook installation and managed HTTPS ingress are healthy.
If any installation phase stops, fix the reported host, storage, DNS, firewall, CA-trust, or port issue. Then request a fresh one-use install command for the same saved intent and run it unchanged. The installer resumes the exact recorded phase: host prerequisites, planned or partially imported runtime images, signed release publication, configuration, runtime health, or ingress health. Each retry first re-proves the Portal intent generation, package payload, trust anchors, complete signed release tree, configuration origins, TLS mode, and exact local image IDs appropriate to that phase. It refuses drift, skipped work, and a different release or origin, and never turns recovery into an implicit update. A consumed download grant is never reused.
The API hostname is dedicated to API and realtime traffic. The admin hostname serves the browser application. When a distinct website hostname was supplied, managed Caddy permanently redirects it to the admin origin. Using the admin origin for both values avoids an unnecessary third DNS record. Caddy obtains and renews publicly trusted certificates automatically when public DNS and TCP 80/443 are reachable.
The default command is safe only on a dedicated host with no existing Caddy configuration. If the host already has an operator-managed proxy, installation stops instead of overwriting it. The operator must integrate the same two loopback upstreams and headers under change control, then use the external checks below.
For private PKI, install the organization CA in Ubuntu’s system trust store before running the
installer. The runtime uses that same host trust store for connected Portal and gateway calls. For
a dedicated private/test deployment, select Internal TLS in Customer Portal before generating
the command. The protected command passes that exact choice as --ingress-tls-mode internal; it is
not inferred from the hostname. Configure private DNS first: numeric IP origins are not supported
because ordinary browser, desktop, and mobile TLS clients do not reliably send SNI for an IP URL.
An operator can re-apply the same managed mode explicitly:
sudo nookctl ingress configure --tls-mode internal
sudo nookctl ingress status
After the first successful configure, export only the public root certificate into a private operator directory and record its certificate fingerprint:
sudo install -d -m 0700 /root/nook-internal-ca-export
sudo install -m 0644 \
/var/lib/caddy/.local/share/caddy/pki/authorities/local/root.crt \
/root/nook-internal-ca-export/nook-caddy-internal-root.crt
sudo openssl x509 \
-in /root/nook-internal-ca-export/nook-caddy-internal-root.crt \
-noout -subject -fingerprint -sha256
Compare that fingerprint over an independent operator channel, then distribute the certificate as a system-trusted root through the organization’s MDM/device-management process before login. A manually imported Android user CA is not a substitute for an MDM-installed system trust anchor. Remove the client trust profile during decommission unless retention policy explicitly preserves it. Never export Caddy’s private CA key, use an insecure client flag, or disable certificate verification.
The required system service is the boot reconciliation gate and delegates to nookctl:
sudo systemctl daemon-reload
sudo systemctl enable nook.service
4. Pair the deployment once
Create the deployment-bound key locally and start the short-lived connected activation:
sudo nookctl setup preflight
sudo nookctl setup claim-issue
sudo nookctl activation key-initialize
sudo nookctl setup claim-issue
sudo nookctl activation connect \
--portal-origin https://portal.nook.cloudylake.io \
--customer-organization-id <customer-organization-uuid> \
--entitlement-id <entitlement-uuid>
Each setup claim is single-use. Paste the first claim into key-initialize, then paste the fresh
second claim into activation connect. The organization and entitlement UUIDs are identifiers, not
secrets. The private key remains on the server. nookctl displays a short user code and server
identity for verification; the connected request expires after 15 minutes.
Successful activation also supplies the signed central-gateway authority used by invitation email. No post-install environment edit, Resend key, or relay token is required for the connected path.
In the Customer Portal:
- Open the matching organization and entitlement.
- Enter the one-time code under Already have a pairing code?
- Compare deployment ID, canonical origin, and public-key fingerprint with the Ubuntu terminal.
- Approve the exact request with the passkey challenge.
- Keep the terminal open until
nookctlacknowledges the signed activation certificate.
Never approve a code received in chat or email without independently comparing the terminal details.
5. Create the first local owner
After commercial activation, provision the local runtime identity:
sudo nookctl setup claim-issue
sudo nookctl setup provision \
--email owner@example.com \
--display-name "Initial Owner" \
--organization-name "Example Organization" \
--workspace-name "General" \
--confirm-deployment <confirmation-shown-by-claim-issue>
Paste this fresh single-use claim into the hidden prompt and enter the initial owner’s password.
nookctl creates and protects the provisioning retry key itself; if the command is interrupted,
rerun the same command with a fresh claim and it safely reuses that internal key. You never need to
generate or paste an operation UUID. This creates exactly one local runtime organization, its first
workspace, and its first local owner.
Invite other runtime users later from the local self-hosted admin. Customer Portal members are never
silently copied into the local instance.
If activation is interrupted after key-initialize, issue a fresh claim, keep the existing local
deployment key, and rerun activation connect. Do not delete the key or repeat initialization just
to obtain another one-time code.
6. Enable calls, if required
Deploy a dedicated LiveKit service or approved managed LiveKit tenant before enabling calls. Its API key and secret must match the provider configuration, and its public WSS address must be reachable by every desktop and mobile client. Expose the WebRTC media ports required by your LiveKit topology through the real firewall and terminate signaling with a publicly trusted TLS certificate.
Configure only the Nook side through the supported interactive command:
sudo nookctl voice configure
sudo nookctl stop
sudo nookctl start
sudo nookctl voice status
voice configure prompts locally for the canonical wss:// origin, API key, and hidden API secret.
It writes only to Nook’s mode-0600 operator configuration, never prints either credential, and does
not place them in command arguments or shell history. voice status reports whether all three
settings are present and prints only the non-secret public URL. Partial configuration fails closed.
Configure the LiveKit signed webhook to /api/v1/voice/livekit-webhook on the public Nook API as
described by the release’s LiveKit operations guide. Do not call the integration healthy until two
independently authenticated clients have joined the same call and exchanged real media. If the
organization does not require calls yet, leave all three LiveKit settings empty; messaging, files,
notifications, and the rest of Nook remain available.
7. Verify the installation
sudo nookctl diagnostics
sudo nookctl activation status
sudo nookctl status
sudo nookctl ingress status
curl --disable --fail --silent --show-error http://127.0.0.1:3001/health/live
Then verify from a normal client network:
- trusted HTTPS with no certificate warning;
- local owner login;
- workspace and channel creation;
- local invitation email delivery and acceptance;
- text message and notification delivery;
- file upload/download according to policy;
- voice/media connectivity through the real firewall;
- privacy-minimized central notification-gateway behavior.
8. Create the first protected backup
sudo nookctl backup --output-dir /var/lib/nook/backups/initial
nookctl securely creates the absent initial leaf for the invoking sudo operator. Confirm that
the directory contains one PostgreSQL custom dump and its sibling
.nook-continuity.json manifest. Copy both together to protected off-host storage. Back up uploaded
files and the reviewed configuration through their separate documented paths.
Installation is not complete until another operator can locate the backups and the organization has scheduled a restore drill. Continue with Operate and update Nook.
Common installation stops
| Symptom | Safe response |
|---|---|
| Prerequisites reject memory or disk | Resize the host; do not bypass the gate. |
| Installer detects an existing Nook | Stop and use the documented update flow; never rerun initial installation over local state. |
| Pairing code expired | Issue a replacement request; the earlier request becomes unusable. |
| Portal details do not match terminal | Reject the request and investigate DNS, host, organization, and entitlement selection. |
| Registry token expired | Request a new short-lived credential; never turn it into a long-lived Docker password. |
| API/admin unhealthy | Keep the instance unavailable, inspect nookctl status and bounded logs, and do not invite users yet. |