Loading...
 

How to install Prosody with Tiki as its identity provider


Prosody is a lightweight and modular XMPP server.

This guide describes how to configure Prosody so that Tiki acts as its identity provider for:

  • Registered Tiki users
  • Persistent anonymous website visitors
  • Password and temporary-token authentication
  • Community group chats
  • Personalized direct support
  • Tiki group-to-XMPP room mapping
  • MUC room creation and affiliation synchronization
  • Browser chat through Converse.js
  • Native XMPP clients such as Gajim and Monal
  • Mobile push notifications through XEP-0357


The reference deployment described here uses:

  • Prosody 0.12
  • Lua 5.4
  • Apache with PHP-FPM
  • Tiki with persistent guest XMPP identities
  • Converse.js
  • Let's Encrypt certificates
  • firewalld
  • Monal or another XEP-0357-compatible mobile client

 Security

Never publish:

  • The Tiki/Prosody shared secret
  • Administrator passwords
  • Guest passwords
  • Temporary XMPP tokens
  • Database credentials
  • Private TLS keys
  • Push notification device identifiers
  • Authentication URLs containing credentials


Replace every example hostname, path, username and credential before deployment.

The values in this guide are examples only.

 Required Tiki implementation

This guide requires a Tiki version containing all of the following components:

  • tiki-xmpp-auth.php
  • tiki-xmpp-guest-auth.php
  • The tiki_xmpp_guest_credentials table
  • Persistent browser identities stored under tiki-xmpp-guest-identity
  • TIKI_SKIP_HTTP_BASIC_AUTH handling for Prosody endpoints
  • The corresponding Converse.js integration
  • XMPP room and group synchronization support
  • Anonymous destination selection between community and private support
  • Support-presence integration when online or last-seen information is required


A server-only Prosody configuration cannot provide features that are missing from Tiki.


1. Functional overview


The intended user scenarios are:

  • Alice, a website visitor: Tiki creates a persistent guest XMPP identity in her browser. She can return later with the same identity and conversation history.
  • Bob, a registered user: Tiki authenticates him to Prosody and may associate him with the Registered users room.
  • Charlie, a translator: membership in the Translators Tiki group gives him access to the corresponding XMPP room.
  • Dan, an external XMPP user: he may use an external JID when federation, transport and room permissions allow it.
  • Eve, a support agent: she can answer visitors through Converse.js, Gajim, Monal or another XMPP client.
  • An anonymous visitor choosing community: the visitor joins the configured community room.
  • An anonymous visitor choosing private support: the visitor opens a direct conversation with the configured support JID.


Presence is aggregated across XMPP resources. A support agent connected through Gajim, Monal or Converse.js may therefore appear online even when one of the other clients is closed.


2. Deployment status

Feature Status
Prosody HTTP authentication Production baseline
Registered-user existence lookup Production baseline
Temporary Tiki XMPP tokens Production baseline
Persistent guest authentication Production baseline
Guest password hashing and verification Production baseline
TLS for native XMPP clients Production baseline
HTTPS BOSH Production baseline
Secure WebSocket Production baseline
Let's Encrypt import and renewal Production baseline
Community MUC rooms Production baseline
Personalized direct support Production baseline
Anonymous destination selection Production baseline
Multi-resource support presence Production baseline with custom presence modules
Mobile push notifications Production baseline with mod_cloud_notify
Group-to-room synchronization Requires administrator credentials and site-specific testing
External XMPP identities Requires site-specific testing
Public XMPP federation Optional; requires DNS, firewall and remote testing


3. Production architecture


The recommended architecture uses four logical roles:

Role Example hostname
Tiki website tiki.example.org
Registered XMPP users xmpp.example.org
Persistent website guests guest.example.org
Multi-user chat component conference.example.org


The Tiki website and registered-user XMPP VirtualHost may share the same hostname in a compact deployment. The guest VirtualHost and MUC component must still use distinct XMPP domains.

Prosody exposes:

Purpose Port Exposure
Native XMPP clients 5222/tcp Public when native clients are supported
XMPP server-to-server communication 5269/tcp Required for federation and some external push gateways
Unencrypted Prosody HTTP 5280/tcp Private only
HTTPS BOSH and WebSocket 5281/tcp Public for direct browser access


Port 5280 must not be publicly reachable.

Where possible, bind unencrypted HTTP to loopback or protect it with the firewall.


4. Preparation


Confirm that:

  • Tiki is installed at https://tiki.example.org.
  • Tiki manages its users, groups, permissions and passwords.
  • The required Tiki XMPP implementation is present.
  • Apache and PHP-FPM work correctly.
  • Root or sudo access is available.
  • DNS records can be changed.
  • A real Tiki administrator or support account exists.
  • Ports 5222, 5269 when required and 5281 can be opened.
  • The system clock and timezone are correct.
  • Outbound DNS and XMPP S2S connections are allowed.


LDAP, Shibboleth, Active Directory and other external authentication systems require additional testing.


5. DNS configuration


Create A and/or AAAA records for:

  • tiki.example.org
  • xmpp.example.org
  • guest.example.org
  • conference.example.org


For native clients:

DNS
_xmpp-client._tcp.xmpp.example.org. 3600 IN SRV 0 5 5222 xmpp.example.org.


For federation or external push-gateway communication:

DNS
_xmpp-server._tcp.xmpp.example.org. 3600 IN SRV 0 5 5269 xmpp.example.org.


Verify:

bash
dig A tiki.example.org dig A xmpp.example.org dig A guest.example.org dig A conference.example.org dig SRV _xmpp-client._tcp.xmpp.example.org dig SRV _xmpp-server._tcp.xmpp.example.org


All enabled XMPP hosts must resolve correctly.


6. Install Prosody


On Debian or Ubuntu:

bash
sudo apt update sudo apt install -y \ prosody \ prosody-modules \ lua-sec \ certbot \ curl


Verify:

bash
sudo prosodyctl about sudo prosodyctl check config sudo systemctl enable prosody


This guide targets Prosody 0.12 with Lua 5.4.

Prosody 13 includes mod_cloud_notify natively. Before upgrading, test:

  • mod_auth_http
  • Tiki authentication endpoints
  • Persistent guests
  • Custom presence modules
  • MAM
  • Push notifications
  • Converse.js
  • Native clients


Use a currently supported Prosody maintenance release whenever possible.


7. Install required Prosody modules


The deployment requires:

  • mod_auth_http
  • mod_guest_presence_autoapprove
  • mod_support_presence


The Debian prosody-modules package supplies mod_cloud_notify for Prosody 0.12.

First locate the modules:

bash
find /usr/lib/prosody /usr/local/lib/prosody \ \( -name "mod_auth_http.lua" \ -o -name "mod_cloud_notify.lua" \ -o -name "mod_guest_presence_autoapprove.lua" \ -o -name "mod_support_presence.lua" \) \ -type f 2>/dev/null


Site-specific modules may be installed in:

/usr/local/lib/prosody/modules


Configure:

plugin_paths = { "/usr/local/lib/prosody/modules"; }


Production deployments must:

  • Pin reviewed module revisions.
  • Record checksums in deployment automation.
  • Avoid downloading an unreviewed moving tip revision automatically.
  • Test module compatibility after every Prosody update.
  • Install modules with root ownership and mode 0644.

 HTTP authentication transport

Some versions of mod_auth_http send check_password parameters using an HTTP GET query string.

This can expose passwords in web-server access logs even when HTTPS protects the network connection.

A production integration should prefer POST for password-bearing requests. If compatibility requires GET, explicitly redact the pass parameter from Apache, proxy and application logs.


8. Obtain TLS certificates


The certificate must cover:

  • xmpp.example.org
  • guest.example.org
  • conference.example.org


Example:

bash
sudo certbot certonly \ --webroot \ -w /var/www/tiki \ --cert-name tiki-xmpp-prosody \ -d xmpp.example.org \ -d guest.example.org \ -d conference.example.org


The Apache VirtualHost serving the ACME challenge must accept all names.

Example:

ServerName tiki.example.org ServerAlias xmpp.example.org ServerAlias guest.example.org ServerAlias conference.example.org


Validate:

bash
sudo apache2ctl configtest sudo systemctl reload apache2 sudo openssl x509 \ -in /etc/letsencrypt/live/tiki-xmpp-prosody/fullchain.pem \ -noout \ -dates \ -ext subjectAltName


Every Prosody host must appear in the certificate SAN list.


9. Import certificates into Prosody


Import the certificate:

bash
sudo prosodyctl --root cert import \ /etc/letsencrypt/live/tiki-xmpp-prosody


Verify:

bash
sudo ls -l /etc/prosody/certs sudo prosodyctl check certs


A single SAN certificate may be stored under the primary XMPP hostname while covering the guest and conference domains.

Private keys must remain readable only by root and Prosody.


10. Automatic certificate renewal


Create:

/etc/letsencrypt/renewal-hooks/deploy/reload-prosody.sh


Content:

sh
#!/bin/sh set -eu /usr/bin/prosodyctl --root cert import /etc/letsencrypt/live/tiki-xmpp-prosody /usr/bin/systemctl reload prosody || /usr/bin/systemctl restart prosody


Set permissions:

bash
sudo chmod 755 /etc/letsencrypt/renewal-hooks/deploy/reload-prosody.sh


Test renewal:

bash
sudo certbot renew --cert-name tiki-xmpp-prosody --dry-run


Adapt the certificate name when necessary.

Some Certbot versions support run-deploy-hooks, but not all versions do. A plain dry-run does not verify that deployment hooks are executed.

After renewal, verify the certificate actually served by Prosody on port 5222.


11. Shared HTTP authentication secret


Generate a secret:

bash
sudo sh -c \ 'openssl rand -base64 48 | tr -d "/=+\n" | cut -c1-40 > /etc/prosody/xmpp_http_secret' sudo chown root:prosody \ /etc/prosody/xmpp_http_secret sudo chmod 640 \ /etc/prosody/xmpp_http_secret


The same value must be configured in:

  • The registered-user Prosody VirtualHost
  • The persistent-guest Prosody VirtualHost
  • The Tiki xmpp_shared_secret preference


Example:

http_auth_credentials = "prosody:REPLACE_WITH_THE_SHARED_SECRET"


Do not add a separate http_auth_user when http_auth_credentials already contains the API username and secret.

Protect /etc/prosody/prosody.cfg.lua if it contains the secret directly. A protected, deployment-specific included file may also be used for secrets.

Never place the secret in version control or public documentation.


12. Persistent guest table


The persistent guest endpoint requires:

CREATE TABLE IF NOT EXISTS `tiki_xmpp_guest_credentials` ( `username` varchar(64) NOT NULL, `password_hash` varchar(255) NOT NULL, `created` int(11) NOT NULL, `last_seen` int(11) NOT NULL, PRIMARY KEY (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;


Apply schema changes through the normal Tiki installer or upgrade mechanism.

Verify:

SHOW CREATE TABLE tiki_xmpp_guest_credentials;


Guest passwords must be stored with password_hash() and verified with password_verify(). Never store them in plaintext.

Define a retention policy for obsolete guest credentials according to the site's privacy requirements.


13. Tiki authentication endpoints


Tiki requires:

Endpoint Purpose
tiki-xmpp-auth.php Registered users and temporary XMPP tokens
tiki-xmpp-guest-auth.php Persistent website guest identities


Prosody uses:

  • /user_exists
  • /check_password


The endpoints must:

  • Require HTTP Basic Authentication.
  • Accept the API username prosody.
  • Verify xmpp_shared_secret.
  • Reject an empty shared secret.
  • Return plain-text true or false.
  • Return HTTP 403 for invalid API authentication.
  • Never expose supplied passwords in application logs.
  • Use constant-time secret comparison where available.
  • Accept password-bearing requests through POST in the recommended implementation.
  • Retain GET compatibility only when required by the deployed mod_auth_http version.


The registered endpoint checks:

  • A temporary Tiki XMPP token.
  • The current Tiki password when password fallback is intentionally enabled.


The guest endpoint accepts usernames matching:

guest-[20 lowercase hexadecimal characters]


Guest passwords contain:

48 lowercase hexadecimal characters


The first valid guest /check_password request creates the hashed guest record. Later requests use password_verify().

The guest /user_exists method may return true for a syntactically valid new identity before its first password check.


14. PHP-FPM Basic Auth handling


Apache and PHP-FPM may expose the Prosody API credentials as normal website credentials.

Without endpoint-specific handling, Tiki may redirect the request to:

tiki-login.php?challenge=1


Each Prosody endpoint must capture the Authorization header before loading Tiki:

$prosodyAuthorization = $_SERVER['HTTP_AUTHORIZATION'] ?? $_SERVER['Authorization'] ?? $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ?? ''; define('TIKI_SKIP_HTTP_BASIC_AUTH', true); unset( $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'], $_SERVER['AUTH_TYPE'], $_SERVER['HTTP_AUTHORIZATION'], $_SERVER['Authorization'], $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ); require_once __DIR__ . '/tiki-setup.php';


The endpoint must validate the saved $prosodyAuthorization value separately.

The Tiki bootstrap must respect TIKI_SKIP_HTTP_BASIC_AUTH when:

  • Copying REDIRECT_HTTP_AUTHORIZATION
  • Reading apache_request_headers()
  • Performing normal website HTTP Basic Authentication


This behavior must be restricted to the Prosody endpoints.

After changing authentication code:

bash
cd /var/www/tiki php console.php cache:clear sudo systemctl reload php8.2-fpm


Use the correct PHP-FPM service name for the deployment.


15. Apache Authorization forwarding


First test whether the Authorization header reaches PHP. Do not add forwarding directives unnecessarily.

When required:

SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1 CGIPassAuth On <Directory /var/www/tiki> Options -Indexes +IncludesNOEXEC +SymLinksIfOwnerMatch Require all granted SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1 CGIPassAuth On </Directory>


Validate:

bash
sudo apache2ctl configtest sudo systemctl reload apache2


Configure Apache logging so that password-bearing query parameters are not recorded.


16. Complete Prosody configuration


Edit:

/etc/prosody/prosody.cfg.lua


Reference configuration:

plugin_paths = { "/usr/local/lib/prosody/modules"; } admins = { "admin@xmpp.example.org"; } modules_enabled = { "disco"; "roster"; "saslauth"; "tls"; "blocklist"; "bookmarks"; "carbons"; "dialback"; "limits"; "pep"; "private"; "smacks"; "vcard4"; "vcard_legacy"; "csi_simple"; "ping"; "time"; "uptime"; "version"; "mam"; "lastactivity"; "admin_adhoc"; "admin_shell"; "bosh"; "websocket"; "support_presence"; "cloud_notify"; } pidfile = "/run/prosody/prosody.pid"; s2s_secure_auth = true s2s_require_encryption = true archive_expires_after = "never" limits = { c2s = { rate = "10kb/s"; }; s2sin = { rate = "30kb/s"; }; } log = { info = "/var/log/prosody/prosody.log"; error = "/var/log/prosody/prosody.err"; { levels = { "error" }; to = "syslog"; }; } interfaces = { "0.0.0.0"; } http_interfaces = { "0.0.0.0"; } https_interfaces = { "0.0.0.0"; } c2s_interfaces = { "0.0.0.0"; } s2s_interfaces = { "0.0.0.0"; } http_ports = { 5280; } https_ports = { 5281; } consider_websocket_secure = true https_ssl = { key = "/etc/prosody/certs/xmpp.example.org.key"; certificate = "/etc/prosody/certs/xmpp.example.org.crt"; } VirtualHost "xmpp.example.org" ssl = { key = "/etc/prosody/certs/xmpp.example.org.key"; certificate = "/etc/prosody/certs/xmpp.example.org.crt"; } authentication = "http" http_auth_url = "https://tiki.example.org/tiki-xmpp-auth.php" http_auth_credentials = "prosody:REPLACE_WITH_THE_SHARED_SECRET" c2s_require_encryption = true allow_unencrypted_plain_auth = false sasl_mech_list = { "PLAIN"; } disco_items = { { "conference.example.org"; }; } support_jid = "admin@xmpp.example.org" VirtualHost "guest.example.org" ssl = { key = "/etc/prosody/certs/xmpp.example.org.key"; certificate = "/etc/prosody/certs/xmpp.example.org.crt"; } authentication = "http" http_auth_url = "https://tiki.example.org/tiki-xmpp-guest-auth.php" http_auth_credentials = "prosody:REPLACE_WITH_THE_SHARED_SECRET" c2s_require_encryption = true allow_unencrypted_plain_auth = false sasl_mech_list = { "PLAIN"; } allow_registration = false disco_items = { { "conference.example.org"; }; } modules_enabled = { "guest_presence_autoapprove"; } presence_requester_jid = "admin@xmpp.example.org" Component "conference.example.org" "muc" ssl = { key = "/etc/prosody/certs/xmpp.example.org.key"; certificate = "/etc/prosody/certs/xmpp.example.org.crt"; } restrict_room_creation = false modules_enabled = { "muc_mam"; } muc_room_default_persistent = true muc_room_default_public = true muc_room_default_members_only = false muc_room_default_allow_anonymous = true muc_room_default_history_length = 20 muc_max_history_messages = 100 muc_tombstones = true Include "conf.d/*.cfg.lua"


The history settings have different purposes:

  • archive_expires_after = "never" keeps MAM archives indefinitely.
  • muc_room_default_history_length = 20 limits the initial history delivered when joining a room.
  • muc_max_history_messages = 100 limits the room's immediate in-memory history behavior.


An unlimited MAM archive has privacy and storage implications. Production sites should define a retention policy suitable for their users.

Do not leave an unused default localhost VirtualHost enabled.

Validate:

bash
sudo prosodyctl check config sudo prosodyctl check certs sudo systemctl restart prosody sudo systemctl status prosody --no-pager


When adding a module for the first time, restart Prosody or explicitly load the module. A configuration reload alone may not load a newly enabled module.


17. Support presence modules


mod_support_presence and mod_guest_presence_autoapprove support the private help-desk workflow.

The registered-user VirtualHost defines:

support_jid = "admin@xmpp.example.org"


The guest VirtualHost enables:

modules_enabled = { "guest_presence_autoapprove"; } presence_requester_jid = "admin@xmpp.example.org"


Expected behavior:

  • Guests can obtain the configured support account's presence when permitted.
  • The support status may reflect any connected resource.
  • Gajim, Monal and Converse.js resources are treated as sessions of the same bare JID.
  • One unavailable resource must not hide another resource that remains connected.
  • Subscription acknowledgements must not be interpreted as online presence.
  • Fresh direct-message activity may temporarily confirm that the support account is active.
  • Archived messages must not incorrectly mark support as online.


The displayed Last seen value may use XEP-0012 and locally observed activity.

Document this behavior in the site's privacy policy if user activity information is exposed publicly.


18. Mobile push notifications


Mobile push uses XEP-0357 through mod_cloud_notify.

For Prosody 0.12, install the Debian prosody-modules package or a reviewed compatible community module.

Verify:

bash
find /usr/lib/prosody /usr/local/lib/prosody \ -path "*mod_cloud_notify*" \ -type f 2>/dev/null


Required modules:

  • cloud_notify
  • smacks
  • mam
  • carbons


Enable:

modules_enabled = { "smacks"; "mam"; "carbons"; "cloud_notify"; }


By default, do not expose message bodies or sender identities to push gateways:

push_notification_with_body = false push_notification_with_sender = false push_max_devices = 5 push_max_hibernation_timeout = 259200


Validate:

bash
sudo prosodyctl check config sudo systemctl restart prosody


Reconnect the mobile client completely.

A successful registration appears as:

Push notifications enabled for user@xmpp.example.org/ResourceName


The mobile application supplies its own push gateway. Prosody must be able to reach it through encrypted XMPP server-to-server communication.

For Monal, the gateway hostname is operated by the Monal project and must not be hard-coded into the Prosody configuration.

A successful registration proves that XEP-0357 was discovered and accepted. Complete validation also requires:

  1. Close or suspend the mobile application.
  2. Send a message from another account.
  3. Confirm that the device receives a notification.
  4. Reopen the client and confirm that MAM retrieves the message.


Idle S2S connections may close normally and reconnect when needed.


19. Configure firewalld


Check:

bash
systemctl is-active firewalld firewall-cmd --state firewall-cmd --list-ports


Open native client and browser transport ports:

bash
sudo firewall-cmd --permanent --add-port=5222/tcp sudo firewall-cmd --permanent --add-port=5281/tcp


Open S2S when federation or external push gateways require it:

bash
sudo firewall-cmd --permanent --add-port=5269/tcp


Reload:

bash
sudo firewall-cmd --reload


Do not expose:

5280/tcp


Verify:

bash
ss -lnt | grep -E \ ':(5222|5269|5280|5281)[[:space:]]'


A listening socket does not prove public exposure. Confirm the firewall and test from an external network.


20. Configure Tiki


Open:

Administration → XMPP


Configure values equivalent to:

Preference Example
XMPP client ConverseJS
XMPP server domain xmpp.example.org
XMPP client port 5222
Authentication method Prosody HTTP Auth
Registered-user domain xmpp.example.org
Anonymous visitor domain guest.example.org
MUC domain conference.example.org
BOSH URL https://xmpp.example.org:5281/http-bind
WebSocket URL wss://xmpp.example.org:5281/xmpp-websocket
Anonymous community room community@conference.example.org
Registered room registered@conference.example.org
Anonymous private target admin@xmpp.example.org
Anonymous destination behavior Community or private support choice
Support label Support team
Group-room mapping Site-specific JSON mapping
Shared secret Same secret as Prosody
CORS allowed origins https://tiki.example.org
XMPP administrator JID admin@xmpp.example.org
XMPP administrator password Current Tiki password or temporary token
Always Load ConverseJS Enable for site-wide chat
ConverseJS Debug Mode Disable in production


The support account must:

  • Be a real Tiki user.
  • Authenticate through Tiki HTTP Auth.
  • Be included in the Prosody admins list when administrative synchronization is required.
  • Use a secure password.
  • Be reachable through the configured support JID.


Do not use prosodyctl register to create a second password for an HTTP-authenticated VirtualHost.

Clear caches after configuration changes:

bash
cd /var/www/tiki php console.php cache:clear sudo systemctl reload php8.2-fpm


21. Configure Converse.js


Recommended extra settings:

{ "discover_connection_methods": false, "keepalive": true, "persistent_store": "localStorage" }


The dedicated WebSocket preference should contain:

wss://xmpp.example.org:5281/xmpp-websocket


It may also be supplied explicitly:

{ "websocket_url": "wss://xmpp.example.org:5281/xmpp-websocket", "discover_connection_methods": false, "keepalive": true, "persistent_store": "localStorage" }


Use localStorage because persistent guest identities must survive navigation and browser restarts.

Debugging is temporary only:

{ "debug": true }


Disable debug mode in production to avoid excessive console output and performance overhead.

For large private conversations:

  • Load only a reasonable initial page of recent messages.
  • Do not request all MAM pages automatically.
  • Keep older messages available through incremental history loading.
  • Avoid rendering off-screen messages unnecessarily.


These optimizations must not delete archived messages.


22. Persistent guests


Visitors do not use Prosody SASL ANONYMOUS.

Tiki generates:

Username: guest-<20 lowercase hexadecimal characters> Password: <48 lowercase hexadecimal characters>


Example:

guest-0123456789abcdef0123@guest.example.org


Converse.js connects using:

  • authentication: login
  • auto_login: true
  • The generated guest JID
  • The generated guest password


The browser stores the identity under:

tiki-xmpp-guest-identity


On subsequent page loads:

  • A valid stored identity is reused.
  • A missing or malformed identity is replaced.
  • Normal Converse.js cleanup must not remove the Tiki guest identity.
  • Prosody validates credentials through tiki-xmpp-guest-auth.php.


Clearing browser storage intentionally creates a new anonymous identity.


23. Community and private support behavior


When both a community room and private support JID are configured, an anonymous visitor is asked:

How would you like to chat?


Description:

Join the community conversation, or chat privately with a member of our support team.


Choices:

Join the community group Chat privately with a team member


The private conversation header uses:

Support team


Community choice:

  • Connects with the persistent guest identity.
  • Joins the configured community room.
  • Allows conversation with room members and other visitors.


Private choice:

  • Connects with the persistent guest identity.
  • Opens a direct chat with the configured support JID.
  • Does not force the visitor to join a support room.
  • Preserves access to the community option through the normal launcher.


A deployment may configure only one destination. In that case, the available destination may open directly.


24. Group-to-room mapping


Example:

{ "Registered": "registered@conference.example.org", "Translators": "translators@conference.example.org" }


With a by-groups strategy:

  • Registered users receive the registered room.
  • Each mapped Tiki group adds its corresponding room.
  • Administrators may receive community or support rooms.
  • Missing rooms may be created during synchronization.
  • The effective JID receives an appropriate affiliation.
  • Obsolete affiliations may be removed.


Administrative synchronization requires a valid administrator JID and credential.

Test:

  • Group addition
  • Group removal
  • JID changes
  • Room creation
  • Affiliation addition
  • Affiliation removal
  • Authentication failures
  • Existing room permissions


25. External XMPP identities


An external JID may be used only when:

  • It is syntactically valid.
  • The user explicitly selects it.
  • Compatible BOSH or WebSocket transport is available.
  • Federation is configured.
  • The external domain can communicate with the MUC component.
  • Room permissions allow the external identity.


Otherwise Tiki uses:

username@xmpp.example.org


External identity support requires site-specific testing.


26. Add XMPP chat to a Tiki page


Enable the XMPP wiki plugin.

Embedded community chat:

{xmpp room="Community" visibility="anonymous" view_mode="embedded" width="100%" height="600px"}


Floating chat:

{xmpp room="Community" visibility="anonymous" view_mode="overlayed"}


Fullscreen presentation:

{xmpp room="Community" visibility="anonymous" view_mode="fullscreen"}


Other examples:

{xmpp room="Support"} {xmpp room="Registered"}


Group-restricted example:

{GROUP(groups="Translators")} {xmpp room="Translators"} {GROUP}


Complete room JID:

{xmpp room="community@conference.example.org"}


Embedded mode is meaningful only on a page containing the XMPP plugin. Site-wide overlay and fullscreen behavior depends on Converse.js being loaded globally.


27. Test registered-user authentication


Without API authentication:

bash
curl -sS \ -o /dev/null \ -w "%{http_code}\n" \ "https://tiki.example.org/tiki-xmpp-auth.php/user_exists?user=admin"


Expected:

403


With API authentication:

bash
SECRET="$(sudo cat /etc/prosody/xmpp_http_secret)" curl --fail-with-body \ -u "prosody:${SECRET}" \ "https://tiki.example.org/tiki-xmpp-auth.php/user_exists?user=admin" unset SECRET


Expected for an existing user:

true


Do not put a real Tiki password directly in a shell command or query-string URL.


28. Test persistent guest authentication


Use a disposable guest identity.

For a POST-capable endpoint:

bash
GUEST_USER="guest-0123456789abcdef0123" GUEST_PASS="0123456789abcdef0123456789abcdef0123456789abcdef" SECRET="$(sudo cat /etc/prosody/xmpp_http_secret)" curl --fail-with-body \ -u "prosody:${SECRET}" \ --data-urlencode "user=${GUEST_USER}" \ --data-urlencode "pass=${GUEST_PASS}" \ "https://tiki.example.org/tiki-xmpp-guest-auth.php/check_password" unset SECRET GUEST_PASS GUEST_USER


Expected:

true


Repeat with the same password. It must still return true.

A wrong password must return false.

Delete the disposable test row afterward.

If the deployed mod_auth_http requires GET, perform compatibility testing in a controlled environment and ensure the pass parameter is redacted from all logs.


29. Test BOSH

bash
curl -vk \ https://xmpp.example.org:5281/http-bind


Expected:

  • HTTP 200
  • The Prosody BOSH endpoint response


30. Test WebSocket correctly


A normal HTTP request is not a complete WebSocket test.

bash
curl \ --http1.1 \ --max-time 2 \ -vk \ -H "Connection: Upgrade" \ -H "Upgrade: websocket" \ -H "Sec-WebSocket-Protocol: xmpp" \ -H "Sec-WebSocket-Version: 13" \ -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \ https://xmpp.example.org:5281/xmpp-websocket


Expected:

HTTP/1.1 101 Switching Protocols Sec-WebSocket-Protocol: xmpp


A 501 response may mean that the test omitted the XMPP WebSocket subprotocol.


31. Configure native clients


Example Gajim or Monal account:

Setting Value
JID admin@xmpp.example.org
Password Current Tiki password
Server xmpp.example.org
Port 5222
Encryption STARTTLS required
Authentication SASL PLAIN over TLS
Certificate verification Enabled


With correct SRV records, a manual server override may not be necessary.

To join a room:

Room: community Server: conference.example.org


Room JID:

community@conference.example.org


For mobile clients, allow notifications at the operating-system level and reconnect after enabling cloud_notify.


32. Logs and diagnostics


Prosody:

bash
sudo systemctl status prosody --no-pager sudo journalctl -u prosody -f sudo tail -f /var/log/prosody/prosody.log sudo tail -f /var/log/prosody/prosody.err sudo prosodyctl check config sudo prosodyctl check certs


Apache:

bash
sudo tail -f /var/log/apache2/tiki.example.org_access_log sudo tail -f /var/log/apache2/tiki.example.org_error_log


PHP-FPM:

bash
sudo systemctl status php8.2-fpm --no-pager sudo journalctl -u php8.2-fpm -f


Listeners:

bash
ss -lnt | grep -E \ ':(5222|5269|5280|5281)[[:space:]]'


Do not enable verbose Converse.js or Prosody debugging permanently in production.


33. Troubleshooting

33.1 Redirect to tiki-login.php?challenge=1


Cause:

Tiki consumed Prosody's Basic Auth credentials as website-login credentials.

Fix:

  • Capture Authorization before Tiki initialization.
  • Define TIKI_SKIP_HTTP_BASIC_AUTH.
  • Prevent Tiki from consuming or reconstructing the header.
  • Clear caches.
  • Reload PHP-FPM.

33.2 Prosody cannot read its private key


Import certificates:

bash
sudo prosodyctl --root cert import \ /etc/letsencrypt/live/tiki-xmpp-prosody


Reference files under /etc/prosody/certs.

33.3 Prosody serves an expired certificate


Compare the source and served certificates:

bash
sudo openssl x509 -in /etc/letsencrypt/live/tiki-xmpp-prosody/fullchain.pem -noout -dates echo | openssl s_client -connect xmpp.example.org:5222 -starttls xmpp -servername xmpp.example.org 2>/dev/null | openssl x509 -noout -dates -subject -issuer -ext subjectAltName


If automatic renewal did not occur, verify that the Certbot timer is not masked or disabled:

bash
sudo systemctl unmask certbot.timer sudo systemctl enable --now certbot.timer sudo systemctl status certbot.timer


Reimport and restart Prosody when necessary.

Verify the certificate actually presented by Prosody, including its expiration date, hostname and certificate chain.

33.4 WebSocket returns 501


Include:

Sec-WebSocket-Protocol: xmpp

33.5 Guest identity changes on every page


Confirm that:

  • persistent_store is localStorage.
  • tiki-xmpp-guest-identity exists.
  • Cleanup code does not remove it.
  • Username and password formats remain valid.
  • Browser privacy settings are not clearing site storage.

33.6 Administrator synchronization fails


Confirm that:

  • The administrator JID identifies a real Tiki user.
  • The JID is in the Prosody admins list.
  • The password or token is current.
  • Authentication uses tiki-xmpp-auth.php.
  • The MUC domain is correct.

33.7 Private support does not join a support room


This is expected.

The private-support flow opens a direct chat with the configured support JID. It does not automatically join a support room.

33.8 Client reports missing XEP-0357 support


Confirm that:

  • cloud_notify is installed and loaded.
  • smacks, mam and carbons are enabled.
  • Prosody was restarted after enabling the module.
  • The mobile client was fully closed and reconnected.
  • Prosody logs contain Push notifications enabled for ....
  • Port 5269 and outbound S2S connectivity are available when required.


A warning cached before the module was loaded may disappear only after reconnecting the account.

33.9 Support status is incorrect


Confirm that:

  • The configured support JID is the correct bare JID.
  • support_presence is loaded.
  • guest_presence_autoapprove is loaded on the guest VirtualHost.
  • The visitor is authorized to receive support presence.
  • Every connected resource is considered.
  • Unavailable resources are removed independently.
  • Archived messages are not treated as current activity.

33.10 Large private conversations open slowly


Confirm that:

  • The initial local history page is bounded.
  • MAM is not fetching every page automatically.
  • Older messages load incrementally.
  • Converse.js debug mode is disabled.
  • The browser cache contains the current JavaScript build.
  • DOM observers are scoped and disconnected when no longer required.


34. Final production checklist


Before declaring the deployment ready, confirm:

  • The required Tiki XMPP implementation is present.
  • Prosody configuration validation passes.
  • Certificate validation passes for every host.
  • Certificates contain all required SAN names.
  • Prosody, Apache, PHP-FPM and firewalld are active.
  • Port 5280 is not publicly exposed.
  • Port 5222 is reachable when native clients are supported.
  • Port 5269 is reachable when federation or push gateways require S2S.
  • Port 5281 is reachable for direct BOSH and WebSocket.
  • The registered endpoint returns 403 without API authentication.
  • The registered endpoint recognizes an existing user.
  • The guest endpoint returns 403 without API authentication.
  • First guest authentication creates a hashed record.
  • Repeated guest authentication succeeds.
  • A wrong guest password is rejected.
  • Password parameters are absent from or redacted in access logs.
  • BOSH responds correctly.
  • WebSocket returns HTTP 101.
  • Native SASL authentication succeeds through TLS.
  • Converse.js uses localStorage.
  • Community choice joins the configured room.
  • Private choice opens the configured support conversation.
  • The support status recognizes Gajim, Monal and Converse.js resources.
  • One disconnected resource does not hide another connected resource.
  • Group-to-room synchronization has been tested.
  • cloud_notify is loaded.
  • A mobile client registers its push gateway.
  • A closed mobile client receives a real test notification.
  • Converse.js debug mode is disabled in production.
  • MAM retention matches the site's privacy policy.
  • Shared secrets and private keys are not stored in public documentation or version control.
  • The Certbot renewal timer or equivalent scheduler is enabled and active.
  • Automatic certificate renewal has been tested successfully.
  • The Certbot deployment hook imports renewed certificates.
  • The renewed certificate actually served by Prosody has been verified.
  • The served certificate matches the expected hostname and certificate chain.


At this point:

  • Registered Tiki users authenticate to Prosody through HTTP Auth.
  • Website visitors use persistent HTTP-authenticated guest identities.
  • Visitors can choose between community discussion and private support.
  • Converse.js connects through secure WebSocket or HTTPS BOSH.
  • Native clients connect through STARTTLS.
  • Support presence can reflect multiple XMPP clients.
  • Tiki groups can map to MUC rooms.
  • Mobile clients can receive XEP-0357 push notifications.
  • Certificates are imported and refreshed automatically.
  • Only required production ports are publicly exposed.