Hub on Kubernetes
Hub-only mode (TOWONEL_HUB_ENABLED=true,
TOWONEL_EDGE_ENABLED=false). Edges run separately — see
Edge on Kubernetes.
Database
Section titled “Database”SQLite is the default — single replica, on-disk file under
TOWONEL_DATA_DIR. Postgres is required to run multiple hub replicas.
| Driver | Replicas | DSN |
|---|---|---|
| sqlite | 1 | hub.db under ${TOWONEL_DATA_DIR} (default) |
| postgres | N | TOWONEL_HUB_DB_DSN required |
SQLite — single replica + PVC
Section titled “SQLite — single replica + PVC”apiVersion: helm.toolkit.fluxcd.io/v2kind: HelmReleasemetadata: name: towonel-hubspec: chartRef: { kind: OCIRepository, name: towonel-hub } interval: 30m values: controllers: towonel-hub: type: statefulset replicas: 1 statefulset: volumeClaimTemplates: - name: data accessMode: ReadWriteOnce size: 1Gi globalMounts: [{ path: /data }] annotations: reloader.stakater.com/auto: "true" containers: app: image: repository: codeberg.org/towonel/towonel-node tag: 0.1.1 env: TOWONEL_HUB_ENABLED: "true" TOWONEL_EDGE_ENABLED: "false" TOWONEL_DATA_DIR: /data TOWONEL_HUB_LISTEN_ADDR: 0.0.0.0:8443 TOWONEL_HUB_LINK_LISTEN_ADDR: 0.0.0.0:51444 TOWONEL_HUB_PUBLIC_URL: https://hub.example.eu envFrom: - secretRef: { name: towonel-hub-secret } probes: &hub-probes startup: enabled: true custom: true spec: httpGet: { path: /v1/health, port: 8443 } periodSeconds: 5 failureThreshold: 60 liveness: enabled: true custom: true spec: httpGet: { path: /v1/health, port: 8443 } readiness: enabled: true custom: true spec: httpGet: { path: /v1/readyz, port: 8443 } resources: requests: { cpu: 100m, memory: 256Mi } limits: { memory: 512Mi } service: app: ports: hub-api: { port: 8443 } hub-link: { port: 51444 }Postgres — multiple replicas
Section titled “Postgres — multiple replicas”Drop the PVC and add the Postgres DSN. mTLS via cert-manager is the recommended setup with CloudNativePG.
spec: values: controllers: towonel-hub: replicas: 2 containers: app: env: TOWONEL_HUB_ENABLED: "true" TOWONEL_EDGE_ENABLED: "false" TOWONEL_HUB_LISTEN_ADDR: 0.0.0.0:8443 TOWONEL_HUB_LINK_LISTEN_ADDR: 0.0.0.0:51444 TOWONEL_HUB_PUBLIC_URL: https://hub.example.eu TOWONEL_HUB_DB_DRIVER: postgres TOWONEL_HUB_DB_DSN: >- postgresql://towonel_hub@pg-pooler-rw.towonel.svc:5432/towonel_hub ?sslmode=verify-full &sslcert=/var/run/secrets/postgresql/tls.crt &sslkey=/var/run/secrets/postgresql/tls.key &sslrootcert=/var/run/secrets/root-ca/ca.crt persistence: postgres-certs: type: secret name: postgres-towonel-hub-cert defaultMode: 0o600 globalMounts: [{ path: /var/run/secrets/postgresql }] root-ca: type: secret name: root-ca defaultMode: 0o440 globalMounts: [{ path: /var/run/secrets/root-ca }]cert-manager issues the client cert with CN towonel_hub; pg_hba on
the CNPG Cluster maps it via hostssl all all all cert clientcert=verify-full map=….
Secret
Section titled “Secret”Hub keys come from env via envFrom. Generate each with
openssl rand -hex 32.
apiVersion: external-secrets.io/v1kind: ExternalSecretmetadata: name: towonel-hubspec: secretStoreRef: kind: ClusterSecretStore name: onepassword target: { name: towonel-hub-secret } data: - secretKey: TOWONEL_IDENTITY_KEY remoteRef: { key: towonel-hub, property: NODE_IDENTITY_KEY } - secretKey: TOWONEL_HUB_OPERATOR_API_KEY remoteRef: { key: towonel-hub, property: OPERATOR_API_KEY } - secretKey: TOWONEL_HUB_KEK remoteRef: { key: towonel-hub, property: HUB_KEK } - secretKey: TOWONEL_INVITE_HASH_KEY remoteRef: { key: towonel-hub, property: INVITE_HASH_KEY } - secretKey: TOWONEL_HUB_LINK_PSK remoteRef: { key: towonel-hub, property: HUB_LINK_PSK }Under Postgres each replica needs the same TOWONEL_IDENTITY_KEY —
auto-generation on first boot would have each replica fork a different
identity, which is why an explicit key is required.
HTTPRoute (Envoy Gateway)
Section titled “HTTPRoute (Envoy Gateway)”route: app: hostnames: [hub.example.eu] parentRefs: - name: envoy-external namespace: network sectionName: https rules: - backendRefs: - identifier: app port: 8443:51444 (hub-link) stays in-cluster — only edges talk to it.
Optional: OIDC + transactional mail
Section titled “Optional: OIDC + transactional mail”TOWONEL_HUB_OIDC_CODEBERG_REDIRECT_URI: https://console.example.eu/api/v1/auth/oidc/codeberg/callback# TOWONEL_HUB_OIDC_CODEBERG_CLIENT_ID/SECRET, TOWONEL_MAIL_MAILJET_* via envFrom