nivq
This install section is for Enterprise / on-prem customers who self-host nivq.

Bare metal (JAR + systemd)

Run nivq directly on a Linux host with a Java runtime — no container engine. Install the JAR, configure it, and run it as a systemd service.

If your policy rules out a container engine, nivq runs as a plain executable JAR on a Linux host with a Java 25 runtime. You bring your own PostgreSQL (with pgvector) and Redis/Valkey (see Requirements); nivq is a single process you supervise with systemd. It runs in production mode by default — there's no profile or mode flag to set.

1. Install a Java 25 runtime

Any build works; the official image uses Eclipse Temurin.

Shell
# Debian/Ubuntu example  install a JDK/JRE 25 from your distro or Adoptium
java -version    #  openjdk version "25"

2. Download the JAR and lay out the directories

The JAR lives in the same registry as the container image: ghcr.io/nivorbit/jars/nivq. Log in with oras and pull it:

Shell
oras login ghcr.io -u <username> -p <token>
oras pull ghcr.io/nivorbit/jars/nivq:0.2.4     #  nivq-0.2.4.jar

No token yet? Ask the Nivorbit team or email [email protected]. Air-gapped? Get the JAR as a file and copy it to the host — skip this step.

Then create a dedicated user and a place for it:

Shell
sudo useradd --system --home /opt/nivq --shell /usr/sbin/nologin nivq
sudo mkdir -p /opt/nivq /etc/nivq
sudo cp nivq-0.2.4.jar /opt/nivq/nivq.jar
sudo chown -R nivq:nivq /opt/nivq /etc/nivq

3. Provision the datastores

Point nivq at a reachable PostgreSQL 16+ with the pgvector extension and a Redis 7+ / Valkey. They can be on the same host or managed elsewhere — nivq just needs the connection details, which go in the env file next.

4. Create the environment file

nivq is configured entirely through environment variables. Put them in /etc/nivq/nivq.env (root-owned, readable only by the service user, since it holds secrets):

Shell
# datastores
NIVQ_DATASOURCE_URL=jdbc:postgresql://localhost:5432/nivqdb
NIVQ_DATASOURCE_USERNAME=nivq
NIVQ_DATASOURCE_PASSWORD=a-strong-value
NIVQ_REDIS_HOST=localhost
NIVQ_REDIS_PORT=6379

# 32-byte base64 key (AES-256)  back this up; losing it is unrecoverable
NIVQ_ENCRYPTION_KEY_V1=base64-32-bytes-here

# platform-managed LLM
NIVQ_PLATFORM_LLM_PROVIDER=anthropic
NIVQ_PLATFORM_LLM_API_KEY=sk-...

# first sign-in without an IdP  wire OAuth/OIDC later, see Authentication
NIVQ_BOOTSTRAP_ADMIN_USERNAME=admin@example.com
NIVQ_BOOTSTRAP_ADMIN_PASSWORD=a-long-passphrase

# public URLs
BACKEND_URL=https://api.example.com
FRONTEND_URL=https://app.example.com

# optional: seed a licence from a file instead of uploading it later
# NIVQ_LICENSING_LICENSE_FILE=/etc/nivq/license.jwt
Shell
sudo chown nivq:nivq /etc/nivq/nivq.env
sudo chmod 600 /etc/nivq/nivq.env

The full set of variables — SSO, per-agent LLMs, embeddings, payments, observability — is in Configuration.

5. Run it directly

That's all it takes — nivq runs straight from the JAR:

Shell
sudo -u nivq env $(grep -v '^#' /etc/nivq/nivq.env | xargs) \
  java -XX:+UseZGC -XX:MaxRAMPercentage=75.0 --enable-native-access=ALL-UNNAMED \
  -jar /opt/nivq/nivq.jar

The first boot runs database migrations. In another shell, curl http://localhost:8080/actuator/health returns {"status":"UP"}. This runs in the foreground — perfect for a first check. For an always-on service that restarts on failure and starts with the host, wire up systemd below (Ctrl-C to stop the foreground run first).

6. Run it as a systemd service

Create /etc/systemd/system/nivq.service:

ini
[Unit]
Description=NivQ API
After=network-online.target
Wants=network-online.target

[Service]
User=nivq
Group=nivq
EnvironmentFile=/etc/nivq/nivq.env
ExecStart=/usr/bin/java -XX:+UseZGC -XX:MaxRAMPercentage=75.0 --enable-native-access=ALL-UNNAMED -jar /opt/nivq/nivq.jar
SuccessExitStatus=143
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Then enable and start it:

Shell
sudo systemctl daemon-reload
sudo systemctl enable --now nivq
sudo systemctl status nivq
journalctl -u nivq -f          # follow the logs

7. Activate the licence

If you didn't set NIVQ_LICENSING_LICENSE_FILE, nivq is activation-pending. Read the fingerprint and upload the licence Nivorbit returns:

Shell
curl http://localhost:8080/v1/license/fingerprint     # → NIVQ-FP-...
curl -F "[email protected]" http://localhost:8080/v1/license/upload

The licence is stored in the database, so it survives restarts and JAR upgrades. See Licensing & activation for the full lifecycle.

8. Put TLS in front

nivq listens on plain HTTP on port 8080. Terminate TLS at a reverse proxy (nginx, Caddy) and set BACKEND_URL / FRONTEND_URL to the public HTTPS URLs. To upgrade later, stop the service, swap the JAR, and start it again. See Production hardening for the proxy, backups, and observability.

9. Serve the web client

The JAR is the API only; your users need the web client (the browser UI). On bare metal you have two options:

  • Run the container — if a container runtime is available just for this, run the static UI image pointed at the API:

    Shell
    docker run -d --name nivq-web -p 3000:8080 \
      -e NIVQ_API_BASE_URL=https://api.example.com \
      ghcr.io/nivorbit/images/nivq-web:0.2.2
  • Serve the static files — no container at all: take the dist/ bundle, drop a config/default.json beside it pointing at your API, and serve it from the nginx/Apache you already run. Starter configs ship in deploy/nginx.conf and deploy/apache.conf.

Serve it at exactly the API's FRONTEND_URL so sign-in works. Full details — config fields and the auth wiring — are in Web client.