Setup of a Prosody XMPP Server on Fedora 37
Setting up an XMPP server is fairly easy with Prosody. This tutorial is a step-by-step guide.
This tutorial is a step-by-step guide meant for the experienced command line user to save time in setting up the details. If you want to setup an XMPP server and can run Fedora 37, you can be sure your XMPP server will work after proceeding these steps.
Prerequisites
Being firm in using the command line.
A domain name, called
foo.net
in this tutorial, andbar.net
as a second domain name.A Fedora server, set up as depicted in Setup of a Server with Fedora 37.
Wording in this tutorial
string |
meaning |
---|---|
foo.net |
domain 1 |
bar.net |
domain 2 |
xxxxxxxxx |
any string |
xx.xx.xxx.xx |
IPv4 address |
xxxx:xxx:xxxx:xxxx::1 |
IPv6 address |
Firewall
First, let's open required ports with the firewall.
Prosody
Compile and install Prosody 0.12 from source, as Fedora 37 only comes with version 0.11. Even though not ideal, you technically can do this directly on the server:
# Source code hg clone https://hg.prosody.im/trunk prosody-trunk mkdir downloads cd downloads hg clone https://hg.prosody.im/trunk prosody-trunk hg pull -u # Compile dnf install libicu libicu-devel openssl openssl-devel ./configure --sysconfdir=/etc/prosody --libdir=/lib64 --datadir=/var/lib/prosody dnf install lua lua-devel make make # Install dnf install lua-expat lua-filesystem lua-rocks lua-sec lua-socket lua-unbound dnf install gcc make install sudo chgrp prosody /var/lib/prosody sudo chmod -R g+w /var/lib/prosody
Create a user that can be used as an admin:
Add it to /etc/prosody/prosody.cfg.lua
(see example
/etc/prosody/prosody.cfg.lua).
Cloud notification on iOS:
# NOTE: mod_cloud_notify_extensions is a meta module that will install # mod_cloud_notify_encrypted, mod_cloud_notify_priority_tag, # and mod_cloud_notify_filters. sudo prosodyctl install --server=https://modules.prosody.im/rocks/ mod_cloud_notify_extensions # Required by mod_cloud_notify_encrypted. sudo dnf install lua-luaossl
mod_vcard_muc
module for Avatar pictures and vCard fields:
Enable all modules as depicted in the example /etc/prosody/prosody.cfg.lua.
Configure VirtualHost
section for each domain as depicted in example
/etc/prosody/prosody.cfg.lua.
Start Prosody:
Certbot
To provide encrypted server-to-client connection, the server needs a
certificate for each domain and sub domain that is configured in
/etc/prosody/prosody.cfg.lua
.
For each domain or sub domain:
Go to your domain provider and point the domain to the server's IP address.
Wait half an hour.
Add domain/sub domain entry to a new
VirtualHost
section of/etc/prosody/prosody.cfg.lua
.Create a certificate with certbot. This will be done in the following steps.
Install
Firewall
Certbot
It is necessary to point the domains to the IP address of the server before continuing. This has already been done above.
Shut down your HTTP server if you have one running. If you don't want to shut
it down, you can keep it running and run sudo certbot certonly --webroot
instead of sudo certbot certonly --standalone
as a command below.
# Request the certificate and import it to Prosody. # Enter all domains and sub domains, e.g. ``example.com upload.example.com``: sudo certbot certonly --standalone
Prosody
# Import sudo prosodyctl --root cert import /etc/letsencrypt/live # Test sudo -u prosody prosodyctl check config -v # Start up sudo systemctl restart prosody.service
Firewall (ONLY IF HTTP PORT IS NOT GENERALLY OPEN FOR SOMETHING ELSE)
Renewing (in about one year)
To renew the certificates in the future, either stop a running HTTP server
(e.g. with sudo systemctl stop caddy.service
) or open port 80 on the
firewall as shown above, and run:
Start the HTTP server (e.g. via sudo systemctl start caddy.service
) or
close the port 80 on the firewall as shown above.
Stable audio/video call
XEP-0215: External Service Discovery (STUN)
Eturnal
Install:
sudo dnf config-manager --add-repo https://eturnal.net/eturnal.repo sudo dnf install eturnal sudo systemctl --now enable eturnal
[https://eturnal.net/documentation/code/readme.html#installation]
Edit sudo vi /etc/eturnal.yml
:
secret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" relay_ipv4_addr: "xx.xx.xxx.xx" relay_ipv6_addr: "xxxx:xxx:xxxx:xxxx::1"
Restart:
Firewall
Prosody
Prosody module external_services
needs to be activated in
/etc/prosody/prosody.cfg.lua
.
Configure external services in sudo vi /etc/prosody/prosody.cfg.lua
(see
example /etc/prosody/prosody.cfg.lua).
Restart:
Backup
Install a proper backup for your server. You don't want your XMPP users lose their accounts or data.
Appendix
Supported functionalities
Our setup provides the following functionality of the XMPP protocol. You
can test it thoroughly on https://compliance.conversations.im. The following
process will reach a 95 % coverage of features. Of course, it's up to you to
configure the last missing XEP (XEP-0368
).
Results
[X] RFC 6121: Roster Versioning
[X] XEP-0215: External Service Discovery (STUN)
[X] XEP-0215: External Service Discovery (TURN)
[X] XEP-0153: ⚡ vCard-Based Avatar (MUC)
[X] XEP-0045: Multi-User Chat
[X] XEP-0065: SOCKS5 Bytestreams (Proxy)
[X] XEP-0115: Entity Capabilities
[X] XEP-0160: Best Practices for Handling Offline Messages
[X] XEP-0163: Personal Eventing Protocol
[X] XEP-0191: Blocking Command
[X] XEP-0198: Stream Management
[X] XEP-0280: Message Carbons
[X] XEP-0313: ⚡ Message Archive Management
[X] XEP-0313: ⚡ Message Archive Management (Multi-User Chat)
[X] XEP-0352: Client State Indication
[X] XEP-0357: Push Notifications
[X] XEP-0363: HTTP File Upload
[ ] XEP-0368: SRV records for XMPP over TLS
[X] XEP-0384: OMEMO Encryption
[X] XEP-0398: User Avatar to vCard-Based Avatars Conversion
Informational Tests
[X] XEP-0157: Contact Addresses for XMPP Services (Abuse)
[X] XEP-0077: In-Band Registration
[ ] XEP-0156: Discovering Alternative XMPP Connection Methods (HTTP)
[X] XEP-0280: Message Carbons - Recommended Rules
[X] XEP-0313: Message Archive Management (extended usage)
[X] XEP-0363: HTTP File Upload (CORS Headers)
[X] XEP-0402: PEP Native Bookmarks
Security and privacy considerations
We configure the server with TLS so the transport from client to server is always encrypted. In addition, for not having to trust what happens on the server, the chat content can always be encrypted by the clients.
However, by XMPPs current design, the user's contact list (roster) is
unencrypted on the server. Encrypted messages still leave log of messages on
the server (the "when and who with whom" information, if you decide to archive
messages for greater sync usability). And the XEPs XEP-0153
and
XEP-0313
always store unencrypted user profile information and logs on the
server.
This is not a problem for you per-se, but your users should be aware of it. They need to trust you as a service provider. It is also a security issue that's not fully under your control, as you can never exclude the possibility of law enforcement requesting data, or your server being hacked.
The fact that profile information is end-to-end-encrypted is my point of criticism of the XMPP protocoll. We have to live with that currently, because there is no other decentralized system that has not at least the metadata problem, including Matrix. (Furthermore, Matrix spreads the all metadata across all systems which is accumulating more metadata on each system, and while Matrix is decentralized by design, in practice it works with some centralized features currently, and comes with opt-out-only tracking features).
At least, in XMPP, all chat content including pictures, voice records, attachments is being encrypted. So as long as users share personal information in encrypted chats, the level of privacy is acceptable. Just be aware that what happens outside the encrypted chat window, especially profile information, is not encrypted.
Example /etc/prosody/prosody.cfg.lua
You can just copy paste this configuration file.
Replace the values from Wording in this tutorial with your own ones.
admins = { "xxxxxxxxx@foo.net" } modules_enabled = { -- Generally required "disco"; -- Service discovery "roster"; -- Allow users to have a roster. Recommended ;) "saslauth"; -- Authentication for clients and servers. Recommended if you want to log in. "tls"; -- Add support for secure TLS on c2s/s2s connections -- Not essential, but recommended "blocklist"; -- Allow users to block communications with other users "bookmarks"; -- Synchronise the list of open rooms between clients "carbons"; -- Keep multiple clients in sync "dialback"; -- s2s dialback support "limits"; -- Enable bandwidth limiting for XMPP connections "pep"; -- Enables users to publish their avatar, mood, activity, playing music and more "smacks"; -- Stream management and resumption (XEP-0198) "private"; -- Private XML storage (for room bookmarks, etc.) "server_contact_info"; -- XEP-0157: Contact Addresses for XMPP Services (Abuse) "vcard4"; -- User profiles (stored in PEP) "vcard_legacy"; -- Conversion between legacy vCard and PEP Avatar, vcard -- Nice to have "csi_simple"; -- XEP-0352 Simple Mobile optimizations --"invites"; -- Create and manage invites --"invites_adhoc"; -- Allow admins/users to create invitations via their client --"invites_register"; -- Allows invited users to create accounts SECURITY CRITICAL "mam"; -- XEP-0313 Store messages in an archive and allow users to access it PRIVACY CRITICAL "ping"; -- Replies to XMPP pings with pongs "register"; -- Allow users to register on this server using a client and change passwords "time"; -- Let others know the time here on this server "uptime"; -- Report how long server has been running "user_account_management"; "version"; -- Replies to server version requests -- Admin interfaces "admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands "admin_shell"; -- Allow secure administration via 'prosodyctl shell' --"admin_telnet"; -- Opens telnet console interface on localhost port 5582 -- HTTP modules --"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP" --"websocket"; -- XMPP over WebSockets --"http_files"; -- Serve static files from a directory over HTTP -- Other specific functionality --"announce"; -- Send announcement to all online users "external_services"; -- XEP-0215: External Service Discovery (STUN) --"groups"; -- Shared roster support --"legacyauth"; -- Legacy authentication. Only used by some old clients and bots. "mimicking"; -- Prevent spoofing attacks "muc_limits"; -- Prevent room floods --"motd"; -- Send a message to users when they log in "proxy65"; -- XEP-0065 Enables a file transfer proxy service which clients behind NAT can use --"s2s_bidi"; -- Bi-directional server-to-server (XEP-0288) --"server_contact_info"; -- Publish contact information for this service "tombstones"; "watchregistrations"; -- Alert admins of registrations --"welcome"; -- Welcome users who register accounts -- Community provided modules "cloud_notify"; -- XEP-0357 Support for sending “push notifications” to clients that need it, typically those running on certain mobile devices "cloud_notify_extensions"; -- XEP-0357 This is a meta-module that simply enables all the modules required to support Siskin or Snikket iOS } modules_disabled = { -- "offline"; -- Store offline messages -- "c2s"; -- Handle client connections -- "s2s"; -- Handle server-to-server connections -- "posix"; -- POSIX functionality, sends server to background, enables syslog, etc. } -- TODO: Fill out with real data. contact_info = { abuse = { "mailto:abuse@localhost", "xmpp:abuse@localhost" }; admin = { "mailto:admin@localhost", "xmpp:admin@localhost" }; feedback = { "http://localhost/feedback.html", "mailto:feedback@localhost", "xmpp:feedback@localhost" }; sales = { "xmpp:sales@localhost" }; security = { "xmpp:security@localhost" }; status = { "gopher://status.localhost" }; support = { "https://localhost/support.html", "xmpp:support@localhost" }; } external_services = { { type = "stun"; transport = "udp"; host = "xx.xx.xxx.xx"; port = 3478; secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }; { type = "turn"; transport = "udp"; host = "xx.xx.xxx.xx"; port = 3478; secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }; } allow_registration = true watchregistrations = true c2s_require_encryption = true s2s_require_encryption = true s2s_secure_auth = true --s2s_insecure_domains = { "insecure.example" } --s2s_secure_domains = { "jabber.org" } -- Rate limits for incoming client and server connections limits = { c2s = { -- rate = "10kb/s"; rate = "3kb/s"; burst = "2s"; }; s2sin = { -- rate = "30kb/s"; rate = "10kb/s"; burst = "5s"; }; } -- Select the authentication backend to use. The 'internal' providers -- use Prosody's configured data storage to store the authentication data. authentication = "internal_hashed" -- Select the storage backend to use. By default Prosody uses flat files -- in its configured data directory, but it also supports more backends -- through modules. An "sql" backend is included by default, but requires -- additional dependencies. See https://prosody.im/doc/storage for more info. --storage = "sql" -- Default is "internal" (Note: "sql" requires installed -- lua-dbi RPM package) -- For the "sql" backend, you can uncomment *one* of the below to configure: --sql = { driver = "SQLite3", database = "prosody.sqlite" } -- Default. 'database' is the filename. --sql = { driver = "MySQL", database = "prosody", username = "prosody", password = "secret", host = "localhost" } --sql = { driver = "PostgreSQL", database = "prosody", username = "prosody", password = "secret", host = "localhost" } -- Archiving configuration -- If mod_mam is enabled, Prosody will store a copy of every message. This -- is used to synchronize conversations between multiple clients, even if -- they are offline. This setting controls how long Prosody will keep -- messages in the archive before removing them. archive_expires_after = "1w" -- Remove archived messages after 1 week -- You can also configure messages to be stored in-memory only. For more -- archiving options, see https://prosody.im/doc/modules/mod_mam -- Logging configuration -- For advanced logging see https://prosody.im/doc/logging log = { -- Log everything of level "info" and higher (that is, all except "debug" messages) -- to /var/log/prosody/prosody.log and errors also to /var/log/prosody/prosody.err info = "/var/log/prosody/prosody.log"; -- Change 'info' to 'debug' for verbose logging error = "/var/log/prosody/prosody.err"; -- Log errors also to file -- error = "*syslog"; -- Log errors also to syslog -- "*console"; -- Log to the console, useful for debugging with daemonize=false } -- Uncomment to enable statistics -- For more info see https://prosody.im/doc/statistics -- statistics = "internal" -- Certificates -- Location of directory to find certificates in (relative to main config file): certificates = "/etc/pki/prosody/" -- HTTPS currently only supports a single certificate, specify it here: --https_certificate = "/etc/prosody/certs/localhost.crt" -- POSIX configuration -- For more info see https://prosody.im/doc/modules/mod_posix pidfile = "/run/prosody/prosody.pid"; --daemonize = false -- Default is "true" ----------- Virtual hosts ----------- -- You need to add a VirtualHost entry for each domain you wish Prosody to serve. -- Settings under each VirtualHost entry apply *only* to that host. --VirtualHost "example.com" -- certificate = "/path/to/example.crt" ----------- Virtual host: foo.net ----------- VirtualHost "foo.net" -- XEP-0045 Multi User Chat Component "conference.foo.net" "muc" name = "The foo.net chatrooms server" restrict_room_creation = false modules_enabled = { "muc_mam", -- XEP-0313: Message Archive Management (Multi-User Chat) "vcard_muc" -- XEP-0153 vCard-Based avatar } -- XEP-0363: HTTP File Upload Component "upload.foo.net" "http_file_share" http_file_share_size_limit = 1024 * 1024 * 200 -- 200 MB http_file_share_daily_quota = 1024 * 1024 * 200 -- 500 MB http_file_share_expires_after = 60 * 60 * 24 * 7 -- a week in seconds ----------- Virtual host: bar.net ----------- VirtualHost "bar.net" -- XEP-0045 Multi User Chat Component "conference.bar.net" "muc" name = "The bar.net chatrooms server" restrict_room_creation = false modules_enabled = { "muc_mam", -- XEP-0313: Message Archive Management (Multi-User Chat) "vcard_muc" -- XEP-0153 vCard-Based avatar } Component "upload.bar.net" "http_file_share" http_file_share_size_limit = 1024 * 1024 * 200 -- 200 MB http_file_share_daily_quota = 1024 * 1024 * 200 -- 500 MB http_file_share_allowed_file_types = { } http_file_share_expires_after = 60 * 60 * 24 * 7 -- a week in seconds ------ Additional config files ------ -- For organizational purposes you may prefer to add VirtualHost and -- Component definitions in their own config files. This line includes -- all config files in /etc/prosody/conf.d/ -- Include "conf.d/*.cfg.lua"