Configuration Reference

Mezite is configured through a YAML file, typically located at /etc/mezite/mezite.yaml. Every setting can also be overridden via environment variables. This page documents every field, its type, default value, and the corresponding environment variable.


Config Loading Order

Settings are resolved in the following order, with later sources taking precedence:

  1. Built-in defaults — Sensible values baked into the binary.
  2. Config file — Loaded from the path given by --config.
  3. Environment variables — Prefixed with MEZITE_, these override any value set in the config file.
Environment variables always win. This makes it easy to inject secrets (like database passwords and CA passphrases) without writing them to disk.

Minimal Config

The smallest useful configuration — just enough to start a combined-mode server with SQLite (the default):

mezite.yaml — minimal (SQLite) yaml
cluster_name: my-cluster

ssh:
  enabled: true

For PostgreSQL, set the driver and connection fields:

mezite.yaml — minimal (PostgreSQL) yaml
cluster_name: my-cluster

database:
  driver: postgres
  host: localhost
  port: 5432
  user: mezite
  password: mezite
  name: mezite
  sslmode: disable

ssh:
  enabled: true

Full Example

Below is a complete mezite.yaml with every field and its default value. In practice you only need to specify values that differ from the defaults.

mezite.yaml — complete reference yaml
# ─── Cluster ─────────────────────────────────────────────
cluster_name: my-cluster

# ─── Logging ─────────────────────────────────────────────
log:
  level: info
  format: json

# ─── Database ────────────────────────────────────────────
database:
  driver: sqlite          # sqlite (default) or postgres
  host: localhost          # PostgreSQL only
  port: 5432               # PostgreSQL only
  user: mezite             # PostgreSQL only
  password: mezite         # PostgreSQL only
  name: mezite             # PostgreSQL only
  sslmode: require         # PostgreSQL only

# ─── Auth Service ────────────────────────────────────────
auth:
  grpc_allow_http: false

# Top-level: CA private key encryption passphrase
ca_key_passphrase: ""

# ─── Proxy Service ───────────────────────────────────────
proxy:
  public_addr: ""              # required for OIDC, WebAuthn, etc.
  listen_addr: 0.0.0.0:3080
  ssh_listen_addr: 0.0.0.0:3023
  tunnel_listen_addr: 0.0.0.0:3024
  apps_domain: ""              # parent domain for application access (empty = off)
  apps_oidc_connector: ""      # SSO connector that gates browser app access
  # apps_keypair:              # optional dedicated wildcard keypair for *.<apps_domain>
  #   cert_file: /etc/mezite/apps-wildcard.crt
  #   key_file: /etc/mezite/apps-wildcard.key

# ─── SSH Service ─────────────────────────────────────────
ssh:
  enabled: false

Cluster

FieldTypeDefaultEnv VarDescription
cluster_namestringmeziteMEZITE_CLUSTER_NAMEUnique identifier for this cluster. Embedded in all certificates and used to namespace audit events. Must be a valid DNS label.

Logging

Logging keys below apply to the mezhub server. The mezd agent emits its own structured logs at production defaults; it does not read MEZITE_LOG_LEVEL or MEZITE_LOG_FORMAT.

FieldTypeDefaultEnv VarDescription
log.levelstringinfoMEZITE_LOG_LEVELMinimum log level for mezhub. One of debug, info, warn, error.
log.formatstringjsonMEZITE_LOG_FORMATLog serialization format for mezhub. json for structured output, text for human-readable.

Database

Mezite supports SQLite and PostgreSQL backends. SQLite is the simplest option for self-hosted deployments (zero external dependencies). PostgreSQL 16+ is recommended for production and managed deployments.

FieldTypeDefaultEnv VarDescription
database.driverstringsqliteMEZITE_DB_DRIVERDatabase backend: sqlite or postgres.
database.urlstring""MEZITE_DB_URLConnection URL. For SQLite: file path. For PostgreSQL: DSN. When empty, built from fields below (PG) or defaults to <data_dir>/mezhub.db (SQLite).
database.hoststringlocalhostMEZITE_DB_HOSTPostgreSQL hostname or IP address.
database.portinteger5432MEZITE_DB_PORTPostgreSQL port.
database.userstringmeziteMEZITE_DB_USERDatabase user (PostgreSQL only).
database.passwordstring""MEZITE_DB_PASSWORDDatabase password (PostgreSQL only).
database.namestringmeziteMEZITE_DB_NAMEName of the PostgreSQL database.
database.sslmodestringrequireMEZITE_DB_SSLMODEPostgreSQL TLS mode. Accepts: disable, require, verify-ca, verify-full.
SQLite (simplest — no external database) bash
export MEZITE_DB_DRIVER=sqlite
export MEZITE_DB_URL=/var/lib/mezite/mezhub.db
PostgreSQL (production) bash
export MEZITE_DB_DRIVER=postgres
export MEZITE_DB_HOST=db.internal.example.com
export MEZITE_DB_PORT=5432
export MEZITE_DB_USER=mezite
export MEZITE_DB_PASSWORD='$(vault kv get -field=password secret/mezite/db)'
export MEZITE_DB_NAME=mezite
export MEZITE_DB_SSLMODE=verify-full

Auth

Local username/password authentication is always available out of the box; SSO connectors (OIDC, SAML, LDAP, GitHub OAuth) are configured at runtime with mezctl connectors create, not via this YAML file. See the SSO Guide for the connector schema.

First-issue SSH certificate TTL is set per call to IssueUserCerts. It defaults to 12h and is hard-capped at 24h regardless of any role or cluster setting. Per-role max_session_ttl is a separate knob that tightens cross-cluster certificate issuance further; it does not raise the 24h ceiling. The schema field auth.session_ttl is currently reserved — it appears for forward compatibility but is not read by any code path today.

FieldTypeDefaultEnv VarDescription
auth.grpc_allow_httpbooleanfalseMEZITE_GRPC_ALLOW_HTTPAllow plaintext h2c (HTTP/2 cleartext) on the gRPC listener. This is HTTP/2 in the clear — use only when a TLS-terminating load balancer or service mesh fronts mezhub. If anything other than that fronts the listener, leave this off and present a certificate to clients directly.
ca_key_passphrase (top-level)string""MEZITE_CA_KEY_PASSPHRASEPassphrase used to encrypt Certificate Authority private keys at rest in the database.

Proxy

FieldTypeDefaultEnv VarDescription
proxy.public_addrstring""MEZITE_PROXY_PUBLIC_ADDRThe public address that clients use to reach this proxy (e.g. mezite.example.com:443). Used to derive the WebAuthn relying-party ID/origin and the cluster's GetServerInfo enrollment URL. The OIDC issuer URL is configured separately via proxy.oidc_issuer_url.
proxy.listen_addrstring0.0.0.0:3080--Bind address for the HTTPS listener.
proxy.ssh_listen_addrstring0.0.0.0:3023--Bind address for the SSH listener.
proxy.tunnel_listen_addrstring0.0.0.0:3024--Bind address for the reverse-tunnel listener.
proxy.oidc_issuer_urlstring""MEZITE_OIDC_ISSUER_URLPublic issuer URL surfaced at /.well-known/openid-configuration and used in workload-identity JWT SVIDs. No trailing slash.
proxy.trusted_ip_headerstring""--HTTP header to read real client IP from (e.g. Fly-Client-IP, X-Forwarded-For). Config-file only — there is no dedicated env var for this field.
proxy.single_portbooleanfalseMEZITE_SINGLE_PORTEnable ALPN single-port routing on the HTTPS listener. When on, the proxy demultiplexes SSH, agent tunnel, and HTTPS traffic onto proxy.listen_addr using TLS ALPN protocol IDs, so a cluster can be reached entirely on :443. The individual ssh_listen_addr and tunnel_listen_addr sockets still bind unless their ports are unset; clients reaching the proxy on :443 are routed by ALPN.
proxy.proxy_protocolstringoff--Mode for HAProxy PROXY protocol v1/v2 headers on the SSH and tunnel listeners. Accepted values are off (default; PROXY headers ignored) and on (PROXY headers required from trusted source ranges). When set to on, pair with proxy.proxy_protocol_trusted_cidrs so only trusted load-balancer source ranges can rewrite the client IP. See Reverse Proxy.
proxy.proxy_protocol_trusted_cidrslist of strings(empty)--IPs or CIDRs permitted to send PROXY headers when proxy.proxy_protocol is on. Required in that case — connections from any other source are rejected.
proxy.apps_domainstring""MEZITE_PROXY_APPS_DOMAINParent domain for application access hostnames (e.g. apps.example.com makes apps reachable at <app>.apps.example.com). Empty disables application-access host routing; nothing else about the cluster changes. Requires a wildcard DNS record and a TLS certificate covering *.<apps_domain>.
proxy.apps_keypair.cert_file / proxy.apps_keypair.key_filestring""MEZITE_PROXY_APPS_CERT_FILE / MEZITE_PROXY_APPS_KEY_FILEOptional dedicated wildcard (or multi-SAN) keypair for *.<apps_domain>, SNI-selected for app subdomains. When unset, the proxy's main HTTPS certificate must cover the apps wildcard in its SANs. Both fields are required together, and only take effect when apps_domain is set — otherwise the proxy refuses to start.
proxy.apps_oidc_connectorstring""MEZITE_PROXY_APPS_OIDC_CONNECTORName of the SSO connector the browser application-access gate redirects unauthenticated users to. Required for the browser app gate to start a login.

SSH

FieldTypeDefaultEnv VarDescription
ssh.enabledbooleanfalse--Enable the built-in SSH service on this node.

Recording

Controls where session recordings are written and how/when the agent uploads them. See the Session Recording guide for end-to-end behavior.

FieldTypeDefaultEnv VarDescription
recording.backendstringlocalMEZITE_RECORDING_BACKENDStorage backend: local (filesystem under data_dir) or s3.
recording.s3.bucketstring""MEZITE_S3_BUCKETS3 bucket name.
recording.s3.regionstringus-east-1MEZITE_S3_REGIONS3 region.
recording.s3.endpointstring""MEZITE_S3_ENDPOINTCustom endpoint URL for MinIO or other S3-compatible stores. Empty uses AWS defaults.
recording.s3.access_keystring""MEZITE_S3_ACCESS_KEYStatic access key. Leave empty to use the default AWS SDK credential chain (IRSA, IAM role, env, ~/.aws).
recording.s3.secret_keystring""MEZITE_S3_SECRET_KEYStatic secret key. Paired with access_key.
recording.s3.prefixstring""MEZITE_S3_PREFIXOptional key prefix under the bucket (e.g. cluster-a/recordings/).
recording.s3.force_path_stylebooleanfalseMEZITE_S3_FORCE_PATH_STYLEUse path-style addressing (https://endpoint/bucket/key) instead of virtual-host style. Required for MinIO and some on-prem stores.
recording.s3.auto_create_bucketbooleanfalseMEZITE_S3_AUTO_CREATE_BUCKETCreate the bucket on startup if it does not exist. Off in production; intended for dev and tests.
recording_enc_key (top-level)string""MEZITE_RECORDING_ENC_KEYHex-encoded 32-byte AES-256-GCM key. When set, the agent encrypts every recording chunk before handing it to the storage backend (covers both local and s3). Leaving this empty disables recording encryption; the recording is written in the clear to the backend.
--string--MEZITE_RECORDING_MODESet on mezd, not mezhub. Controls agent-side recording behaviour: node (default — buffer locally and upload after the session ends) or node-sync (stream chunks to the auth service in real time; agent terminates the SSH session if the upload stream breaks).

Audit Log Sinks

Audit events are always written to the cluster database. In addition, events can be mirrored to one or more external sinks for SIEM, alerting, or long-term archive. See the Audit Logging guide.

FieldTypeDefaultEnv VarDescription
audit_hmac_key (top-level)string""MEZITE_AUDIT_HMAC_KEYHex-encoded HMAC key for the tamper-detection chain on persisted audit events. Strongly recommended in production. Rotating this key invalidates the existing chain — keep the old value alongside the new one during transition.
--string--MEZITE_AUDIT_SINK_FILE_PATHWhen set, every audit event is appended to this file in newline-delimited JSON format (one JSON object per line). Useful for shipping to a log forwarder or for offline archival.
--string--MEZITE_AUDIT_SINK_WEBHOOK_URLWhen set, every audit event is POSTed as JSON to this URL. Common target for Splunk HEC, Datadog Logs intake, Elastic ingest, or a tenant-side Lambda. The receiving endpoint should be idempotent — transient retries can deliver the same event more than once.
--duration5sMEZITE_AUDIT_SINK_WEBHOOK_TIMEOUTHTTP timeout for the webhook sink. Slow endpoints stall the mirror; the in-process audit pipeline keeps emitting to the database regardless.

KMS-Backed CA Keys

By default, CA signing keys live in the cluster database, AES-256-GCM encrypted with the key derived from MEZITE_CA_KEY_PASSPHRASE. For higher assurance — and for managed deployments — the cluster can be configured so that every CA signing operation calls AWS KMS instead, with the raw private key material never leaving the KMS HSM boundary.

FieldTypeDefaultEnv VarDescription
kms.enabledbooleanfalseMEZITE_KMS_ENABLEDRoute CA signing through AWS KMS. When on, both kms.region and kms.alias_prefix are required (validated at startup).
kms.regionstring""MEZITE_KMS_REGIONAWS region the KMS keys live in (e.g. eu-west-2).
kms.alias_prefixstring""MEZITE_KMS_ALIAS_PREFIXPrefix used when building per-tenant KMS aliases. Must not start with alias/ (the CA layer prepends it) and must end with -. The final alias shape is alias/<prefix><tenant>-<ca-type>.
--string--MEZITE_KMS_EXTRA_TAGSComma-separated key=value pairs to apply on KMS CreateKey for each new CA key. Used by the managed plane to attach the tenant tag the per-tenant IAM policy keys off of.

Managed Mode

Set on cloud-managed tenants. When on, the cluster fails to start unless kms.enabled is also true — managed tenants are required to sign with KMS-backed keys so the platform operator can revoke a tenant out-of-band. Leave this off for self-hosted deployments.

FieldTypeDefaultEnv VarDescription
managed_mode (top-level)booleanfalseMEZITE_MANAGED_MODEEnable managed-tenant behaviour. Forces kms.enabled=true; refuses to boot otherwise.

Moderation and Access Requests

FieldTypeDefaultEnv VarDescription
moderation.transfer_approval_timeoutduration5mMEZITE_TRANSFER_APPROVAL_TIMEOUTHow long the proxy waits for moderator approval on an SFTP transfer before denying. Capped at 5 minutes — the agent enforces the same ceiling locally, so a longer value would let the agent deny a transfer the proxy still considers pending.
--duration7dMEZITE_ACCESS_REQUEST_MAX_DURATIONMaximum duration an access-request grant can be issued for. A request asking for a longer window is rejected; a shorter window is honoured as-is.
--duration30mMEZITE_HOST_CERT_TTLTTL on agent host certificates. Lower values shorten the window an attacker who exfiltrates a node's signing material can keep impersonating that host.

Workload Identity (mezd identity)

The mezd identity daemon runs on a workload node, exposes a Unix socket that local workloads can call to fetch short-lived X.509/JWT SPIFFE SVIDs, and renews those SVIDs on a timer. These knobs are read by mezd identity only, not by mezhub.

VariableRequiredDescription
MEZITE_IDENTITY_TOKENYesBootstrap join token used to authenticate the daemon to mezhub on first start.
MEZITE_IDENTITY_DIRNoDirectory holding the persisted identity material between renewals.
MEZITE_IDENTITY_TTLNoRequested SVID TTL (server may clamp lower).
MEZITE_IDENTITY_RENEWAL_INTERVALNoHow often the daemon renews. Should be well under MEZITE_IDENTITY_TTL.
MEZITE_IDENTITY_ONE_SHOTNoRun a single renewal and exit. Useful for CI helpers and Machine ID-style use cases where another process holds the SVID lifecycle.
MEZITE_WORKLOAD_SOCKETNoPath of the Unix socket workloads connect to. Default /var/run/mezite/workload.sock.

Bootstrap and Operations

VariableDescription
MEZITE_ADMIN_PASSWORDWhen set on first boot, seeds the bootstrap admin account with this password. After the cluster is initialised the variable can be removed; subsequent admin accounts are created via mezctl users create.
MEZITE_BOOTSTRAP_JOIN_TOKENWhen set on first boot, creates a node-role join token with this value so an initial mezd can register without first invoking mezctl tokens create.
MEZITE_DATA_DIROverride for the on-disk data directory (default /var/lib/mezite) used by SQLite, local recordings, and the join-state file.
MEZITE_METRICS_ADDRWhen set (e.g. :9100), exposes a Prometheus /metrics endpoint on the given address.
MEZITE_METRICS_TOKENOptional bearer token required to scrape the metrics endpoint. Leave unset to expose metrics without authentication on an internal listener.
MEZITE_HTTPSAFE_ALLOW_PRIVATE / MEZITE_HTTPSAFE_ALLOW_LOOPBACKTest-and-dev overrides for the outbound HTTP allowlist that normally blocks mezhub from calling private or loopback addresses (used by OIDC discovery, SAML metadata, webhook sinks). Off in production.

Port Reference

PortProtocolComponentDescription
3025gRPCAuth ServiceInternal auth API. Should not be exposed publicly.
3080HTTPSProxy ServiceWeb UI, REST API, OIDC callbacks.
3023SSHProxy ServiceSSH client connections via msh.
3024gRPCProxy ServiceAgent reverse-tunnel connections.
5432PostgreSQLDatabaseState store (only when using PostgreSQL backend).

Agent Configuration

The mezd binary is configured entirely via environment variables.

VariableRequiredDescription
MEZITE_JOIN_TOKENYes (first run)One-time join token. Only needed on first join.
MEZITE_AUTH_ADDRYesAddress of the Auth service (e.g. mezite.example.com:3025).
MEZITE_PROXY_ADDRYesAddress of the Proxy tunnel listener (e.g. mezite.example.com:3024).
MEZITE_NODE_NAMENoNode name shown in msh ls. Defaults to hostname.
MEZITE_NODE_LABELSNoComma-separated key=value labels for RBAC matching (e.g. env=prod,role=web).
MEZITE_DATA_DIRNoData directory for identity and recordings. Default: /var/lib/mezite.
MEZITE_RECORDING_MODENoRecording mode: node (default — async upload after session) or node-sync (real-time streaming to the auth service). See Session Recording.
MEZITE_TLS_WRAPNoWrap tunnel connection in TLS. Required when connecting through a TLS-terminating load balancer. See Reverse Proxy.
MEZITE_BPF_ENABLEDNoEnable eBPF enhanced recording (Linux only, requires privileged mode). Captures command executions in addition to terminal I/O.
MEZITE_PAM_SERVICENoPAM service name for session hooks (Linux only).
MEZITE_AUTH_H2CNoRun gRPC auth in h2c (HTTP/2 cleartext) mode. Use when a TLS-terminating load balancer sits in front (Fly.io, ALB, Istio/Linkerd service mesh). Also suitable for local development.
Agent startup example bash
MEZITE_JOIN_TOKEN=d4f8a2e1-7b3c-4d9e-a5f6-1234567890ab \
MEZITE_AUTH_ADDR=mezite.example.com:3025 \
MEZITE_PROXY_ADDR=mezite.example.com:3024 \
MEZITE_NODE_NAME=web-server-01 \
MEZITE_NODE_LABELS="env=production,role=webserver" \
mezd start

Environment Variables

VariableConfig EquivalentDescription
MEZITE_CLUSTER_NAMEcluster_nameCluster name
MEZITE_DB_DRIVERdatabase.driverDatabase backend (sqlite or postgres)
MEZITE_DB_URLdatabase.urlConnection URL (file path for SQLite, DSN for PostgreSQL)
MEZITE_DB_HOSTdatabase.hostPostgreSQL host
MEZITE_DB_PORTdatabase.portPostgreSQL port
MEZITE_DB_USERdatabase.userPostgreSQL user
MEZITE_DB_PASSWORDdatabase.passwordPostgreSQL password
MEZITE_DB_NAMEdatabase.namePostgreSQL database name
MEZITE_DB_SSLMODEdatabase.sslmodePostgreSQL TLS mode
MEZITE_LOG_LEVELlog.levelLog verbosity
MEZITE_LOG_FORMATlog.formatLog format (json or text)
MEZITE_CA_KEY_PASSPHRASEca_key_passphrase (top-level)CA private key encryption passphrase
MEZITE_AUTH_H2C-Run gRPC in h2c mode (required behind a TLS-terminating LB). Process-level env var read directly by mezhub at startup; not a config-file field.
MEZITE_GRPC_ALLOW_HTTPauth.grpc_allow_httpAllow plaintext h2c on the gRPC listener (also enabled by MEZITE_AUTH_H2C).
MEZITE_PROXY_PUBLIC_ADDRproxy.public_addrPublic proxy address. Derives the WebAuthn RP ID/origin and the GetServerInfo enrollment URL; the OIDC issuer URL is set separately via MEZITE_OIDC_ISSUER_URL.
MEZITE_OIDC_ISSUER_URLproxy.oidc_issuer_urlPublic issuer URL surfaced at /.well-known/openid-configuration. No trailing slash.
MEZITE_AUDIT_HMAC_KEYaudit_hmac_key (top-level)Hex-encoded HMAC key for the audit-log tamper-detection chain.
MEZITE_RECORDING_BACKENDrecording.backendRecording storage backend: local (default) or s3
MEZITE_S3_BUCKETrecording.s3.bucketS3 bucket for recording storage
MEZITE_S3_REGIONrecording.s3.regionS3 region (default: us-east-1)
MEZITE_S3_ENDPOINTrecording.s3.endpointCustom S3 endpoint (for MinIO or other S3-compatible stores)
MEZITE_RECORDING_ENC_KEYrecording_enc_key (top-level)32-byte hex-encoded AES-256 key for recording encryption at rest
Example: SQLite with env vars (simplest self-hosted) bash
MEZITE_CLUSTER_NAME=production \
MEZITE_DB_DRIVER=sqlite \
MEZITE_DB_URL=/var/lib/mezite/mezhub.db \
MEZITE_LOG_LEVEL=info \
MEZITE_CA_KEY_PASSPHRASE='another-secret' \
mezhub
Example: PostgreSQL with env vars bash
MEZITE_CLUSTER_NAME=production \
MEZITE_DB_HOST=db.internal.example.com \
MEZITE_DB_PORT=5432 \
MEZITE_DB_USER=mezite \
MEZITE_DB_PASSWORD='hunter2' \
MEZITE_DB_NAME=mezite \
MEZITE_DB_SSLMODE=verify-full \
MEZITE_LOG_LEVEL=info \
MEZITE_LOG_FORMAT=json \
MEZITE_CA_KEY_PASSPHRASE='another-secret' \
mezhub

Production Config

SSO connectors are not configured in mezite.yaml — create them at runtime with mezctl connectors create once the hub is up. See the SSO Guide.

mezite.yaml — production yaml
cluster_name: production

log:
  level: info
  format: json

database:
  driver: postgres
  host: db.internal.example.com
  port: 5432
  user: mezite
  # password set via MEZITE_DB_PASSWORD
  name: mezite
  sslmode: verify-full

# ca_key_passphrase set via MEZITE_CA_KEY_PASSPHRASE

proxy:
  public_addr: mezite.example.com:443
  listen_addr: 0.0.0.0:3080
  ssh_listen_addr: 0.0.0.0:3023
  tunnel_listen_addr: 0.0.0.0:3024
  oidc_issuer_url: https://mezite.example.com

ssh:
  enabled: false  # dedicated proxy node, not an SSH target

Next Steps

  • Quickstart — Apply this configuration in a working setup.
  • Architecture — Understand how auth, proxy, and agent components interact.
  • SSH Access Guide — Deep dive into SSH certificate authentication and session recording.
  • SSO Guide — Configure OIDC or SAML authentication.
  • Application Access — Publish internal web and TCP apps using the proxy.apps_* settings above.