Install from a package
The next release is 0.4; its GitHub release is not published yet. The commands below describe the planned artifacts. Build from source until publication, then verify each artifact before use. See docs/releases/0.4-install-surfaces.json for the observed publication state.
This is the path for a normal Linux host where you want the engine as a service, not in a container. Debian/Ubuntu and RHEL/Fedora/SUSE default to systemd. Alpine’s default init is OpenRC, not systemd. For containers see Docker deployment; for a host with no route out at all, Install in an air-gapped environment, which this page links back to at the upgrade step.
1. Verify the release before you trust it
Section titled “1. Verify the release before you trust it”For a security product the build pipeline is part of the trust model, so nothing here asks
you to take the download on faith. Put the package, checksums.txt and the signature in one
directory and run the verifier from that directory:
# The verifier is in a source checkout of the release tag, not a release asset; running it# trusts the checkout. Without one, INSTALL.md shows the cosign + sha256sum commands.# keyless / Sigstore (default; reaches Rekor over the network)/path/to/olivares/scripts/verify-release.shReleases are signed keyless and do not publish a cosign public key, so use the keyless command
for packages downloaded from a release. It needs Sigstore trusted-root material, which cosign
fetches unless it is already cached. --offline removes only the Rekor lookup; it does not make
verification network-free. --key is only for files signed with a private key you control, and
you must obtain that public key separately from the files it verifies.
What each step checks, how it behaves on a partial release, and how to verify the container image instead is Verify what you downloaded.
2. Install the package
Section titled “2. Install the package”The three package formats carry the binary at /usr/bin/olivares, a commented
environment file at /etc/olivares/olivares.env (marked config|noreplace, so your edits
survive an upgrade), the data directory /var/lib/olivares, and the licence texts —
LICENSE, NOTICE, LICENSING.md, DISCLAIMER.md — under /usr/share/doc/olivares/.
.deb and .rpm ship the hardened systemd unit at
/usr/lib/systemd/system/olivares.service. The .apk puts an executable OpenRC unit at
/etc/init.d/olivares, with an explicit package-init stamp so hooks do not guess from host
systemctl presence. The Linux archives carry the same service adapters:
scripts/install-service.sh and packaging/service/.
# Debian / Ubuntusudo dpkg -i olivares_0.4_linux_amd64.deb
# RHEL / Fedora / SUSEsudo rpm -Uvh olivares_0.4_linux_amd64.rpm
# Alpinesudo apk add --allow-untrusted olivares_0.4_linux_amd64.apkInstalling creates the system user and group olivares (with /usr/sbin/nologin as
its shell and /var/lib/olivares as its home), creates /var/lib/olivares mode 0750
owned by that user, and creates /etc/olivares. systemd packages reload systemd when
systemctl is present; OpenRC packages do not enable or start the service. It does
not start anything — see what the package does not do.
Start the engine
Section titled “Start the engine”On Debian/Ubuntu and RHEL/Fedora/SUSE:
sudo systemctl enable --now olivaresOn OpenRC (.apk built from this source):
sudo rc-service olivares start# optional; the package does not do this:sudo rc-update add olivares defaultThe first-boot token is in /var/log/olivares.log (and logread if syslogd is
running). Extra flags in
OLIVARES_EXTRA_ARGS are appended with globbing disabled and split on spaces;
nested quoting is not interpreted, and the env file is not sourced as shell.
On the previously published Alpine package, systemctl is absent and that .apk has no OpenRC
unit. Start the engine as the service user; the first-boot token is printed on stdout:
sudo -u olivares olivares serve --data-dir=/var/lib/olivares \ --listen=:8443 --grpc-listen=:8444 --checkpoint-interval=1h3. The hardened systemd unit
Section titled “3. The hardened systemd unit”The packaged systemd unit runs the engine as the unprivileged olivares user with an empty
capability bounding set — it holds no capabilities at all, ambient or bounding — and
NoNewPrivileges=true, so nothing it launches can gain any. On top of that it carries
ProtectSystem=full (/usr, /boot, /efi and /etc are read-only),
PrivateDevices=true, ProtectClock=true, ProtectKernelTunables=true,
ProtectKernelModules=true, ProtectKernelLogs=true, ProtectControlGroups=true,
RestrictNamespaces=user net mnt (a session gets its own user and network namespace, and
the helper that keeps a folder’s Git hooks and configuration read-only gets its own mount
namespace, where the syscall filter allows mount; every other namespace type is denied), RestrictSUIDSGID=true, RestrictRealtime=true,
LockPersonality=true, SystemCallArchitectures=native, a @system-service syscall
filter that additionally drops @privileged and @resources, and UMask=0027.
The unit does not hide home or temporary directories, and it allows executable memory:
it sets ProtectHome=false, PrivateTmp=false and MemoryDenyWriteExecute=false. The
engine can reach whatever ordinary file permissions allow the olivares account, including
/home, /tmp and /var/tmp, so the folders you choose for sessions stay reachable. The
confinement is per session instead: before each agent tool or stdio MCP server runs, the
engine applies a Landlock policy that lets it write to its session folder, its tool home
and its temporary directory, and never reach the engine’s data directory, /etc/olivares
or the engine account’s own credentials. Node/V8 agent and MCP runtimes need executable
JIT memory, which is why MemoryDenyWriteExecute=false. On a kernel without Landlock the
engine refuses to start sessions; olivares doctor names the cause.
26.10.0 shipped a stricter unit: the whole file system read-only except the data directory,
homes hidden, a private /tmp and no writable executable memory. 26.10.1 relaxed it to the
values above. You can add any of those settings back in a drop-in (systemctl edit olivares). Session folders under homes or /tmp and JIT-based tools then stop working, and
with a read-only file system every session folder outside the data directory needs its own
ReadWritePaths= line.
On default Alpine those systemd directives do not apply to a previously published
.apk, because that payload’s systemd unit is not running. .apk packages built from
this source run under OpenRC instead: they use the olivares account, write the
first-boot token to /var/log/olivares.log, and do not implement systemd
sandbox directives.
The listeners accept connections from the network by default — --listen=:8443 for
HTTP (REST plus the embedded console) and --grpc-listen=:8444 for gRPC, the dual-stack
wildcard. This is a server, and what protects it is TLS on, no default credentials and a
single-use setup token. Restrict it deliberately with
OLIVARES_EXTRA_ARGS=--listen=127.0.0.1:8443 --grpc-listen=127.0.0.1:8444 in
/etc/olivares/olivares.env — those flags are appended after the unit’s own and the later
flag wins — and front the result with your own TLS termination for a certificate browsers
trust. For IPv6 loopback use --listen=[::1]:8443.
Executable scratch mount
Section titled “Executable scratch mount”This is the failure worth knowing in advance on a systemd host, because the symptom does not name its cause.
Out-of-process first-party connectors ship embedded in the binary. At boot the engine
extracts the ones it needs into private scratch and executes them as subprocesses. When
TMPDIR is unset, scratch is created under <data-dir>/tmp; only an unwritable data
directory makes the engine fall back to the system temporary directory. An explicit
TMPDIR always wins.
The packaged systemd service therefore uses /var/lib/olivares/tmp, not /tmp, by default.
Check the mount that will actually hold the executable scratch:
check_scratch_mount() { target=${1:-/var/lib/olivares} opts=$(findmnt -no OPTIONS --target "$target") || { printf '%s\n' "cannot read mount options for $target (missing path or permission)" >&2 return 1 } [ -n "$opts" ] || { printf '%s\n' "mount options for $target are unknown" >&2 return 1 } case ",$opts," in *,noexec,*) printf '%s\n' 'noexec — set TMPDIR' ;; *) printf '%s\n' 'exec-capable — nothing to do' ;; esac}check_scratch_mount /var/lib/olivaresIf it says noexec, point TMPDIR at a directory that the olivares user can write
and that lies on an exec-capable mount:
sudo install -d -o olivares -g olivares -m 0750 /run/olivares-exec-tmpsudo systemctl edit olivares # creates a drop-in; do not edit the shipped unit[Service]Environment=TMPDIR=/run/olivares-exec-tmpReadWritePaths=/run/olivares-exec-tmpThen restart. If an exec is rejected with EACCES or ENOEXEC, the engine’s error names
the extraction mount and the two relocation controls (TMPDIR and data-dir); it does not
report a noexec mount as a missing connector.
Use systemctl edit, never a direct edit of /usr/lib/systemd/system/olivares.service:
that file belongs to the package and an upgrade replaces it.
4. First boot: olivares quickstart
Section titled “4. First boot: olivares quickstart”quickstart is serve with friendly defaults and a guided banner. It never invents
default credentials; it points you at the embedded console to create your first
administrator with a one-time token.
Running under the packaged systemd unit you are already serving, so you do not run
quickstart — the first-boot setup token is printed to the journal:
journalctl -u olivares | sed -n '/FIRST-BOOT SETUP/,/========================/p'If you started serve in the foreground (default Alpine), the same banner is on stdout.
Open the console at https://127.0.0.1:8443 (a self-signed certificate is generated on
first start), present that token, and create the administrator. The token is single-use.
On a workstation, to look around without installing a service, olivares quickstart does
the same thing in the foreground with --listen/--grpc-listen/--data-dir if you need
to move it off the defaults.
5. Your first source: pgAudit
Section titled “5. Your first source: pgAudit”A source is where the engine ingests observations from. The verbs are split by what each one
costs, and it is worth using them in that order: plan says what would change and writes
nothing, validate says the configuration is coherent by itself without touching the
network, test opens the source for real to prove it answers, and set applies.
Configuration carries secret references (store:<name>), never values.
pgAudit reads the PostgreSQL audit log, so log_path is the only required field:
# coherent by itself? (writes nothing, opens no socket)sudo -u olivares olivares sources validate --name pg-prod --kind pgaudit \ --tenant <your-tenant-id> \ --config log_path=/var/log/postgresql/postgresql.log \ --data-dir /var/lib/olivares
# does it actually answer? (opens the source for real)sudo -u olivares olivares sources test --name pg-prod --kind pgaudit \ --tenant <your-tenant-id> \ --config log_path=/var/log/postgresql/postgresql.log \ --data-dir /var/lib/olivares
# apply itsudo -u olivares olivares sources set --name pg-prod --kind pgaudit \ --tenant <your-tenant-id> \ --config log_path=/var/log/postgresql/postgresql.log \ --actor "$(id -un)" --reason "onboard the production audit log" \ --data-dir /var/lib/olivaresThree things the command line above is not padding:
--tenantis required. A source must name the business tenant its observations belong to; without it the command refuses rather than guessing an owner for your audit data.--actorand--reasonare required byset, and only byset. A privileged offline operation has to record who did it and why.validateneeds neither, because it writes nothing — the asymmetry is the point.formatdefaults tocsvlogandfollowtotrue, so a standard pgAudit deployment needs neither.
Applying prints what changed, field by field, and tells you how to make a running engine
pick it up without a restart — POST /v1/console/runtime/reload, or a SIGHUP. Under the
packaged systemd unit that is sudo systemctl reload olivares. If you started serve in
the foreground, send SIGHUP to that process.
The service user needs read access to that log file; on most distributions that means adding
olivares to the adm or postgres group — a deliberate grant you make, not something the
package does for you.
6. Upgrading
Section titled “6. Upgrading”From the package repository (apt and dnf)
Section titled “From the package repository (apt and dnf)”A host that adds the repository takes each Olivares release with the operating system’s own
updates. apt verifies the signed repository metadata, which carries the hash of every package;
dnf verifies that metadata and the signature of each package. The repository carries amd64
and arm64 for apt and x86_64 and aarch64 for dnf. For apt the file you download names the
repository and carries the signing key. For dnf you first store the key, then download the file
that names it.
# Debian / Ubuntu (apt 2.4 or later)sudo apt-get update && sudo apt-get install -y ca-certificates curl gnupgsudo curl --proto '=https' --tlsv1.2 -fsSL https://packages.olivares.ai/olivares.sources -o /etc/apt/sources.list.d/olivares.sourcessudo apt-get update && sudo apt-get install olivares
# AlmaLinux / RHEL / Fedorasudo curl --proto '=https' --tlsv1.2 -fsSL https://packages.olivares.ai/olivares-packages.asc -o /etc/pki/rpm-gpg/RPM-GPG-KEY-olivares-package-repositorysudo gpg --show-keys --fingerprint /etc/pki/rpm-gpg/RPM-GPG-KEY-olivares-package-repositorysudo curl --proto '=https' --tlsv1.2 -fsSL https://packages.olivares.ai/olivares.repo -o /etc/yum.repos.d/olivares.reposudo dnf install olivaresWhat you trust. The key comes from the same address as the file, so the host trusts
packages.olivares.ai on first use. The fingerprint below is the one check that does not depend on
that address. Compare it before you install; gpg prints it in groups of four.
curl --proto '=https' --tlsv1.2 -fsSL https://packages.olivares.ai/olivares-packages.asc | gpg --show-keys --fingerprint# fingerprint: AE27B5B818C9BCFE485B4D8B155E5EC6550A6EF8On dnf, the second command prints the fingerprint of the key you stored, and dnf shows it again
when it imports that key on the first install: compare both with the one above, and do not add -y
to that first install. dnf keeps the keys it imports, in the rpm database, where a key applies to
every repository on the host that checks signatures, and under /var/cache/dnf; dnf clean all
does not remove them. The repository file you installed names the stored key file and no address,
so a later dnf upgrade, with or without -y, and dnf-automatic never ask the repository for a
key: metadata signed by another key is refused. To move to a new key, compare its fingerprint and
replace that file yourself. After that, sudo apt-get update && sudo apt-get upgrade and
sudo dnf upgrade move the host to the newest release, and dnf-automatic does it on a schedule.
unattended-upgrades takes only the origins you allow; add Olivares, bound to its address, with a
drop-in:
Unattended-Upgrade::Origins-Pattern { "origin=Olivares.AI,suite=stable,site=packages.olivares.ai"; };Use one updater per host. A host installed from a package or from the repository updates with
its package manager (apt, dnf, apk, or a newer package file); olivares upgrade refuses
to replace the package-owned binary, as the next section says.
olivares upgrade on a package install
Section titled “olivares upgrade on a package install”The package manager owns /usr/bin/olivares on every package install (deb, rpm, apk, AUR).
Replacing that file in place would leave the package database describing a file it no longer
has, so olivares upgrade refuses: it exits 2 before it downloads anything and names the
package route. Upgrade with the package manager, as above. olivares upgrade --check still
works; it shows the plan and changes nothing:
sudo olivares upgrade --check # what would change, without changing anythingWhere no package manager owns the binary (one placed by install.sh or by hand),
olivares upgrade replaces it in place, and the safety properties are the reason to use it:
it never replaces the binary until the downloaded candidate has been exec-probed
successfully, it keeps a timestamped backup, and it reverts to that backup if the
post-swap probe fails. --target <path> is the operator override: it replaces the file you
name, /usr/bin/olivares included, and from then on the package database no longer matches
that file.
Three flags matter to --check and to a --target run:
--endpoint— take updates from a GitHub repository you control rather than the default. This is the escape hatch for a mirror or a fork.--bundle— Offline installation requires Enterprise. Community verifies a bundle with--bundle --checkwithout reading a license or installing it.--install-timer— emit an opt-in systemd timer and service that check for updates on a schedule. Nothing installs this for you; see what the package does not do. It is a systemd generator. On a package install it refuses:/usr/bin/olivaresbelongs to the package manager, so--install-timerexits 2 and writes no unit. Upgrade with the package manager (on the Olivares appliance,systemctl start olivares-appliance-update.service).
Note that the staging and the exec-probe happen in the install directory, next to the
target — not in /tmp, so the noexec mount discussed above
does not break an upgrade. A noexec mount on the install directory is a different
matter and makes the installed version unmeasurable; that case, the release channels, staged
rollout and rolling back are Upgrade and roll back.
7. Uninstall or migrate without guessing paths
Section titled “7. Uninstall or migrate without guessing paths”The package writes /var/lib/olivares/install-manifest.json. The uninstaller validates
the complete manifest against the signed distribution index before touching the service or
filesystem; an unexpected path returns 2. Inspect first, then choose retention explicitly:
sudo olivares uninstall --plan --data-dir /var/lib/olivaressudo olivares uninstall --preserve --data-dir /var/lib/olivaressudo olivares uninstall --purge --data-dir /var/lib/olivares --yesPreserve is the package-removal policy: it retains configuration, data, logs, keys and
their service identity. On systemd packages the removal hook runs --preserve. On OpenRC
.apk packages built from this source the hook stops the service if it is active, removes
the default runlevel entry without failing if it was never enabled, validates the complete
manifest with --plan, and lets apk remove package-owned files. Previously published Alpine
packages validated with --plan only, because that payload had no OpenRC unit to stop.
Run --purge before removing the package only when erasure is the intent. It requires
confirmation and deletes only indexed paths.
For an estate move, create an olivares dr backup first, install the destination and run
olivares dr restore there. Current bundles use hmac-sha256-kek-v1 to authenticate the
manifest and every payload under your KEK. A newer-engine export is refused before writes;
a separately authenticated pre-v26.9 bundle needs --allow-legacy-unsigned explicitly.
The backup and restore guide covers KEK custody and the
post-import continuity proof.
8. What the package does not do
Section titled “8. What the package does not do”Stated plainly, because a security product that is vague here does not deserve the install:
- It does not add a repository. Nothing is written to
/etc/apt/sources.list.d,/etc/yum.repos.dor/etc/apk/repositories. You installed one file; only that file was installed. Upgrades are yours to trigger: by a new package, or by adding the package repository yourself;olivares upgraderefuses to replace a package-owned binary. - It does not start or enable the service. systemd packages reload systemd when
systemctlis present and printsystemctl enable --now. OpenRC packages printrc-service olivares startand do notrc-update add. Starting remains your decision. An upgrade of an already-running OpenRC service stops it, replaces files, and starts it again; an inactive service stays inactive. - Verifying a licence never calls anyone. Downloading what you paid for does. Licence
validation in the open build is offline Ed25519, there is no remote kill switch, and no
licence key gates or degrades that build — the AGPL build is the whole platform.
There is no mandatory telemetry and no control-plane egress by default: what crosses
your perimeter is what you configure to cross it — calls to your model APIs, the
SIEM/webhook outputs you wire, an external embedding provider if you provision one, and
any source a connector polls (its
addr,base_urlorendpoint) at the interval you set. - But
olivares upgradedoes make a network call, deliberately, when you run it — that is the point of an update check, and--checkshows you the plan before anything moves. The honest form of the promise is: verifying a licence never calls anyone; downloading what you paid for does. Use--bundleif you want the update path to make no call either. - It opens a port to the network. The unit binds every interface until you restrict it yourself.
See also
Section titled “See also”- Verify what you downloaded — the full verification path
- Upgrade and roll back — channels, staged rollout, rollback
- Harden a deployment — beyond what the unit already does
- Install in an air-gapped environment
- Deploy with Docker
- Connect a source
- Back up and restore