Production & Maintenance
Deploying Telmoni in high-security production environments requires hardening database access, establishing automated audit partition rotations, configuring TLS reverse proxies, and transitioning authentication from quickstart passwords to enterprise Single Sign-On (OIDC).
Identity & Authentication: Production OIDC Hardening
Section titled “Identity & Authentication: Production OIDC Hardening”When first launching Telmoni, you can bootstrap an initial owner account using ADMIN_EMAIL and ADMIN_PASSWORD. However, local username and password authentication is designed only for quickstarts, local testing, and evaluation.
In a production deployment, we strongly recommend connecting an enterprise OpenID Connect (OIDC) identity provider (such as Okta, Keycloak, Microsoft Entra ID, Authentik, or Google Workspace) and disabling local password forms entirely.
Why use OIDC in production?
Section titled “Why use OIDC in production?”- Centralized Lifecycle & Access Control: When an employee leaves your organization or changes roles, deprovisioning their access in your IdP immediately blocks their Telmoni session.
- Enforce Enterprise MFA: All multi-factor authentication (FIDO2 WebAuthn, hardware security keys, TOTP) is enforced upstream at your identity provider.
- Eliminate Password Attacks: Removing local password forms eliminates credential stuffing, password spraying, and brute-force vectors against your console.
Step-by-step transition to OIDC
Section titled “Step-by-step transition to OIDC”-
Configure your OpenID Connect Provider
Register Telmoni in your Identity Provider (IdP) with the following parameters:
- Allowed Redirect URI:
https://telmoni.example.com/auth/callback - Scopes:
openid,email,profile
- Allowed Redirect URI:
-
Add OIDC variables to your environment
Configure the provider details in your
.envor Kubernetes secret:Terminal window # Identity Provider Discovery URL (must serve /.well-known/openid-configuration)OIDC_ISSUER=https://idp.example.com/realms/productionOIDC_CLIENT_ID=telmoni-client-idOIDC_CLIENT_SECRET=telmoni-client-secretOIDC_REDIRECT_URI=https://telmoni.example.com/auth/callbackOIDC_NAME="Corporate SSO"# Restrict self-registrationOIDC_ALLOW_SIGN_UP=falseALLOW_SIGN_UP=false -
Verify OIDC sign-in
Restart the server and log in using the newly available “Continue with Corporate SSO” button. Confirm that your user identity logs in and gains administrative access.
-
Disable the local password form
Once OIDC login is verified, remove
ADMIN_EMAILandADMIN_PASSWORDfrom your environment and set:Terminal window DISABLE_LOGIN_FORM=true[!IMPORTANT] The Telmoni server performs sanity checks at boot:
- If
DISABLE_LOGIN_FORM=trueis set without a configuredOIDC_ISSUER, the server halts immediately because nobody could sign in. - If
ADMIN_EMAILis set alongsideDISABLE_LOGIN_FORM=true, the server halts because a password account could never log in. RemoveADMIN_EMAILbefore enablingDISABLE_LOGIN_FORM.
- If
Database role hardening
Section titled “Database role hardening”Telmoni enforces strict least-privilege principles at the database layer. In a production cluster, the application modules should never connect as a PostgreSQL superuser.
Role separation
Section titled “Role separation”The database tier is split into four distinct roles:
┌─────────────────┬────────────────────────────────────────────────────────┐│ Role │ Granted Capabilities │├─────────────────┼────────────────────────────────────────────────────────┤│ telmoni_migrator│ Owns all tables, schemas, and views. Runs DDL. ││ telmoni_auth │ CRUD on accounts, orgs, projects, and RBAC tables. ││ telmoni_notif │ CRUD on delivery queues, feeds, and connector records. ││ telmoni_agent │ Read/write on document chunks and vector embeddings. │└─────────────────┴────────────────────────────────────────────────────────┘Applying role hardening
Section titled “Applying role hardening”To apply the production hardening policies, run the superuser setup script provided in the repository:
-
Create the login roles
Connect to your PostgreSQL 17 cluster as a superuser and create the service roles:
CREATE ROLE telmoni_migrator WITH LOGIN PASSWORD 'migrator_secure_password';CREATE ROLE telmoni_auth WITH LOGIN PASSWORD 'auth_secure_password';CREATE ROLE telmoni_notif WITH LOGIN PASSWORD 'notif_secure_password';CREATE ROLE telmoni_agent WITH LOGIN PASSWORD 'agent_secure_password'; -
Execute hardening script
Apply
crates/migrator/sql/role_hardening.sql:Terminal window psql "$SUPERUSER_DATABASE_URL" -v ON_ERROR_STOP=1 -f crates/migrator/sql/role_hardening.sqlThis script:
- Strips
SUPERUSER,CREATEROLE, andCREATEDBfrom all service roles. - Enforces
NOBYPASSRLSacrosstelmoni_auth,telmoni_notif, andtelmoni_agentso that application pools cannot bypass PostgreSQL Row-Level Security policies. - Locks down default permissions in the
publicschema.
- Strips
-
Run migrations and apply object grants
Execute the migrator as the
telmoni_migratoruser:Terminal window MIGRATOR_DATABASE_URL="postgres://telmoni_migrator:migrator_secure_password@postgres:5432/telmoni" \telmoni migrateThe migrator automatically executes
object_grants.sql, granting only the specificSELECT,INSERT,UPDATE, andDELETEprivileges each service module needs to operate.
Audit log partition rotation
Section titled “Audit log partition rotation”Telmoni’s audit log uses range-partitioned tables partitioned monthly by timestamp (occurred_at). To maintain query performance and automatically drop tables that exceed your organization’s retention window, run the rotation command:
telmoni rotateRotation behavior
Section titled “Rotation behavior”- Forward Runway: Always ensures that the current calendar month and the next three months of partitions exist ahead of time (
{table}_YYYY_MM). - Retention Pruning: Automatically drops expired monthly child tables that fall outside your configured retention window.
- Idempotency: Safe to run continuously; if partitions exist, no changes are made.
Scheduling via cron or systemd timer
Section titled “Scheduling via cron or systemd timer”Run the rotation job once per week (or once per day):
0 3 * * 0 root docker compose -f /opt/telmoni/deploy/compose/docker-compose.yml run --rm migrate telmoni rotateOperator CLI sweeps & disaster recovery
Section titled “Operator CLI sweeps & disaster recovery”The telmoni binary includes administrative commands for cluster operators.
Background maintenance sweeps
Section titled “Background maintenance sweeps”While telmoni serve runs scheduled background sweeps in its main loop, you can trigger individual maintenance jobs on demand:
# Execute soft-deletion cleanup saga (permanently purges organizations past 14-day grace)telmoni sweep deletion
# Verify cryptographic hash chain across the audit ledgertelmoni sweep audit-verify
# Purge read notifications and webhook delivery logs past retentiontelmoni sweep retention
# Re-index all document and metadata embeddings into pgvectortelmoni sweep agent-reindexEmergency organization management
Section titled “Emergency organization management”If an organization needs to be terminated or recovered manually by a platform administrator:
# Immediately suspend an organization and enter the 14-day soft-deletion windowtelmoni terminate org_01j7abcde987654321
# Restore a suspended organization within the 14-day grace periodtelmoni restore org_01j7abcde987654321Reverse proxy configuration
Section titled “Reverse proxy configuration”In production, place Telmoni behind a reverse proxy that terminates TLS, enforces HTTP/2 or HTTP/3, and handles WebSocket upgrades. Never expose internal ports 3000 or 8082 directly to the public internet.
Caddy automatically provisions and renews Let’s Encrypt / ZeroSSL certificates:
telmoni.example.com { encode zstd gzip
# Next.js Web Console reverse_proxy localhost:3000 { header_up Host {host} header_up X-Real-IP {remote_host} header_up X-Forwarded-For {remote_host} header_up X-Forwarded-Proto {scheme} }}Standard Nginx configuration with TLS and WebSocket/SSE support:
server { listen 80; server_name telmoni.example.com; return 301 https://$host$request_uri;}
server { listen 443 ssl http2; server_name telmoni.example.com;
ssl_certificate /etc/letsencrypt/live/telmoni.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/telmoni.example.com/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5;
client_max_body_size 25M;
location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1;
# WebSocket and SSE support proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";
proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;
# Timeouts for real-time streams proxy_read_timeout 86400s; proxy_send_timeout 86400s; }}Backups & disaster recovery
Section titled “Backups & disaster recovery”PostgreSQL backups
Section titled “PostgreSQL backups”Telmoni stores all persistent state in PostgreSQL. Create periodic physical or logical backups using pg_dump:
# Logical database dumppg_dump -U telmoni -d telmoni -Fc -f "/backups/telmoni_$(date +%Y%m%d_%H%M%S).dump"To restore from a backup file:
pg_restore -U telmoni -d telmoni --clean --if-exists "/backups/telmoni_backup.dump"[!IMPORTANT] If your deployment uses
CONNECTOR_KEKfor encrypting connector tokens at rest, always safeguard and backup your encryption key alongside your database dumps. Restoring database rows without the matching key will make connector credentials permanently unreadable.
Upgrades
Section titled “Upgrades”To upgrade a self-hosted Telmoni installation:
-
Pull the latest container images
Terminal window docker compose -f deploy/compose/docker-compose.yml pull -
Execute database migrations
Always run the migration step before starting new application containers:
Terminal window docker compose -f deploy/compose/docker-compose.yml run --rm migrate -
Restart the server and web console
Terminal window docker compose -f deploy/compose/docker-compose.yml up -d