Overpass distributes a Nix Flake containing precompiled binaries for the
control plane, node agent, op, opctl, and two NixOS modules. Releases are
packaged and published automatically to nix/overpass
via GoReleaser.
Add the flake
Add the Overpass repository to your system flake:
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
overpass.url = "git+https://forgejo.ofkm.us/nix/overpass.git";
};
outputs = { nixpkgs, overpass, ... }: {
nixosConfigurations.gateway = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
overpass.nixosModules.default
./configuration.nix
];
};
};
}
The flake exposes:
packages.<system>.default/overpass— package containingoverpass,op, andopctl.- Apps named
overpass,op, andopctlfornix run. - An overlay as
overlays.default. - NixOS modules:
nixosModules.default,nixosModules.overpass, andnixosModules.overpass-node.
Package outputs are provided for x86_64-linux, aarch64-linux, and aarch64-darwin.
Run the control plane
Enable the control-plane module in configuration.nix:
{
services.overpass = {
enable = true;
openFirewall = true;
settings = {
cluster_name = "production";
proxy = {
public_addr = "overpass.example.com";
public_url = "https://overpass.example.com";
};
};
};
}
Apply the configuration and inspect the service:
sudo nixos-rebuild switch --flake .#gateway
systemctl status overpass
sudo journalctl -u overpass -b
On its first start, Overpass writes a one-time setup claim code to the journal.
Open https://overpass.example.com/setup, enter that code, and create the first
administrator. With the default self-signed certificate, the browser will show
a certificate warning until you configure a trusted certificate.
The module:
- Creates the
overpasssystem user and group. - Creates
/var/lib/overpasswith mode0700. - Adds the selected package to
environment.systemPackages. - Generates the YAML configuration in the Nix store.
- Runs
overpass serveras a hardened systemd service. - Marks the executable as package-managed so it cannot replace itself.
services.overpass.dataDir always becomes the generated data_dir; a
data_dir value inside settings is ignored. The directory contains the
SQLite database, certificate-authority keys, TLS keys, and the server-managed
config directory at <dataDir>/overpass.d,
which holds configuration made through the web UI (settings, roles, SSO
connectors, desktops). Include the whole directory in your backups. Anything
declared in settings is authoritative and shows as read-only in the web UI;
set settings.config_dir to relocate the writable layer.
If you change services.overpass.user or services.overpass.group, create the
custom account or group elsewhere in your NixOS configuration. The module only
creates the default overpass user and group automatically.
Listener ports and the firewall
Without TLS routing, the default listeners are:
| Port | Purpose |
|---|---|
8443 |
Web UI, REST API, OIDC, and browser terminal |
3023 |
Client SSH routing |
3024 |
Node reverse tunnels |
3025 |
Login, enrollment, and administrative gRPC |
Set services.overpass.openFirewall = true to allow the ports configured in
settings.proxy. When proxy.tls_routing = true, the module opens only the
configured web listener because clients and nodes share it through TLS ALPN or
WebSocket routing.
For a reverse-proxy deployment, configure public_url, public_addr, and any
trusted proxy networks explicitly. See Reverse proxy for
the single-port routing examples.
Keep secrets outside the Nix store
Values under services.overpass.settings are rendered into a file in the Nix
store. Do not put passwords, tokens, or private credentials directly in that
attribute set.
Reference environment-variable names from the generated configuration and
supply their values with environmentFile:
{
services.overpass = {
environmentFile = "/run/secrets/overpass.env";
settings = {
auth.oidc = [
{
name = "sso";
issuer_url = "https://id.example.com";
client_id = "overpass";
client_secret_env = "OVERPASS_OIDC_CLIENT_SECRET";
}
];
};
};
}
The environment file uses systemd KEY=value syntax:
OVERPASS_OIDC_CLIENT_SECRET=replace-with-secret
Create that file with sops-nix, agenix, or another secret manager. The module
rejects inline OIDC client_secret values to prevent this common leak.
Enroll a node
Create a one-time join token from the dashboard, or locally on the control plane:
sudo -u overpass opctl --local --data-dir /var/lib/overpass tokens add
Store the token in a root-readable secret file on the node, then configure the node service:
{
services.overpass-node = {
enable = true;
name = "web-1";
proxy = "overpass.example.com:3025";
tlsPin = "sha256:BASE64_CERTIFICATE_FINGERPRINT";
joinTokenFile = "/run/secrets/overpass-join";
labels = {
env = "production";
role = "web";
};
};
}
Apply the node configuration and follow enrollment:
sudo nixos-rebuild switch --flake .#web-1
systemctl status overpass-node
sudo journalctl -u overpass-node -b -f
The module passes the token with systemd credentials. Its value does not appear in the generated unit command line or in the Nix store. The service performs an enrollment-only check before starting the long-running agent and reads the token only when no valid identity already exists.
After the first successful enrollment, remove joinTokenFile and delete the
one-time token secret. The enrolled identity remains under
/var/lib/overpass-node.
TLS to the control plane has three modes: with a publicly trusted certificate, omit
both options and the agent does standard PKI validation; insecure = true
disables verification and is for bootstrap/testing only; tlsPin remains an
optional advanced override for self-signed clusters.
For initial testing against a self-signed endpoint, you can use:
services.overpass-node.insecure = true;
The node needs only outbound access to the control plane; it does not require an inbound firewall rule.
Remote sessions on NixOS
The node runs as root because it must switch each SSH session to the requested local Unix account. It resolves that account's configured login shell and starts the session with these Nix profile directories before the system PATH:
$HOME/.nix-profile/bin/etc/profiles/per-user/<username>/bin
Override the system portion with services.overpass-node.sessionPath when the
host needs additional commands or wrapper directories.
Module option reference
services.overpass
| Option | Default | Description |
|---|---|---|
enable |
false |
Start the Overpass control plane. |
package |
Flake package | Package containing overpass, op, and opctl. |
user |
"overpass" |
Service user. Custom users must already exist. |
group |
"overpass" |
Service group. Custom groups must already exist. |
dataDir |
"/var/lib/overpass" |
Persistent database, CA/TLS state, and the writable config directory (overpass.d). |
settings |
{ } |
Attributes serialized to the Overpass YAML configuration. Declared values are authoritative and read-only in the web UI. |
environmentFile |
null |
Absolute path to a systemd environment file containing secrets. |
openFirewall |
false |
Allow the configured listener ports through the NixOS firewall. |
debug |
false |
Run the control plane with debug logging. |
See Configuration for the complete set of values accepted
under settings.
services.overpass-node
| Option | Default | Description |
|---|---|---|
enable |
false |
Start the node agent. |
package |
overpass-node variant |
Node executable; the web-free overpass-node build by default. |
name |
networking.hostName |
Name presented to users and the control plane. |
proxy |
Required | Control-plane gRPC address in host:port form. |
tunnel |
Learned during enrollment | Optional explicit reverse-tunnel address. |
dataDir |
"/var/lib/overpass-node" |
Persistent node identity directory. |
labels |
{ } |
Labels requested during initial enrollment. |
joinTokenFile |
null |
Root-readable one-time enrollment-token file. |
tlsPin |
null |
Control-plane certificate pin in sha256:<base64> form. |
insecure |
false |
Disable certificate verification for testing or bootstrap. |
sessionPath |
NixOS system paths | System PATH appended after user-specific Nix profiles. |
debug |
false |
Run the node with debug logging. |
Update and roll back
Nix-built executables identify themselves as package-managed and never replace files in the Nix store. Update the locked Overpass input and rebuild:
nix flake update overpass
sudo nixos-rebuild switch --flake .#gateway
Apply the same input update to node configurations so the fleet converges on one version. If the fleet target is newer than a deployed Nix package, the Updates page keeps that control plane or node pending until its system is rebuilt.
Use the normal NixOS rollback if a new generation fails:
sudo nixos-rebuild switch --rollback
Troubleshoot
Inspect the effective units and recent logs:
systemctl cat overpass
systemctl cat overpass-node
sudo journalctl -u overpass -b
sudo journalctl -u overpass-node -b
Check the control-plane health endpoint locally:
curl --fail --insecure https://127.0.0.1:8443/healthz
Common failures:
- A fresh node without
joinTokenFilecannot enroll. Add the credential, rebuild, and remove it only after enrollment succeeds. - A node that cannot verify the control-plane certificate fails to connect. Use
a publicly trusted certificate (set neither option),
tlsPinfor a self-signed control plane, orinsecure = truefor bootstrap only. - Inline OIDC secrets are rejected because
settingsis stored in the Nix store. Move them toenvironmentFile. - A custom control-plane user or group must be declared separately and needs
write access to
dataDir. - With
openFirewall = false, open the configured ports through your own firewall rules or keep them intentionally private.