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.
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).
❯ omnesis secure --dry-run
❯ omnesis secure
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.
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. 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. |
| Service hardening | Whether the installed service units carry the expected restrictions. |
| 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 → Doctor 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 24 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. --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.
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, takes a backup through the gateway, switches to the new release,
restarts the service and waits for the new version to answer. If it does not, it switches
back and prints the commands that list and restore backups, in case the new release
already migrated the data. --no-backup switches without a backup. 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. 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.
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. The gateway never drops a pin on a client's behalf.
- Phones paired through a Tailscale certificate verify the name through the operating system, so they keep working across renewals.
-
Phones paired by fingerprint, which includes every pairing against the
self-signed certificate, stop connecting when it changes. A phone paired by fingerprint
on a local address while the gateway serves a Tailscale certificate stops at each
renewal, which the pairing screen dates. Run
omnesis devices repair <name>and pair the phone again;omnesis doctorlists phones that have not connected since a renewal. -
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.