Operate
Security
How Omnesis protects the data on your machines: encryption at rest and its recovery code,
the security checks omnesis doctor runs, running the gateway under a
dedicated account, and what happens to the gateway's TLS certificate after setup. It is
for whoever installs and looks after the gateway. Choosing a certificate in the first
place is covered in Setup → Certificates.
Use at your own risk. You are responsible for securing the environment where you run Omnesis, including your devices, operating systems, networks, credentials, and backups. Omnesis cannot guarantee the security of your data on a compromised system. To the extent permitted by applicable law and subject to the LICENSE, the authors and contributors disclaim liability for data loss, disclosure, or compromise caused by malicious actors, malware, viruses, or an insecure environment.
Encryption at rest
With encryption at rest, the databases, stored credentials and backups in the configuration directory are encrypted. Everything hangs off one root key per machine, held by the operating system's keyring (macOS Keychain or Linux Secret Service) or sealed with a passphrase you supply. If the root key cannot be read, the gateway and collector refuse to start rather than open data unencrypted. The installer offers encryption on a fresh install; this section covers turning it on later, headless machines, and recovery.
Turn it on
omnesis secure is the guided path. It inspects the install, takes a backup
(through the running gateway, or an offline copy), creates the root key, prints a recovery
code, encrypts the secret files that already exist, prepares the keys each store is opened
with, and restarts the gateway or tells you to. On a machine that only runs a collector
there are no gateway databases, so it prepares the collector's keys and restarts the
collector instead. Run again on an install that is already encrypted, it changes nothing:
no backup and no restart. An encrypted install that has no recovery code yet, such as one
armed with a passphrase file you supplied, gets one, still with no backup and no restart.
It works out the machine's role from the configuration directory;
--host gateway, --host collector or
--host all overrides that, for example when the gateway's database lives
elsewhere. --dry-run prints the plan without changing anything. When the
gateway was not running, the backup is an offline snapshot of the database files;
--rollback --yes, run with the gateway stopped, puts that snapshot back if
the database step went wrong. A backup taken through the running gateway is restored with
omnesis restore instead (see Restore).
--verify checks, without changing anything, that the root key and store keys
exist, every secret file is encrypted, and the running gateway's database is no longer
plaintext.
❯ omnesis secure --dry-run
❯ omnesis secure
❯ omnesis secure --verify
Encryption in Docker
On a Docker install, run omnesis secure on the machine that runs the
containers, as any other command. A container has no OS keyring, so it uses the
passphrase backend. When no passphrase is configured, it generates an
owner-only passphrase file at ~/.config/omnesis/keyring.pass (on a machine
that only collects, beside its docker-compose.yml) and records it in the
.env the containers read at start. A passphrase file you name with
OMNESIS_KEYRING_PASSPHRASE_FILE must sit inside the configuration directory,
the one directory the containers see.
The steps then run in the same order as on any machine: backup, root key, recovery code,
secret files and store keys. A container cannot restart itself, so the
omnesis command on the machine restarts the gateway and collector containers
once the steps succeed, and then runs omnesis secure --verify. An install
whose omnesis command predates this prints the
docker compose … restart command to run instead; omnesis update
brings that command up to date (see
Docker installs).
The steps it runs are also available one by one:
-
omnesis keyring initcreates the root key in the OS keyring. On Linux this needs libsecret'ssecret-tooland an unlocked, persistent login keyring. -
omnesis keyring migrateencrypts existing credential, token, sign-in state and config-secret files in place, and moves API keys written inline inomnesis.jsoninto encrypted config-secret files. -
omnesis keyring storage-statusreports which stores are encrypted, andomnesis keyring storage-initprepares their keys before a restart. Both take--host gateway|collector|all. Each process also creates any store key it lacks at start, and each store is encrypted as it next opens.
The encrypted analytics database needs DuckDB's signed httpfs extension.
Omnesis ships the build pinned for its DuckDB version: the Docker images carry it, and
source and package installs fetch it once while installing and verify its checksum. The
gateway loads that copy, so encrypted analytics opens without network access. Should it be
missing, the gateway downloads the extension beside the analytics database on first open
and says so in its log; re-running the installer or update restores the shipped copy.
Headless machines: the passphrase backend
A server or container with no desktop keyring uses the passphrase backend:
set OMNESIS_SECRET_STORE=passphrase and supply a passphrase at every start.
Keyring entries are then sealed on disk under a key derived from it, and the passphrase
itself is never stored. There are three ways to supply it:
| Source | How | Use for |
|---|---|---|
| systemd credential |
omnesis service install --secret-store passphrase
--keyring-passphrase-credential <abs-path>
adds a LoadCredential=omnesis-keyring-passphrase line to the unit
|
Linux services (systemd 247 or newer; older versions ignore the line and the daemon starts without its passphrase) |
| File |
OMNESIS_KEYRING_PASSPHRASE_FILE, or
--keyring-passphrase-file <abs-path> on
service install and the installer
|
macOS services, containers, a fresh headless install |
| Environment | OMNESIS_KEYRING_PASSPHRASE |
A process you start by hand |
Keep the passphrase file owner-only: systemd reads a credential whatever its mode, but any
local account can read a world-readable file. For a credential tied to this machine's TPM,
encrypt the file with systemd-creds encrypt first. When the configuration
directory already uses an OS keyring, service install detects it and needs no
flag. omnesis doctor warns about a unit that selects the passphrase backend
without naming a passphrase, which would otherwise fail later on the first encrypted
store.
Recovery code
Losing the root key means losing every encrypted store and every encrypted backup made
with it. omnesis keyring export-recovery writes a recovery envelope into the
configuration directory and prints a one-time recovery code. Keep the code somewhere other
than this machine. On a new machine, omnesis keyring import-recovery rebuilds
the root key from the envelope and the code. omnesis restore --code does the
same while restoring a backup, using the envelope the backup carries (see
Restore). Backups never contain the root key itself.
❯ omnesis keyring export-recovery
Collectors on other machines
A collector on another machine has its own root key and its own store keys; pairing gives
it a gateway credential, never the gateway's keys. The installer's collector role runs
omnesis keyring init and
omnesis keyring storage-init --host collector, so a fresh collector opens its
encrypted stores (such as the WhatsApp archive and the iMessage transcript cache) without
a gateway on its machine.
When encryption is on and the root key cannot be read, the collector refuses to start and names the fix. Restore or unlock a missing key rather than deleting files to get past the error: a bank connection's saved session, for example, may hold history the bank will not provide again.
What encryption at rest does not cover
Some imports work on short-lived plaintext copies: browser-history and Screen Time
snapshots, and WhatsApp backup imports, use temporary SQLite files in owner-only folders.
They are removed when the operation finishes, fails or is cancelled; a killed process can
leave them until a later operation cleans up. Transcription decodes an MP4-family
recording (such as an .m4a voice memo) from a copy in an owner-only temporary
folder, removed when decoding ends; a gateway killed mid-decode can leave it in the system
temporary directory. Deleting a file is not secure erasure.
The source originals Omnesis reads, logs, filesystem snapshots and swap are outside Omnesis's control. Full-disk encryption (FileVault on macOS, LUKS on Linux) remains what protects a machine that is stolen while powered off. The vector index file is a rebuildable cache; with encryption on, Omnesis keeps an encrypted copy of it so a restart does not rebuild it.
Security checks
omnesis doctor checks this host's security posture by default. The checks are
local and read-only, so they run even when the gateway is down; --no-security
skips them. On a collector the same checks describe the collector's own stores and
service.
| Check | What it looks at |
|---|---|
| Permissions |
The configuration directory and its files are owner-only. Repair drift with
omnesis doctor --fix-permissions.
|
| Full-disk encryption |
Whether FileVault or LUKS is on, or could not be confirmed. A Docker install
reports the host's disk, which its omnesis command reads on the host.
|
| Service hardening | Whether the installed service units carry the expected restrictions. A Docker install has none: Docker runs and restarts its containers. |
| Gateway isolation | Whether the gateway runs as your login user or a dedicated account. |
| Keyring | Whether the root key exists and can be read, and whether each service unit is wired to the backend it names. |
| Recovery code | Whether a recovery envelope has been exported, and whether it is intact. |
| Store encryption | Whether each database or provider store is encrypted, still plaintext, or locked. |
--fix-permissions keeps directories and managed executables owner-only and
restricts other files to owner read and write. The portal's
Debug → System → Health page shows the same checks but cannot repair
anything.
Hardened gateway
By default both daemons run as your login user. Owner-only file modes keep other OS
accounts out, but not other programs running as you: any of them can read the gateway's
databases. On Linux with systemd, the gateway can instead run as a dedicated account that
systemd allocates each time it starts (DynamicUser=), with all of its state
(databases, index, certificate, tokens, models) under
/var/lib/omnesis-gateway, unreadable by your account.
That separation holds only if your account also cannot change the code the gateway runs.
So root fetches a release, builds it and installs it under
/opt/omnesis-gateway, where only root can write. A program running as you can
then neither read the corpus nor alter the code that reads it. Root still can, and anyone
who compromises the gateway process holds what the gateway holds. On a single-user machine
where nothing untrusted runs under your account, the default services are a reasonable
choice.
Hardened mode needs Linux with systemd. macOS has no equivalent: run the gateway as your user, or in Docker, which separates it from your other programs in a different way. Collectors never move to the dedicated account and never run as root, because they read your data with your permissions; a Mac collector pairs with a hardened Linux gateway over the network like any other collector.
Installing
On a Linux host run by systemd, an interactive install of a new gateway asks which account
should run it; --hardened and --no-hardened answer that for an
unattended install. The dedicated account installs the CLI as you and prints one command
to run as root; the installer never runs sudo itself.
omnesis service install gateway --hardened prints the same command.
❯ omnesis service install gateway --hardened
The dedicated gateway runs from a copy of Omnesis that root fetches and owns, so installing it takes one command as root: curl -fsSL https://omnesis.dev/hardened-gateway.sh | sudo sh -s -- install --version X.Y.Z
Run as root, that command:
- fetches the release with git hooks disabled (reading a token from your git credential helper if the repository needs one);
- hands over to that release's own copy of the script, so the release decides how it is built;
- builds it as a throwaway account that can reach neither home directories nor the rest of the system;
-
installs the result, root-owned, under
/opt/omnesis-gateway/releases; -
puts the passphrase that seals the gateway's keys in
/etc/omnesis-gateway/keyring.pass, readable only by root, then installs and startsomnesis-gateway.service.
It needs git and a Node that only root can change, such as your distribution's under
/usr; a Node installed in a home directory (through nvm, for example) is
refused. The release is built from source, so use a Node the
source install supports: 24.16 or newer within Node 24,
or 26.1 or newer. --no-keyring installs without encryption at rest, and
--keyring-passphrase-file uses your own passphrase, which root copies into
/etc/omnesis-gateway. --port sets the gateway's port.
It is a new gateway, never your existing one moved: devices pair with it again and sources
sync into it again, and nothing in ~/.config/omnesis is copied or removed. So
--hardened is refused while a gateway service of yours is registered (remove
it first with omnesis service uninstall gateway), and together with
--docker, the client and collector roles, an agent-harness install,
--no-service and --mkcert, each with its reason. The dedicated
gateway serves its own self-signed certificate; for a browser-trusted address put a
reverse proxy in front of it (see Setup → Certificates).
Administering
Administer it with omnesis-gateway-admin, linked into
/usr/local/sbin. Its cli command runs the installed release's
omnesis as root against the gateway's state, address and keyring, so nothing
from your account runs as root. After installing, export a recovery code, install a model,
and pair this machine's collector, which stays under your account and pairs with a code
like a collector on another machine:
# as root, against the dedicated gateway
❯ sudo omnesis-gateway-admin cli keyring export-recovery --backend passphrase
❯ sudo omnesis-gateway-admin cli model install <model-id>
❯ sudo omnesis-gateway-admin cli devices pair --kind collector
❯ sudo omnesis-gateway-admin cli tls status
# as you: this machine's collector
❯ curl -fsSL https://omnesis.dev/install.sh | sh -s -- --collector --gateway-url https://localhost:7600 --trust-fingerprint sha256:<fingerprint> --code <code>
tls status shows the fingerprint the collector's command confirms. Inspect
the service with sudo systemctl status omnesis-gateway and
journalctl -u omnesis-gateway; omnesis service status covers
only your user services. The unit is readable only by root, so run
sudo omnesis doctor to include it in the checks.
If installation fails while activating the gateway, the installer stops the service so systemd does not keep restarting it. Inspect the journal, correct the startup error, and run the install command again. The state and passphrase are kept.
The keys reach the gateway as a systemd credential: the unit names
/etc/omnesis-gateway/keyring.pass, which systemd reads as root and hands to
this service alone. Before the first start the unit creates the root key, so the stores
are encrypted from the beginning; a key the passphrase cannot open stops the start. Keep
the passphrase file. Without it, the stores open again only by restoring the key from the
recovery code and the recovery envelope in the state directory.
Updating and removing
omnesis update updates your CLI and collector and prints the root command
that moves the dedicated gateway to the same release.
sudo omnesis-gateway-admin update --version X.Y.Z builds the new release
beside the running one, switches to it, restarts the service and waits for the new version
to answer. If it does not, it switches back. Updates take no backup by default;
--backup requests one through the gateway before switching releases, and
--no-backup is accepted for compatibility with no effect. It refuses a
release older than the running one unless you pass --force.
sudo omnesis-gateway-admin rollback switches back to the previous release,
and sudo omnesis-gateway-admin status shows both.
sudo omnesis-gateway-admin uninstall removes the service and the releases but
keeps the state directory and the passphrase that opens it; --purge deletes
them too. omnesis uninstall gateway runs the
same removal from a login account, through sudo. Running the install command
on a dedicated gateway whose unit runs code from a login account moves it onto a
root-owned release, keeping its port, state and passphrase.
TLS certificate
The gateway always serves HTTPS, with the certificate chosen at setup: a Tailscale certificate, an mkcert one, one you provide, or the self-signed pair the gateway creates on first start. This section covers what happens afterwards: renewal, how a new certificate goes live, and what clients that pinned the old one need.
Renewal and activation
Renewing writes a new certificate to the files the gateway reads; activating starts
serving it. The gateway activates on its own: once an hour it re-reads the certificate and
key, checks that they parse, match and are within their validity dates, and if they differ
from what it serves, switches to them without a restart.
omnesis tls reload does this immediately. A replacement that fails the checks
is reported and ignored, and the previous certificate stays in use.
The gateway renews the certificates it created: the self-signed pair, the Tailscale
certificate and the mkcert certificate. From 30 days before expiry it creates a new one of
the same kind (through openssl, tailscale cert or
mkcert), checks it and activates it.
Any other certificate you point the gateway at through OMNESIS_TLS_CERT and
OMNESIS_TLS_KEY is checked and reported but never renewed or overwritten:
renew it with the tool that issued it, into the same files, and the gateway picks it up. A
gateway in Docker renews only its self-signed pair; a Tailscale or mkcert certificate is
renewed on the host, by re-running its issuer into the same file. For the Tailscale
certificate the installer issues on a Docker host, a job it registers there does that
daily. gateway.tls.autoRenew: false turns automatic renewal off and
gateway.tls.renewBeforeDays moves the threshold;
omnesis tls renew renews on request, and --force renews one that
is not yet due. omnesis update never renews certificates.
❯ omnesis tls status
Certificate expiring ownership Tailscale, minted by Omnesis certificate /home/maya/.config/omnesis/tls/tailscale.crt fingerprint sha256:4f1c…9be2 valid until 2026-10-02T09:14:00.000Z (18 days remaining) names studio.tail-example.ts.net renewal automatic, 30 days before expiry last attempt 2026-09-14T03:00:12.000Z failed: `tailscale cert` failed: HTTPS is not enabled for this tailnet
omnesis doctor reports the same facts: a certificate inside its renewal
window is a warning, an expired one a failure, and each names the command to fix it. A
certificate that does not cover a name the gateway is reached by (the gateway URL, the
public address, a pairing address) is also a warning, because clients using that name will
refuse it; the fix is a new certificate, not weaker verification.
The self-signed certificate lasts ten years but covers only the network addresses the host
had when it was created. After those change,
omnesis tls renew --force recreates it with the current ones. A Tailscale or
mkcert certificate that no longer covers the address you use is recreated with
omnesis tls refresh (add --mkcert for mkcert), which also
activates it in the running gateway when it can reach it.
Behind a reverse proxy that terminates TLS, clients see the proxy's certificate, renewed
by the proxy's own tooling. omnesis tls status then describes the gateway's
own certificate on the hop from the proxy, and lists the public name as served by the
proxy.
Clients that pinned the old certificate
A renewed certificate has a new fingerprint, which matters to clients that pinned the old one. A phone or agent pinned to a certificate that verifies publicly for the name it connects to switches to verifying that name on its next connection, so it follows every later renewal. Otherwise the gateway never drops a pin on a client's behalf.
- Phones paired through a Tailscale or domain name verify the name through the operating system and keep working across renewals. A phone paired by fingerprint to such a name does the same once it runs a current app and is opened.
-
Phones paired by fingerprint to a local address or an mkcert certificate, which includes every pairing against the self-signed certificate, stop connecting
when the certificate changes. When the gateway renews that certificate itself, the
pairing screen dates the renewal. Run
omnesis devices repair <name>and pair the phone again, by the gateway's Tailscale or domain name if it has one. -
OpenClaw and Hermes connected to a Tailscale or domain name verify that
name and keep working across renewals. Connected to an address, or to a certificate no
public authority issued, they pin it and stop at a renewal. Afterwards, run the command
the doctor prints on the agent's machine, which carries the new fingerprint:
omnesis connect <harness> --refresh --trust-fingerprint sha256:<served>. A plugin from a release that does not report how it verifies the gateway pins the certificate even on a Tailscale name. The gateway names it ahead of each renewal, and updating it before then (Update now in its warning on the Devices page, oromnesis update --fleet) lets it follow a Tailscale renewal while the certificate it trusts is still served. -
A collector or CLI on another machine saved the certificate on first
use and refuses a new one, showing both fingerprints. Compare them with
omnesis tls statuson the gateway machine, then runomnesis tls trust --fingerprint <served>on the other machine, or setOMNESIS_TRUST_FINGERPRINTthere before the collector starts. - A collector on the gateway machine reads the gateway's certificate file and follows a renewal when it next reconnects.
Phones and agents report how they verify the gateway. omnesis doctor,
omnesis devices list and the portal's Devices page name a device that will
lose its connection when the gateway renews its certificate, with the date and how to make
it verify by name instead or the update that lets it follow, and a device that has not
connected since a renewal, with the command that brings it back.
Public root certificates
The gateway, collector and CLI verify public names with the root certificates Node.js
bundles. Node.js checks no certificate revocation and reads no browser blocklist, so a
root that Mozilla removes stays trusted until Node.js ships a newer set. Omnesis does not
trust roots that Mozilla has removed but the installed Node.js still bundles; this needs
Node.js 24.5 or later. The npm runs and Node.js header downloads that the installer, the
omnesis launcher, omnesis update and the hardened gateway's
release build start do not trust them either, unless npm is configured with its own
ca or cafile. Keep Node.js current all the same. Tools outside
Omnesis, such as curl and git, use the operating system's store,
so keep the operating system's CA certificates current too.