Podman / Docker Deployment

Mezite ships container images and Podman Compose files for deploying the full stack with Podman (preferred) or Docker.

Building the Container Image

The repository's build/Containerfile produces an Alpine image with all four binaries (mezhub, mezd, msh, mezctl) and exposes the four standard ports. The image's ENTRYPOINT is mezhub.

Build the image bash
podman build -t mezite:latest -f build/Containerfile .

Compose Deployment

The repository's podman-compose.yml is the source of truth for the full E2E stack (PostgreSQL, mezhub, agents, mock providers, S3, etc.). For a minimal production-style deployment, a much shorter Compose file is sufficient. The example below pairs mezhub with PostgreSQL; pass MEZITE_DB_DRIVER=sqlite (and drop the postgres service) for a zero-dependency setup.

compose.yml — minimal mezhub + Postgres yaml
services:
  postgres:
    image: docker.io/library/postgres:16-alpine
    environment:
      POSTGRES_USER: mezite
      POSTGRES_PASSWORD: mezite
      POSTGRES_DB: mezite
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U mezite"]
      interval: 2s
      retries: 10

  mezhub:
    image: mezite:latest
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      MEZITE_CLUSTER_NAME: my-cluster
      MEZITE_DB_DRIVER: postgres
      MEZITE_DB_HOST: postgres
      MEZITE_DB_PORT: "5432"
      MEZITE_DB_USER: mezite
      MEZITE_DB_PASSWORD: mezite
      MEZITE_DB_NAME: mezite
      MEZITE_DB_SSLMODE: disable
      MEZITE_LOG_LEVEL: info
      MEZITE_PROXY_PUBLIC_ADDR: mezite.example.com:3080
      MEZITE_CA_KEY_PASSPHRASE: change-me-in-production
    ports:
      - "3025:3025"   # Auth gRPC
      - "3080:3080"   # Proxy HTTPS / Web UI
      - "3023:3023"   # SSH proxy
      - "3024:3024"   # Agent reverse tunnel
    healthcheck:
      test: ["CMD-SHELL", "/usr/local/bin/mezhub healthcheck"]
      interval: 2s
      retries: 15

volumes:
  pgdata:
Start with Compose bash
podman-compose -f compose.yml up -d

Running with podman run

Run mezhub directly bash
podman run -d --name mezhub \
  -e MEZITE_CLUSTER_NAME=my-cluster \
  -e MEZITE_DB_DRIVER=postgres \
  -e MEZITE_DB_HOST=host -e MEZITE_DB_PORT=5432 \
  -e MEZITE_DB_USER=mezite -e MEZITE_DB_PASSWORD=mezite \
  -e MEZITE_DB_NAME=mezite -e MEZITE_DB_SSLMODE=disable \
  -e MEZITE_CA_KEY_PASSPHRASE=change-me \
  -p 3025:3025 -p 3080:3080 -p 3023:3023 -p 3024:3024 \
  mezite:latest

Environment Variables

The mezhub server reads configuration in this order of precedence (highest wins): explicit environment variables, then the YAML config file (--config), then built-in defaults. The variables below are the env-var bindings that exist today; for keys without an env binding, use the YAML file. See Configuration for the full reference.

VariableDescriptionDefault
MEZITE_CLUSTER_NAMECluster identifier (also used as the trust domain)mezite
MEZITE_DB_DRIVERDatabase backend: sqlite or postgressqlite
MEZITE_DB_URLConnection string (overrides the host/port/user/password fields)
MEZITE_DB_HOSTPostgreSQL hostlocalhost
MEZITE_DB_PORTPostgreSQL port5432
MEZITE_DB_USERPostgreSQL usermezite
MEZITE_DB_PASSWORDPostgreSQL password(empty)
MEZITE_DB_NAMEPostgreSQL database namemezite
MEZITE_DB_SSLMODEPostgreSQL SSL moderequire
MEZITE_LOG_LEVELLog level (debug, info, warn, error)info
MEZITE_LOG_FORMATLog format (json or console)json
MEZITE_PROXY_PUBLIC_ADDRPublic address clients reach the proxy at (used for WebAuthn RPID and host/SSH cert principals)(empty)
MEZITE_OIDC_ISSUER_URLOIDC issuer URL advertised at /.well-known/openid-configuration. Explicit — never inferred from the Host header or public_addr.(empty)
MEZITE_CA_KEY_PASSPHRASEPassphrase for the software-encrypted CA signing keys(empty — required for production)
MEZITE_SINGLE_PORTMultiplex all protocols on the proxy HTTPS port via ALPNfalse
MEZITE_GRPC_ALLOW_HTTPEnable h2c on the gRPC auth port (for reverse-proxy deployments)false
MEZITE_AUTH_H2CDisable TLS on the gRPC auth port entirely (LB terminates TLS)(unset)

Listen addresses (auth.listen_addr, proxy.listen_addr, proxy.ssh_listen_addr, proxy.tunnel_listen_addr) are configured via the YAML file — they do not have env-var bindings and default to 0.0.0.0 on ports 3025/3080/3023/3024 respectively.

Health Checks

The proxy serves a liveness endpoint at /healthz and a readiness endpoint at /readyz on the HTTPS port. The mezhub healthcheck subcommand wraps the same check and is what the bundled podman-compose.yml uses.

Health check in Compose yaml
healthcheck:
  test: ["CMD-SHELL", "/usr/local/bin/mezhub healthcheck"]
  interval: 10s
  timeout: 5s
  retries: 3