Files
prosody/data/prosody/configuration/prosody.cfg.lua
T
mguschinandClaude Opus 5 7d08ff13d7 Enable stream management and CSI for mobile clients.
Conversations re-authenticated every 5-10 minutes (138 full logins in
two days) because no XEP-0198 module was loaded. Each reconnect re-ran
its OMEMO bootstrap and republished the PEP device list built from a
partial fetch, which dropped the desktop client's device id from the
list. Senders then encrypted to nobody, and Gajim showed "could not be
decrypted" until it reconnected and re-added itself.

smacks lets the session resume across network blips, csi_simple keeps
backgrounded clients quiet. Both ship with Prosody 0.12.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 12:36:48 +03:00

162 lines
5.0 KiB
Lua

-- Prosody XMPP Server Configuration
-- Domain: xmpp.guschin.info
admins = { "admin@guschin.info", "admin@xmpp.guschin.info" }
plugin_paths = { "/usr/lib/prosody/modules" }
modules_enabled = {
-- Generally required
"roster";
"saslauth";
"tls";
"dialback";
"disco";
-- Not essential, but recommended
"carbons";
"pep";
"private";
"vcard";
"version";
"uptime";
"time";
"ping";
"register";
"mam";
-- Mobile-friendly sessions. smacks (XEP-0198) lets a client resume a
-- dropped connection instead of re-authenticating; csi_simple (XEP-0352)
-- lets the server hold back unimportant traffic for backgrounded clients.
-- Without smacks the phone re-authenticated every few minutes, and each
-- reconnect re-ran Conversations' OMEMO bootstrap, which republished the
-- PEP device list without the devices it had not managed to fetch. That
-- silently dropped the desktop client from the list, so messages were
-- encrypted to nobody and could never be decrypted there.
"smacks";
"csi_simple";
-- Admin interface
"admin_adhoc";
-- Gateway support
"privilege";
"http_file_share";
-- Audio/video calls (Jingle): advertise the TURN/STUN server to clients
-- via XEP-0215. Clients do the media themselves; Prosody only signals
-- and hands out time-limited TURN credentials.
"turn_external";
};
modules_disabled = {
-- "offline";
"posix"; -- Disable posix module to avoid threading issues in Docker
};
-- Logging configuration
log = {
info = "/var/log/prosody/prosody.log";
error = "/var/log/prosody/prosody.err";
};
-- Storage configuration for MySQL
storage = "sql"
sql = {
driver = "MySQL";
database = os.getenv("MYSQL_DATABASE") or "prosody";
username = os.getenv("MYSQL_USER") or "prosody";
password = os.getenv("MYSQL_PASSWORD") or "prosodypass";
host = os.getenv("MYSQL_HOST") or "localhost";
port = 3306;
}
-- Port configuration (global section)
c2s_ports = { 5222 }
s2s_ports = { 5269 }
component_ports = { 5347 }
component_interface = "0.0.0.0"
http_ports = { 5280 }
https_ports = { 5281 }
-- Require TLS on c2s/s2s connections
c2s_require_encryption = true
s2s_require_encryption = true
-- Authentication
authentication = "internal_plain"
-- Message archive settings
archive_expires_after = "never"
-- Certificates directory (global, before VirtualHost)
certificates = "/etc/prosody/certs"
-- TURN/STUN for audio/video calls (XEP-0215 External Service Discovery).
-- mod_turn_external does not run a relay itself; it tells clients where the
-- coturn instance is and issues short-lived credentials signed with the
-- shared secret. turn_external_secret must equal static-auth-secret in
-- coturn/turnserver.conf.
--
-- turn_external_host is guschin.info rather than turn.guschin.info because
-- only the former is in the certificate SANs, and turns:// (TLS) clients
-- validate the name against the cert.
turn_external_host = os.getenv("TURN_HOST") or "guschin.info"
turn_external_secret = os.getenv("TURN_SECRET")
turn_external_port = 3478
turn_external_tls_port = 5349
turn_external_ttl = 86400
-- Also advertise TCP transports, not just UDP: some restrictive networks
-- block UDP entirely, and TCP/TLS on 5349 is the fallback that still works.
turn_external_tcp = true
-- Primary virtual host (user@guschin.info)
VirtualHost "guschin.info"
ssl = {
key = "/etc/prosody/certs/guschin.info.key";
certificate = "/etc/prosody/certs/guschin.info.crt";
}
privileged_entities = {
["telegram.guschin.info"] = {
roster = "both"; -- auto add/remove Telegram contacts from roster
message = "outgoing"; -- reflect messages sent via official Telegram apps
iq = {
["http://jabber.org/protocol/pubsub"] = "both"; -- PEP bookmarks
["http://jabber.org/protocol/pubsub#owner"] = "set"; -- message display sync
["urn:xmpp:http:upload:0"] = "get"; -- upload on behalf of users
};
};
}
-- Secondary virtual host (user@xmpp.guschin.info)
VirtualHost "xmpp.guschin.info"
ssl = {
key = "/etc/prosody/certs/guschin.info.key";
certificate = "/etc/prosody/certs/guschin.info.crt";
}
-- Component for MUC (Multi-User Chat)
Component "muc.guschin.info" "muc"
modules_enabled = { "muc_mam" }
storage = "sql"
ssl = {
key = "/etc/prosody/certs/guschin.info.key";
certificate = "/etc/prosody/certs/guschin.info.crt";
}
-- HTTP file upload (XEP-0363) — used by slidgram for Telegram→XMPP attachments
Component "upload.guschin.info" "http_file_share"
http_file_share_access = { "telegram.guschin.info", "guschin.info", "xmpp.guschin.info" }
ssl = {
key = "/etc/prosody/certs/guschin.info.key";
certificate = "/etc/prosody/certs/guschin.info.crt";
}
-- Telegram gateway (slidgram)
Component "telegram.guschin.info"
component_secret = os.getenv("SLIDGRAM_COMPONENT_SECRET")
ssl = {
key = "/etc/prosody/certs/guschin.info.key";
certificate = "/etc/prosody/certs/guschin.info.crt";
}