Electric Monk — Apps Overview
All applications are deployed to the electricmonk namespace on a K3s cluster.
Images are pulled from the private registry at registry.lan.ccrow.org.
Secrets are managed by the 1Password Kubernetes Operator (OnePasswordItem).
Domain Map
| Domain | App | Port | Description |
|---|---|---|---|
electricmonk.io / www.electricmonk.io |
em-web (Nginx) | 80 | Static website (Astro) + mail discovery |
auth.electricmonk.io |
Authentik | 9000 | Identity provider (OIDC / LDAP) |
portal.electricmonk.io |
em-portal | 8080 | User portal (Ghost, SSH keys, etc.) |
files.electricmonk.io |
oCIS | 9200 | Cloud file storage (ownCloud Infinite Scale) |
office.electricmonk.io |
OnlyOffice | 80 | In-browser document editing |
mail.electricmonk.io |
Stalwart | 8080 | Mail server (JMAP / SMTP / IMAP) |
webmail.electricmonk.io |
Bulwark Webmail | 3000 | Web-based mail client |
s3.electricmonk.io |
RustFS | 9000 | S3-compatible object storage |
vault.electricmonk.io |
Vaultwarden | 8080 | Password manager (Bitwarden-compatible) |
gitlab.electricmonk.io |
GitLab | 8181 | Git repository hosting (Helm chart) |
registry.electricmonk.io |
GitLab Registry | 5000 | Docker container registry |
chat.electricmonk.io |
Element Web | 80 | Matrix chat client |
synapse.electricmonk.io |
Synapse | 8008 | Matrix homeserver |
account.electricmonk.io |
MAS | 8080 | Matrix Authentication Service (OIDC) |
mrtc.electricmonk.io |
Matrix RTC | — | WebRTC SFU for Element Call |
mastodon.electricmonk.io |
Mastodon | 3000 | ActivityPub social network |
lemmy.electricmonk.io |
Lemmy | 80 | Fediverse link aggregator / forum |
peertube.electricmonk.io |
PeerTube | 9000 | Federated video hosting |
status.electricmonk.io |
Uptime Kuma | 3001 | Public status page |
cs.electricmonk.io |
SSH Server | 22 (LB) → 2222 | SSH/SFTP/rsync access to cloud storage |
*.electricmonk.io |
Ghost (per-user) | 2368 | User-provisioned Ghost blogs (dynamic) |
rust-console.lan.electricmonk.io |
RustFS Console | 9001 | RustFS admin console (LAN only) |
traefik.lan.electricmonk.io |
Traefik Dashboard | — | Reverse proxy dashboard (LAN only) |
TLS
A wildcard certificate (*.electricmonk.io, *.lan.electricmonk.io, *.s3.electricmonk.io)
is provisioned by cert-manager using a letsencrypt-prod-dns01 ClusterIssuer. The
certificate secret (electricmonk-wildcard-tls-secret) lives in kube-system and is
referenced by the Traefik gateway for HTTPS termination.
See: apps/traefik/resources/wildcard-certificates.yaml
Networking
Traefik is the sole ingress controller, deployed via Helm in kube-system. It provides:
- Gateway API (
HTTPRoute) for HTTP/HTTPS traffic - IngressRouteTCP (Traefik CRD) for raw TCP mail ports (SMTP/SMTPS/IMAPS)
- PROXY protocol v2 on all TCP routes so backends see real client IPs
All HTTP services use the traefik-gateway Gateway with websecure (HTTPS) and
web (HTTP → HTTPS redirect) listeners.
Storage
| Backend | Type | Used by | Notes |
|---|---|---|---|
| RustFS | S3-compatible | oCIS, Stalwart, Authentik, GitLab, Matrix (Synapse media), llama-cpp (models) | NFS-backed (10.0.2.11:/c/object) |
| Longhorn (encrypted) | Block (PVC) | oCIS (config + metadata), GitLab Gitaly (50Gi), GitLab Redis (8Gi), Uptime Kuma | LUKS-encrypted, single replica |
| CNPG (PostgreSQL) | Database | Stalwart, Authentik, GitLab, Matrix (Synapse + MAS), Mastodon, Lemmy, Vaultwarden, PeerTube | Auto-provisioned clusters with S3 WAL backup |
Application Details
Traefik (apps/traefik/)
Role: Reverse proxy and ingress controller.
Deployment: Helm chart rendered via src/build.sh into overlays.
Key config:
- Gateway API provider enabled
- Custom TCP entrypoints for SMTP (25), SMTPS (465), IMAPS (993)
- Wildcard TLS cert as default certificate
Authentik (apps/authentik/)
Role: Identity provider — OIDC for oCIS/em-portal, LDAP outpost for Stalwart.
Deployment: Helm chart rendered via src/build.sh.
Key config:
- PostgreSQL via CNPG (
authentik-postgres) - Media storage on RustFS S3 (
authentik-mediabucket) - Helm chart's built-in PostgreSQL sub-chart disabled
- Gateway API route to
auth.electricmonk.io
OIDC Applications served:
- oCIS — file storage login + role assignment
- em-portal — admin portal login
- Stalwart — OAuth2 for webmail (via Stalwart's built-in OAuth)
oCIS (apps/ocis/)
Role: Cloud file storage with S3NG backend and OnlyOffice integration.
Deployment: Kustomize manifests in resources/.
Key config:
- Built-in IDP disabled (
OCIS_EXCLUDE_RUN_SERVICES: idp) - Collaboration service enabled (
OCIS_ADD_RUN_SERVICES: collaboration) - S3NG storage driver → RustFS (
ocis-databucket) - OIDC role assignment from Authentik (
rolesclaim) - CSP whitelist for OnlyOffice domain
- App registry mapping MIME types to OnlyOffice editor
PVCs: ocis-config (1Gi), ocis-data (10Gi) on longhorn-encrypted
Secrets: ocis-oidc-secrets, ocis-s3-creds
See: OCIS_SETUP.md, OCIS_ADMIN_SETUP.md
OnlyOffice (apps/onlyoffice/)
Role: In-browser document editor (WOPI client for oCIS).
Deployment: Kustomize manifests in resources/.
Key config:
- WOPI enabled, JWT disabled (cluster-internal trust)
- Embedded PostgreSQL + Redis (single-pod, no external deps)
- Custom entrypoint override to handle config file initialization
See: ONLYOFFICE_SETUP.md
Stalwart (apps/stalwart/)
Role: Full-featured mail server (SMTP, IMAP, JMAP, admin UI).
Deployment: Kustomize manifests in resources/.
Key config:
- PostgreSQL via CNPG (
stalwart-postgres) - Blob storage on RustFS S3
- Auth via Authentik LDAP outpost (bind auth with user lookup)
- Init container injects admin credentials (SHA-512 hashed)
- Traefik terminates TLS for all mail protocols; PROXY protocol v2
Secrets: stalwart-admin, stalwart-ldap-creds, stalwart-s3-creds, stalwart-postgres-app
See: MAIL_CLIENT_SETTINGS.md (in em-cd repo)
Bulwark Webmail (apps/webmail/)
Role: Web-based mail client for Stalwart.
Deployment: Kustomize manifests in resources/.
Key config:
- Connects to Stalwart via JMAP (
https://mail.electricmonk.io) - OAuth-only auth (Stalwart's built-in OAuth provider)
- Ephemeral storage (
emptyDir)
Secrets: webmail-secrets
RustFS (apps/rustfs/)
Role: S3-compatible object storage (MinIO-compatible).
Deployment: Kustomize manifests in resources/.
Key config:
- NFS-backed data volume (
10.0.2.11:/c/object) - Console on LAN-only domain
Secrets: rustfs-secrets
Buckets: ocis-data, stalwart-data, authentik-media, cnpg-em-backup, gitlab-artifacts, gitlab-lfs, gitlab-uploads, gitlab-packages, gitlab-registry, gitlab-backups
See: apps/rustfs/CREATING_BUCKETS.md (bucket/user/policy setup)
em-web (apps/em-web/)
Role: Public-facing static website (Astro + Nginx).
Deployment: Kustomize manifests in resources/.
Key config:
- Nginx serving Astro-built static files
- Handles
electricmonk.ioandwww.electricmonk.io - Hosts
.well-knownmail discovery files (autoconfig, mta-sts, autodiscover redirect) - Image built from
em-websiterepo via git hook
Image: registry.lan.ccrow.org/em-website:latest
See: EM_WEBSITE_SETUP.md
em-portal (apps/em-portal/)
Role: Admin portal for Electric Monk services.
Deployment: Kustomize manifests in resources/.
Key config:
- OIDC login via Authentik
- Calls em-api internally (
http://em-api:8000)
Secrets: em-portal-secrets
em-api (apps/em-api/)
Role: Backend API for em-portal (SSH key management, Stalwart management, etc.).
Deployment: Kustomize manifests in resources/.
Key config:
- Validates OIDC tokens from em-portal's Authentik provider
- SSH key management: reads/writes
ssh-usersConfigMap, triggers ssh-server restarts - ServiceAccount
em-apiwith RBAC for ConfigMap patch + Deployment restart - Manages Stalwart via admin API
Secrets: em-api-secrets, also reads em-portal-secrets for OIDC config
SSH Server (apps/ssh-server/)
Role: Managed SSH/SFTP/rsync server for cloud storage access.
Deployment: Kustomize manifests in resources/.
Key config:
linuxserver/openssh-serverwith pubkey-only auth- Init container provisions users from
ssh-usersConfigMap (managed by em-api) - NFS-backed home directories (
10.0.2.11:/c/cloud) - LoadBalancer service on port 22
- UIDs start at 10000 for deterministic NFS ownership
ConfigMaps: ssh-server-init (init script), ssh-users (API-managed, NOT in kustomize)
See: SSH_SERVER_SETUP.md
GitLab (apps/gitlab/)
Role: Git repository hosting, CI/CD, container registry.
Deployment: Helm chart deployed via src/deploy.sh (direct helm upgrade --install).
Key config:
- PostgreSQL via CNPG (
gitlab-postgres) - Standalone Redis StatefulSet (
gitlab-redis) - Consolidated object storage on RustFS S3 (6 buckets)
- OIDC login via Authentik
- All bundled sub-charts disabled (Postgres, Redis, NGINX, Prometheus, Runner, KAS)
- Gateway API routes to
gitlab.electricmonk.ioandregistry.electricmonk.io
Secrets: gitlab-secrets, gitlab-oidc-secrets, gitlab-rails-storage, gitlab-registry-storage, storage-config, gitlab-postgres-app
See: GITLAB_SETUP.md
Mastodon (apps/mastodon/)
Role: ActivityPub social network — microblogging, following, and federation.
Deployment: Helm chart deployed via src/deploy.sh.
Key config:
- PostgreSQL via CNPG (
mastodon-postgres) - Redis StatefulSet for Sidekiq job queues
- OIDC login via Authentik
- S3 media storage on RustFS (
mastodon-mediabucket) - Three components:
mastodon-web,mastodon-streaming,mastodon-sidekiq - Gateway API route to
mastodon.electricmonk.io
Secrets: mastodon-secrets, mastodon-oidc-secret, mastodon-s3-secret, mastodon-smtp-secret, redis-password
Lemmy (apps/lemmy/)
Role: Fediverse link aggregator and forum (Reddit-like, ActivityPub-federated).
Deployment: Kustomize manifests in resources/.
Key config:
- PostgreSQL via CNPG (
lemmy-postgres) lemmy-pictrsfor image hosting- Nginx reverse proxy fronting the Lemmy backend and UI
- Gateway API route to
lemmy.electricmonk.io
Secrets: lemmy-secrets
PeerTube (apps/peertube/)
Role: Federated video hosting (ActivityPub).
Deployment: Kustomize manifests in resources/.
Key config:
- PostgreSQL via CNPG (
peertube-postgres) - Redis StatefulSet
- S3 object storage for video files (HLS streaming playlists + web-videos)
- Gateway API route to
peertube.electricmonk.io
Vaultwarden (apps/vaultwarden/)
Role: Self-hosted password manager, Bitwarden API-compatible.
Deployment: Kustomize manifests in resources/.
Key config:
- PostgreSQL via CNPG (
vaultwarden-postgres) - OIDC login via Authentik
- Gateway API route to
vault.electricmonk.io
Secrets: vaultwarden-oidc-secrets
Matrix / Element (apps/matrix/)
Role: Matrix homeserver (Synapse) with Element Web client, Matrix Authentication
Service (MAS) for OIDC, and Element Call / WebRTC SFU.
Deployment: Helm chart (Element Server Suite) deployed via src/deploy.sh.
Key config:
- Synapse PostgreSQL via CNPG (
synapse-postgres) - MAS PostgreSQL via CNPG (
auth-postgres) - S3 media storage on RustFS
- OIDC via Authentik (MAS handles all auth; Synapse delegates to MAS)
- Synapse federation inbound/reader/sender StatefulSets
- Hookshot bot StatefulSet for integrations
- HAProxy fronts Element Web
- Gateway API routes:
chat.electricmonk.io,synapse.electricmonk.io,account.electricmonk.io,mrtc.electricmonk.io,admin.electricmonk.io .well-known/matrix/served viaelectricmonk.ioroute
Secrets: authentik-auth-config, matrix-s3-creds, synapse-mail-config
Ghost (apps/em-ghost/)
Role: User-provisioned Ghost blog sites. Each user gets one blog at a custom
subdomain (<name>.electricmonk.io), spun up through the em-portal.
Deployment: Each Ghost instance is provisioned dynamically by em-api into the
em-ghost namespace. Kustomize base in resources/.
Key config:
- Provisioned and managed by em-api on behalf of authenticated portal users
- Each site gets its own Deployment, Service, PVC, and HTTPRoute
- RBAC in
rbac.yamlgrants em-api the necessary permissions inem-ghost - Network policy controls egress/ingress per site
llama-cpp (apps/llama-cpp/)
Role: LLM inference server for the support bot and other internal consumers.
Deployment: Kustomize manifests in resources/.
Key config:
- Multiple model deployments: default (
qwen2.5-coder-14b), Gemma variants (CPU and GPU-accelerated) - GPU-enabled deployments use NVIDIA device plugin resource limits
- Models stored on RustFS S3 (
llm-modelsbucket), mounted via init container - Internal service only — not exposed via Gateway API
Secrets: models-s3-creds
Support Bot (apps/support-bot/)
Role: AI-powered support chatbot — embedded on the website, backed by Matrix
for conversation history, and uses the MCP server for documentation search.
Deployment: Kustomize manifests in resources/.
Key config:
- FastAPI application exposing
/api/chat/*endpoints (consumed by em-website) - Matrix bot (
@support:electricmonk.io) creates a private room per session - LLM inference via llama-cpp with failover between primary and secondary endpoints
- MCP server (
em-mcpserver) runs as an init container, copiesserver.pyinto a shared volume; the bot subprocess it as a local stdio MCP server - Gateway API route to
supportbot-api.electricmonk.io
Secrets: support-bot-token
Uptime Kuma (apps/uptime-kuma/)
Role: Service uptime monitoring and public status page.
Deployment: Kustomize manifests in resources/.
Key config:
- StatefulSet with Longhorn PVC for persistent monitor state
- Gateway API route to
status.electricmonk.io
Repository Layout
apps/
├── _template/ # Reference build.sh pattern for Helm-based apps
├── authentik/ # Helm-based (src/build.sh → overlays/)
├── em-api/ # Kustomize (resources/) — Backend API for em-portal
├── em-docs/ # In-repo docs (MAIL_CLIENT_SETTINGS.md)
├── em-ghost/ # Kustomize (resources/) — Ghost blog namespace + RBAC
├── em-portal/ # Kustomize (resources/) — User portal
├── em-web/ # Kustomize (resources/) — Static website (Astro/Nginx)
├── gitlab/ # Helm-based (src/deploy.sh) — Git hosting + container registry
├── lemmy/ # Kustomize (resources/) — Fediverse forum
├── llama-cpp/ # Kustomize (resources/) — LLM inference server
├── mastodon/ # Helm-based (src/deploy.sh) — ActivityPub social network
├── matrix/ # Helm-based (src/deploy.sh) — Matrix/Element chat
├── ocis/ # Kustomize (resources/ + overlays/) — Cloud file storage
├── onlyoffice/ # Kustomize (resources/ + overlays/) — Document editor
├── peertube/ # Kustomize (resources/) — Federated video hosting
├── rustfs/ # Kustomize (resources/ + overlays/) — S3 object storage
├── ssh-server/ # Kustomize (resources/) — SSH/SFTP/rsync server
├── stalwart/ # Kustomize (resources/ + overlays/) — Mail server
├── support-bot/ # Kustomize (resources/) — AI support chatbot
├── traefik/ # Helm-based (src/build.sh → overlays/)
├── uptime-kuma/ # Kustomize (resources/) — Status page
├── vaultwarden/ # Kustomize (resources/) — Password manager
└── webmail/ # Kustomize (resources/ + overlays/) — Web mail client
Helm-based apps (Authentik, Traefik, GitLab, Mastodon, Matrix): Use src/build.sh <overlay> to render
Helm templates into overlays/<overlay>/, or src/deploy.sh <overlay> for direct
Helm installs. The rendered YAML (where applicable) is committed and applied via
kubectl apply -k overlays/<overlay>/.
Kustomize apps (everything else): Manifests in resources/, overlays in
overlays/<cluster>/kustomization.yaml. Deploy via kubectl apply -k overlays/<cluster>/.