homelab/k3s/ejabberd/ejabberd.yaml
Samantha Atkins 7649edba32 wip
2026-04-24 02:38:40 -04:00

337 lines
8.8 KiB
YAML

# ejabberd — XMPP server
# Vhost: xmpp.the-fulfillment.org
# Unpinned — scheduler places freely, local-path PVC for Mnesia data
# TLS terminated externally by Caddy at venture ingress VPS
# (HTTP admin/BOSH/websocket on 5280 is served plain; Caddy fronts it)
# (c2s/s2s use ejabberd's auto-generated self-signed cert for STARTTLS
# until real certs are mounted — see "TLS notes" below)
# No STUN/TURN — add later when available
# No MQTT — skipped
#
# Storage:
# Mnesia (on-disk, via PVC) — default backend for most modules
# PostgreSQL (cluster-local `postgres` service) — only mod_mam (archive + archive_prefs)
# DB schema loaded from /home/ejabberd/sql/pg.new.sql into ejabberd_db.
# SQL password lives in ejabberd-secret and is injected into the rendered
# config at pod start by the `render-config` init container (sed).
#
# NodePorts:
# 32378 — XMPP c2s (5222)
# 32381 — XMPP s2s federation (5269)
# 32382 — HTTP admin / BOSH / websocket / HTTP upload (5280)
#
# Deploy:
# kubectl create secret generic ejabberd-secret \
# --from-literal=admin-password='<password>' \
# --from-literal=erlang-cookie='<random-long-string>' \
# --from-literal=db-password='<postgres-password-for-ejabberd_user>'
#
# # Create DB + user + schema (one-shot, from a host with kubectl):
# kubectl exec -i deploy/postgres -- psql -U postgres <<SQL
# CREATE USER ejabberd_user WITH PASSWORD '<db-password>';
# CREATE DATABASE ejabberd_db ENCODING 'UTF8' LC_COLLATE 'C' LC_CTYPE 'C'
# TEMPLATE template0 OWNER ejabberd_user;
# SQL
# kubectl exec deploy/ejabberd -- cat /home/ejabberd/sql/pg.new.sql \
# | kubectl exec -i deploy/postgres -- psql -U ejabberd_user -d ejabberd_db
#
# kubectl apply -f ejabberd.yaml -n <ns>
#
# First startup does NOT auto-register the admin (CTL_ON_CREATE entrypoint hook
# doesn't expand shell vars). Register manually:
# kubectl exec deploy/ejabberd -- ejabberdctl register admin xmpp.the-fulfillment.org <admin-password>
#
# Admin web UI: http://<any-node-wg-ip>:32382/admin
# (login: admin@xmpp.the-fulfillment.org / <admin-password>)
#
# TLS notes:
# For production federation, mount real certs for xmpp.the-fulfillment.org
# at /home/ejabberd/conf/server.pem (PEM with privkey + fullchain) and
# set certfiles in the ConfigMap to point at it. Many federating servers
# reject self-signed s2s peers.
#
# User registration is CLOSED by default — admin must create accounts via:
# kubectl exec deploy/ejabberd -- ejabberdctl register <user> xmpp.the-fulfillment.org <password>
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ejabberd-data-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: local-path
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: ConfigMap
metadata:
name: ejabberd-config
data:
ejabberd.yml: |
hosts:
- "xmpp.the-fulfillment.org"
loglevel: info
## ejabberd will auto-generate a self-signed cert on first run.
## Replace with real certs for production federation.
certfiles: []
## PostgreSQL — used only by mod_mam (see modules section).
## Password is substituted into a rendered copy of this file at pod
## start by the `render-config` init container.
sql_type: pgsql
sql_server: postgres
sql_port: 5432
sql_database: ejabberd_db
sql_username: ejabberd_user
sql_password: "__SQL_PASSWORD__"
listen:
-
port: 5222
ip: "::"
module: ejabberd_c2s
max_stanza_size: 262144
shaper: c2s_shaper
access: c2s
starttls: true
-
port: 5269
ip: "::"
module: ejabberd_s2s_in
max_stanza_size: 524288
-
port: 5280
ip: "::"
module: ejabberd_http
request_handlers:
"/admin": ejabberd_web_admin
"/api": mod_http_api
"/bosh": mod_bosh
"/ws": ejabberd_http_ws
"/upload": mod_http_upload
s2s_use_starttls: optional
acl:
admin:
user:
- "admin@xmpp.the-fulfillment.org"
local:
user_regexp: ""
access_rules:
local:
allow: local
c2s:
deny: blocked
allow: all
announce:
allow: admin
configure:
allow: admin
muc_create:
allow: local
pubsub_createnode:
allow: local
register:
deny: all
trusted_network:
allow: loopback
api_permissions:
"console commands":
from: ejabberd_ctl
who: all
what: "*"
"admin access":
who:
access:
allow:
acl: admin
what:
- "*"
- "!stop"
- "!start"
shaper:
normal:
rate: 3000
burst_size: 20000
fast: 100000
shaper_rules:
max_user_sessions: 10
max_user_offline_messages:
5000: admin
100: all
c2s_shaper:
none: admin
normal: all
s2s_shaper: fast
modules:
mod_adhoc: {}
mod_admin_extra: {}
mod_announce:
access: announce
mod_avatar: {}
mod_blocking: {}
mod_bosh: {}
mod_caps: {}
mod_carboncopy: {}
mod_client_state: {}
mod_configure: {}
mod_disco: {}
mod_http_api: {}
mod_http_upload:
put_url: "http://@HOST@:5280/upload"
max_size: 104857600 # 100 MB
mod_last: {}
mod_mam:
db_type: sql
assume_mam_usage: true
default: always
mod_muc:
access:
- allow
access_admin:
- allow: admin
access_create: muc_create
access_persistent: muc_create
default_room_options:
mam: true
mod_offline:
access_max_user_messages: max_user_offline_messages
mod_ping: {}
mod_privacy: {}
mod_private: {}
mod_pubsub:
access_createnode: pubsub_createnode
plugins:
- flat
- pep
mod_push: {}
mod_push_keepalive: {}
mod_roster:
versioning: true
mod_sic: {}
mod_stream_mgmt:
resend_on_timeout: if_offline
mod_vcard: {}
mod_vcard_xupdate: {}
mod_version:
show_os: false
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ejabberd
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: ejabberd
template:
metadata:
labels:
app: ejabberd
spec:
securityContext:
fsGroup: 9000
initContainers:
## Render ejabberd.yml from template, substituting the SQL password
## from the ejabberd-secret. Avoids baking the password into the ConfigMap.
- name: render-config
image: busybox:1.37
env:
- name: SQL_PASSWORD
valueFrom:
secretKeyRef:
name: ejabberd-secret
key: db-password
command:
- /bin/sh
- -c
- |
sed "s|__SQL_PASSWORD__|${SQL_PASSWORD}|" /template/ejabberd.yml > /rendered/ejabberd.yml
volumeMounts:
- name: config-template
mountPath: /template
- name: config-rendered
mountPath: /rendered
containers:
- name: ejabberd
image: ejabberd/ecs:latest
env:
- name: ERLANG_NODE
value: ejabberd@localhost
- name: ERLANG_COOKIE
valueFrom:
secretKeyRef:
name: ejabberd-secret
key: erlang-cookie
ports:
- name: c2s
containerPort: 5222
- name: s2s
containerPort: 5269
- name: http
containerPort: 5280
volumeMounts:
- name: config-rendered
mountPath: /home/ejabberd/conf/ejabberd.yml
subPath: ejabberd.yml
- name: data
mountPath: /home/ejabberd/database
readinessProbe:
tcpSocket:
port: 5222
initialDelaySeconds: 20
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 5222
initialDelaySeconds: 60
periodSeconds: 30
volumes:
- name: config-template
configMap:
name: ejabberd-config
- name: config-rendered
emptyDir: {}
- name: data
persistentVolumeClaim:
claimName: ejabberd-data-pvc
---
apiVersion: v1
kind: Service
metadata:
name: ejabberd
spec:
selector:
app: ejabberd
ports:
- name: c2s
port: 5222
targetPort: 5222
nodePort: 32378
- name: s2s
port: 5269
targetPort: 5269
nodePort: 32381
- name: http
port: 5280
targetPort: 5280
nodePort: 32382
type: NodePort