Installing a server
Two procedures, one from the Linux kit and one from the container image, then what both share: the state directory, the first boot, the first tenant, and what to check before calling an installation done. The platforms each form runs on are on Requirements.
The kit and the container image are available only to holders of a licence or a contract with the supplier: see Licence.
The platform is one process. There is no cluster to join, no agent to install on the machines it talks to, and nothing to configure in a message broker before the first delivery. What follows is the whole installation.
On Linux, from the kit
The kits run only on Linux, and the archive’s architecture must be the host’s. uname -m on the
host names it: x86_64 takes the amd64 kit, aarch64 the arm64 kit. A mismatch shows at
step 3. exec format error means the kit was run on a system that is not Linux, or on the other
architecture; rosetta error: failed to open elf at /lib64/ld-linux-x86-64.so.2 means an amd64 kit
was run in an arm64 Linux container on a Mac. On a Mac, see
On a Mac, for evaluation.
-
Verify the kit you received: Verifying a kit gives the commands, offline.
-
Extract it into
/opt/nexus, so thatnexusandui/land there. The archive holds one directory,nexus-<version>-linux-<arch>/, which--strip-components=1removes:Terminal window install -d -m 0755 /opt/nexustar -xzf nexus-<version>-linux-<arch>.tar.gz -C /opt/nexus --strip-components=1 -
Check the program:
/opt/nexus/nexus --versionprints the version of the release. -
Create the state directory and install the service unit.
What goes on disk
Two things, in the same directory:
/opt/nexus/ nexus # the executable ui/ # locales/ templates/ static/ — the management UI's assetsui/ beside the executable is the shipping layout and the one the binary looks for. Put it elsewhere
and name the path in NEXUS_UI_ASSETS_DIR. A ui/ that is present but incomplete stops the
start instead of quietly falling back to another path — a half-finished install must not come up
serving a UI with no stylesheet. Whichever rule won is announced at boot, because from the outside the
three of them are invisible:
INFO nexus_ui::assets: UI assets path=/opt/nexus/ui origin=the `ui/` directory beside the executableOne extra tool is worth installing: sqlite3. The server does not need it — SQLite is compiled
into the binary — but the backup procedure is written with it. See
Backup and restore.
A service unit
[Unit]Description=NexusFabricAfter=network.target
[Service]User=nexusGroup=nexusWorkingDirectory=/var/lib/nexusEnvironment=RUST_LOG=infoEnvironmentFile=/etc/nexus/nexus.envExecStart=/opt/nexus/nexus serve --host 127.0.0.1 --port 9090 --db /var/lib/nexus/registry.dbRestart=on-failureRestartSec=5
[Install]WantedBy=multi-user.targetRestart=on-failure, not Restart=always. A start that fails on configuration — a missing
NEXUS_CONFIG_* a flow declares, a state key that is not there — has to stay down and visible rather
than loop every five seconds with the reason scrolling past. The refusal names what is missing; it is
in the log the first time.
Secrets and configuration go in EnvironmentFile. The binary also reads a .env from its working directory
(under the conditions on .env), but it does not override
variables already in the environment, so EnvironmentFile wins — which is the order you want. .env is a development convenience.
In a container, from the image
-
Log in to the registry with the access the supplier gave you:
Terminal window docker login ghcr.io -
Pull the image of the release:
Terminal window docker pull ghcr.io/iello/nexusfabric:<version>Verifying the image checks its signature.
-
Run it with its
/datavolume, as below.
The container form
The image carries the same two things, at /usr/local/bin/nexus and /usr/local/bin/ui/: a
different path, the same rule, so NEXUS_UI_ASSETS_DIR is not needed. State lives under /data,
which is the volume, and --db /data/registry.db is already the image’s default command.
docker run --rm -p 9090:9090 -v nexus-data:/data ghcr.io/iello/nexusfabric:<version>The process runs as an unprivileged user (uid 10001), which is why the port is 9090 and not 443, and
why the volume is created owned by that user rather than by root. The entrypoint is nexus, so
every command in this manual runs in the container as docker exec <container> nexus ….
services: nexus: image: ghcr.io/iello/nexusfabric:<version> volumes: - nexus-data:/data ports: - "9090:9090" environment: NEXUS_UI_ADMIN_USER: admin NEXUS_UI_ADMIN_PASS: change-me-before-first-boot RUST_LOG: info restart: unless-stopped
volumes: nexus-data:Replace the NEXUS_UI_ADMIN_PASS shown with a password of your own: the example value stops the
start.
Two translations hold for the rest of the operator pages: where a procedure says
systemctl stop nexus, read docker stop; where it says nexus …, read
docker exec <container> nexus …. The backup is the one place that needs more than a translation,
because of file ownership on a fresh volume — it says so on its own page.
No healthcheck is declared in the image, on purpose: the runtime image carries no HTTP client to ask
with. An orchestrator uses its own check against /health.
On a Mac, for evaluation
A Mac does not run the kit directly, on an Intel or an Apple silicon processor. It runs NexusFabric inside a Linux container, through a container engine such as Docker Desktop.
The simplest way is the image: follow In a container, from the image as written. The engine pulls the variant of the Mac’s architecture, linux/arm64 on Apple silicon and linux/amd64 on Intel.
The other way is the kit, inside a Linux container of the same architecture as the Mac, with
glibc 2.36 or later (debian:12, for example): the arm64 kit on Apple silicon, the amd64 kit on
Intel. On Linux, from the kit then runs inside that container.
Either way, this is for evaluation. A production installation runs on a Linux host.
The state directory
There is no separate setting for it. Everything derives from --db: with
--db /var/lib/nexus/registry.db every other file the installation owns lands in that parent
directory. What lands there, file by file, is in
Where state lives.
install -d -o nexus -g nexus -m 0750 /var/lib/nexusThe mode carries weight. That directory holds the API keys as blake3 fingerprints, the audit chain,
and — for any flow deployed with log_level: full — message payloads in the clear. 0750 and a
dedicated user is the shape the rest of this manual assumes.
When the directory does not exist, nexus creates it 0700, together with any missing parent, so
the first command never leaves it open whatever the umask. Every command that opens the registry,
nexus serve and nexus config check included, refuses a state directory that any other account
of the host can reach, before it creates a file in it or binds a port:
state directory /var/lib/nexus is open to other accounts of this host (mode 0755); close it with chmod o-rwx /var/lib/nexus and run the command againchmod o-rwx on that directory is the remedy; nexus never changes the mode itself. Group bits are
your choice and are accepted: 0750, 0770 and a setgid 2770 all pass.
First boot
sudo -u nexus /opt/nexus/nexus serve \ --host 127.0.0.1 --port 9090 \ --db /var/lib/nexus/registry.db--host 127.0.0.1, not the default 0.0.0.0: the platform speaks plaintext HTTP and TLS terminates
in front of it. What the proxy has to do, and what it must leave alone, is
The gateway boundary.
The start prints what it opened, what it resolved and what it refused —
Starting the server reads the boot output line by line. Two flags are
worth knowing here: --grpc-port opens the gRPC door on a listener of its own, and --port 0 asks
the system for a port, which then appears in the listening on line and nowhere else.
The state key, if any flow needs one
A flow that declares dedup_key:, correlation_open: or correlation_close: keeps its
deduplication memory and its open correlations keyed by a per-installation secret, 64 hexadecimal
characters in NEXUS_SECRET_NEXUS_STATE_KEY:
openssl rand -hex 32Four cases at startup, and only the first is an ordinary installation:
- Absent, and no deployed flow declares one of those three keys. Normal. The boot line reads
flow state (dedup + correlation): disabled — no NEXUS_SECRET_NEXUS_STATE_KEY set. - Absent, with such a flow deployed. The start is refused and the message names the flows. Those
flows declared deduplication or correlation, whose memory is keyed by this secret; running without
it would read every duplicate as a fresh delivery and run the flow again. A flow deployed into an already-running server that has no key answers
503instead, with noRetry-After— waiting a second does not produce a key. - Malformed. The start is refused whether or not anything needs it. Starting anyway would fingerprint later deliveries under a different key and split the deduplication memory in two.
- Not the key the stored flow state was written under. The start is refused while deduplication
rows or correlations are stored, and the message gives both counts: under another key none of them
matches, and every redelivered message would run again. Start with the earlier key, or start once
with
--accept-new-state-keyto replace it on purpose; the start then writesstate.key_replacedto the audit chain. The flag is refused on any start that has nothing to accept.
The first start with a key records it, as a check value in registry.db (state key: recorded in
the boot output); the key itself is never stored. While no row is stored any well-formed key is
accepted: the start records it in place of the old one (state key: replaced (0 deduplication rows and 0 correlations no longer match)), with no flag and no audit entry, since nothing stops matching.
The key is deliberately not in the databases: whoever holds the file with the fingerprints would otherwise also hold the key that made them. So it is not in a backup of the state directory either — keep it with the installation’s other secrets, and see what a restore does not bring back.
The first UI account
The management UI is served by the same process, under /ui/, on the same port. The first sysadmin
comes from NEXUS_UI_ADMIN_USER and NEXUS_UI_ADMIN_PASS on first boot — the full procedure, and
what to do with those variables afterwards, is under
The first UI account.
The first tenant and the first key
The access gate is closed by default, so a fresh installation answers /health and the UI login and
refuses everything else until a tenant and a key exist.
nexus tenant create --id acme --display-name Acme \ --db /var/lib/nexus/registry.dbnexus keys create --tenant acme --label integration --scopes '*' \ --db /var/lib/nexus/registry.dbThe raw key is printed once and never stored — the registry keeps a blake3 fingerprint of it. Scopes, per-key rate limits and flow allowlists are in Authentication.
Before you call it installed
In this order:
curl http://127.0.0.1:9090/healthanswers{"ok":true}.- The UI answers at
/ui/. - TLS terminates in front, and the proxy passes what the platform needs and strips what it must — The gateway boundary.
- The first account signs in to the UI through the TLS front. The session cookie carries
Secure, so a sign-in over plain HTTP is not the check — Management UI sign-in. nexus config checkreports nothing missing, if any deployed flow declaresconfig:.- One flow deployed, and one real message through it, with the key the callers will actually use.
- That delivery is visible in the log and in the UI — Observability.
- A backup runs on a schedule, and a restore has been rehearsed once, on this machine, from those files — Backup and restore.