Get Rewarded! We will reward you with up to €50 credit on your account for every tutorial that you write and we publish!

Installing and Configuring Prosody XMPP Server on Debian 9

profile picture
Author
Noah Seefried
Published
2019-03-07
Time to read
18 minutes reading time

Introduction

Prosody is a modern and well-known xmpp server written in Lua. This tutorial will help you to deploy a state of the art xmpp server which passes all test in the compliance tester but also has some further tweaks.

In this tutorial the latest ("trunk") version is used. It has the most features and it is quite stable.

If you are behind a firewall which only allows some single ports please follow the advanced guide at the bottom.

We will also minimize the metadata and logfiles being stored for privacy reasons.

What you will need at least:

  • A small virtual (cloud) server
  • A own domain (example.com in this tutorial)
  • Basic knowledge about Linux

Assumptions

All commands are executed by default as root user.

You should have a basic installation and SSH access. Make sure your SSH login is secured. We do not setup any firewall in this tutorial. After the installation you can find open ports with netstat -tulpen and restrict them if you want.

The server will be for real on xmpp.example.com. The XMPP-IDs are still user@example.com. To make it easier later we will also point example.com to the server. You do not have to do this, just note the steps during certificate creation.

Example terminology

  • Server IPv4: 10.0.0.1
  • Server IPv6: 2001:db8:1234::1
  • XMPP-ID (username): holu.
  • File Upload: xmpp.example.com
  • MUC (Multi User Chat): conference.example.com (others also use muc. or chat.)
  • Pubsub: pubsub.example.com
  • Proxy: proxy.example.com
  • User Directory (VJUD): vjud.example.com
  • Email addresses or aliases: abuse@example.com, support@example.com, security@example.com
  • Admin email address: holu@example.com

Step 1 - Setup DNS Records

Setup following DNS records:

example.com. 7200 IN A 10.0.0.1
example.com. 7200 IN AAAA 2001:db8:1234::1

xmpp.example.com. 7200 IN A 10.0.0.1
xmpp.example.com. 7200 IN AAAA 2001:db8:1234::1

conference.example.com. 7200 IN A 10.0.0.1
conference.example.com. 7200 IN AAAA 2001:db8:1234::1

pubsub.example.com. 7200 IN A 10.0.0.1
pubsub.example.com. 7200 IN AAAA 2001:db8:1234::1

proxy.example.com. 7200 IN A 10.0.0.1
proxy.example.com. 7200 IN AAAA 2001:db8:1234::1

vjud.example.com. 7200 IN A 10.0.0.1
vjud.example.com. 7200 IN AAAA 2001:db8:1234::1

_xmpp-client._tcp.example.com. 14400 IN  SRV 5 1 5222 xmpp.example.com.
_xmpps-client._tcp.example.com. 14400 IN SRV 10 1 5223 xmpp.example.com.

_xmpp-server._tcp.example.com. 14400 IN SRV 5 0 5269 xmpp.example.com.

_xmpp-server._tcp.conference.example.com. 14400 IN SRV 10 10 5269 xmpp.example.com.

Step 2 - Installation

First we add the official repository to get the latest ("trunk") versions

wget https://prosody.im/files/prosody-debian-packages.key -O- | gpg --dearmor | tee /etc/apt/trusted.gpg.d/prosody.gpg
echo deb http://packages.prosody.im/debian $(lsb_release -sc) main | tee -a /etc/apt/sources.list.d/prosody.list

and then we install the latest build available. We also need gnupg, git and mercurial.

apt-get update && apt-get install prosody-trunk gnupg git mercurial

Do not forget to stop prosody for the moment.

prosodyctl stop

After that we will download the so called "community modules" which will add more super cow power to the xmpp server.

hg clone https://hg.prosody.im/prosody-modules/ /opt/prosody-modules

Prosody needs to be able to access the modules folder, therefore we need to change the owner of the directory.

chown root:prosody -R /opt/prosody-modules/

Now we add a cronjob to update the repository periodically: First run crontab -e and go down to the bottom of the file and create a new line. Paste the following line:

0 18 * * 2 cd /opt/prosody-modules && hg pull --update && chown root:prosody -R /opt/prosody-modules/

As we do not need all community modules and also some official modules still have old versions in the community repository we symlink all needed modules.

mkdir /opt/prosody-modules-enabled/ && cd /opt/prosody-modules-enabled/
(Click to expand) You can just paste the next lines into your command line
ln -s ../prosody-modules/mod_addressing/
ln -s ../prosody-modules/mod_auto_answer_disco_info/
ln -s ../prosody-modules/mod_bidi/
ln -s ../prosody-modules/mod_bob/
ln -s ../prosody-modules/mod_bookmarks/
ln -s ../prosody-modules/mod_cache_c2s_caps/
ln -s ../prosody-modules/mod_carbons_copies/
ln -s ../prosody-modules/mod_checkcerts/
ln -s ../prosody-modules/mod_cloud_notify/
ln -s ../prosody-modules/mod_csi_battery_saver/
ln -s ../prosody-modules/mod_default_bookmarks/
ln -s ../prosody-modules/mod_delay/
ln -s ../prosody-modules/mod_http_avatar/
ln -s ../prosody-modules/mod_http_upload/
ln -s ../prosody-modules/mod_idlecompat/
ln -s ../prosody-modules/mod_muc_limits/
ln -s ../prosody-modules/mod_muc_mam_hints/
ln -s ../prosody-modules/mod_presence_cache/
ln -s ../prosody-modules/mod_privacy_lists/
ln -s ../prosody-modules/mod_pubsub_feeds/
ln -s ../prosody-modules/mod_pubsub_text_interface/
ln -s ../prosody-modules/mod_smacks/
ln -s ../prosody-modules/mod_strict_https/
ln -s ../prosody-modules/mod_vcard_muc/
ln -s ../prosody-modules/mod_vjud/
ln -s ../prosody-modules/mod_watchuntrusted/
ln -s ../prosody-modules/mod_webpresence/

For best support when you later use the client AstraChat we also install mod_img2url:

git clone https://github.com/lixmal/mod_img2url.git /opt/external-prosody-modules/mod_img2url
ln -s ../external-prosody-mod/mod_img2url/mod_img2url.lua

Step 3 - Configuration

Time for the configuration file. Move the original configuration file away:

mv /etc/prosody/prosody.cfg.lua /etc/prosody/prosody.cfg.lua.old

Public registration is disabled by default, you can enable it if you remove the -- in front of the lines under VirtualHost "example.com".

Edit /etc/prosody/prosody.cfg.lua and add the content below.

(Click to expand) prosody.cfg.lua
pidfile = "/var/run/prosody/prosody.pid"

default_storage = "internal"
storage = {
    account_details = "none"
}

authentication = "internal_hashed"

admins = { "holu@example.com" }

contact_info = {
    abuse = { "mailto:abuse@example.com", "xmpp:holu@example.com" };
    admin = { "mailto:support@example.com", "xmpp:holu@example.com" };
    security = { "mailto:security@example.com" };
    support = { "mailto:support@example.com", "xmpp:support@conference.example.com" };
};

https_ssl = {
    key = "/usr/lib/prosody/cert/xmpp.example.com/privkey.pem";
    certificate = "/usr/lib/prosody/cert/xmpp.example.com/fullchain.pem";
}

ssl = {
    key = "/usr/lib/prosody/cert/example.com/privkey.pem";
    certificate = "/usr/lib/prosody/cert/example.com/fullchain.pem";
}

legacy_ssl_ports = 5223

c2s_require_encryption = true;
s2s_require_encryption = true;

s2s_secure_auth = true;

consider_bosh_secure = true

http_default_host = "xmpp.example.com"
http_external_url = "https://xmpp.example.com/"

plugin_paths = { "/opt/prosody-modules-enabled" }
modules_enabled = {

    "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
    "dialback"; -- s2s dialback support
    "disco"; -- Service discovery

-- custom
    "carbons"; -- Keep multiple clients in sync
    "carbons_copies"; -- carbons for legacy clients
    "mam"; -- Store messages in an archive and allow users to access it
    "pep"; -- Enables users to publish their mood, activity, playing music and more
    "private"; -- Private XML storage (for room bookmarks, etc.)
    "default_bookmarks"; -- Default bookmarks for all users
    "blocklist"; -- Allow users to block communications with other users
    "privacy_lists";
    "bookmarks"; -- Bookmarks for xmpp channels
    "vcard4";
    "vcard_legacy";
    "http_avatar"; -- serves avatars from local users
    "strict_https"; -- force https on web
    "offline"; -- Store offline messages
    "version"; -- Replies to server version requests
    "uptime"; -- Report how long server has been running
    "time"; -- Let others know the time here on this server
    "ping"; -- Replies to XMPP pings with pongs
    "admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands
    "bosh"; -- Enable BOSH clients, aka Jabber over HTTP
    "watchregistrations"; -- Alert admins of registrations
    "cloud_notify"; -- allows clients to register an app server which is notified about new messages while the user is offline
    "legacyauth"; -- Legacy authentication. Only used by some old clients and bots
    "announce"; -- Send announcement to all online users
    "smacks"; --  allow a client to resume a disconnected session to prevent message loss
    "csi"; -- https://modules.prosody.im/mod_csi.html
    "csi_battery_saver"; -- Use less battery on mobile phones
    "presence_cache"; -- stores a timestamp of the latest presence received from users contacts
    "checkcerts"; -- Inform admins before certificates expire
    "websocket"; -- Enable mod_websocket
    "net_multiplex";
    "server_contact_info"; -- contact info
    "idlecompat";
    "auto_answer_disco_info";
    "bidi";
    "addressing";
    "webpresence";
    "img2url";
    "watchuntrusted"; -- notify on unencrypted s2s
-- debugging
--    "admin_telnet";
--    "rawdebug";
};

log = {
   warn = "/var/log/prosody/prosody.log";
}

checkcerts_notify = 7 -- in days

registration_watchers = { "holu@example.com" } -- mod_watchregistrations will use this list of users instead of the admin list
registration_notification = "$username registered on $host"

untrusted_fail_watchers = { "holu@example.com" }
untrusted_fail_notification = "Establishing a secure connection from $from_host to $to_host failed. Certificate hash: $sha1. $errors"

default_bookmarks = {
    { jid = "support@conference.example.com", name = "Support Room" };
}

hsts_header = "max-age=31556952"

archive_expires_after = "4w" -- configure message archive
max_archive_query_results = 20;
mam_smart_enable = true
default_archive_policy = "roster" -- archive only messages from users who are in your roster

-- cloud_notify
push_notification_with_body = false -- Whether or not to send the message body to remote pubsub node
push_notification_with_sender = false -- Whether or not to send the message sender to remote pubsub node
push_max_errors = 5 -- persistent push errors are tolerated before notifications for the identifier in question are disabled
push_max_devices = 5 -- number of allowed devices per user

VirtualHost "example.com"
  name = "Prosody"
  modules_enabled = {
--    "register"; -- Allow users to register on this server using a client and change passwords
  }

--  allow_registration = true
--  min_seconds_between_registrations = 900
  http_host = "xmpp.example.com"

ssl = {
    key = "/usr/lib/prosody/cert/example.com/privkey.pem";
    certificate = "/usr/lib/prosody/cert/example.com/fullchain.pem";
}

disco_items = {
    { "example.com", "Prosody" };
    { "conference.example.com", "example.com chatrooms" };
    { "proxy.example.com" };
    { "vjud.example.com" };
}

-- multi user chat
Component "conference.example.com" "muc"
  name = "example.com chatrooms"
  restrict_room_creation = false
  ssl = {
     key = "/usr/lib/prosody/cert/conference.example.com/privkey.pem";
     certificate = "/usr/lib/prosody/cert/conference.example.com/fullchain.pem";
  }

  modules_enabled = {
    "muc_mam"; -- message archive in muc
    "muc_mam_hints";
    "muc_limits";
    "vcard_muc"; -- This module adds the ability to set vCard for MUC rooms.
    "bob";
  }

  muc_log_by_default = true;
  muc_log_all_rooms = false;
  max_history_messages = 20;

Component "xmpp.example.com" "http_upload"
  http_upload_path = "/opt/prosody_http_data"
  http_upload_file_size_limit = 10485760 -- in bytes (10 MB)
  http_upload_expire_after = 60 * 60 * 24 * 3 -- 3 days
  http_upload_quota = 104857600 -- bytes max uploaded by one user (100 MB)

  http_host = "xmpp.example.com"

  ssl = {
     key = "/usr/lib/prosody/cert/xmpp.example.com/privkey.pem";
     certificate = "/usr/lib/prosody/cert/xmpp.example.com/fullchain.pem";
  }

-- pubsub
Component "pubsub.example.com" "pubsub"
  modules_enabled = { "pubsub_feeds", "pubsub_text_interface" }

  ssl = {
     key = "/usr/lib/prosody/cert/pubsub.example.com/privkey.pem";
     certificate = "/usr/lib/prosody/cert/pubsub.example.com/fullchain.pem";
  }

-- proxy
Component "proxy.example.com" "proxy65"
  proxy65_address = "proxy.example.com"
  name = "SOCKS5 Bytestreams Service"

  ssl = {
     key = "/usr/lib/prosody/cert/proxy.example.com/privkey.pem";
     certificate = "/usr/lib/prosody/cert/proxy.example.com/fullchain.pem";
  }

-- vjud, user directory
Component "vjud.example.com" "vjud"

  ssl = {
     key = "/usr/lib/prosody/cert/vjud.example.com/privkey.pem";
     certificate = "/usr/lib/prosody/cert/vjud.example.com/fullchain.pem";
  }

Step 3.1 - Register Let's Encrypt Certificates

Note: If you have pointed example.com to another IP address please generate the certificate for example.com on the other server and copy it over with for example scp.

We will use certbot from EFF for the Let's Encrypt certificates.

apt-get install snapd
snap install --classic certbot
ln -s /snap/bin/certbot /usr/bin/certbot
certbot certonly --standalone --rsa-key-size 4096 -m holu@example.com -d example.com
certbot certonly --standalone --rsa-key-size 4096 -m holu@example.com -d xmpp.example.com
certbot certonly --standalone --rsa-key-size 4096 -m holu@example.com -d conference.example.com
certbot certonly --standalone --rsa-key-size 4096 -m holu@example.com -d proxy.example.com
certbot certonly --standalone --rsa-key-size 4096 -m holu@example.com -d pubsub.example.com
certbot certonly --standalone --rsa-key-size 4096 -m holu@example.com -d vjud.example.com

You will get an email 30 (and 7) days before the certificates expire to holu@example.com. You will also get a notification via XMPP 7 days before the certificates expire.

Step 3.2 - Install the certificates

mkdir /usr/lib/prosody/cert/

mkdir /usr/lib/prosody/cert/example.com
cp -L /etc/letsencrypt/live/example.com/fullchain.pem /usr/lib/prosody/cert/example.com/fullchain.pem ;
cp -L /etc/letsencrypt/live/example.com/privkey.pem /usr/lib/prosody/cert/example.com/privkey.pem ;

mkdir /usr/lib/prosody/cert/xmpp.example.com
cp -L /etc/letsencrypt/live/xmpp.example.com/fullchain.pem /usr/lib/prosody/cert/xmpp.example.com/fullchain.pem ;
cp -L /etc/letsencrypt/live/xmpp.example.com/privkey.pem /usr/lib/prosody/cert/xmpp.example.com/privkey.pem ;

mkdir /usr/lib/prosody/cert/conference.example.com
cp -L /etc/letsencrypt/live/conference.example.com/fullchain.pem /usr/lib/prosody/cert/conference.example.com/fullchain.pem ;
cp -L /etc/letsencrypt/live/conference.example.com/privkey.pem /usr/lib/prosody/cert/conference.example.com/privkey.pem ;

mkdir /usr/lib/prosody/cert/proxy.example.com
cp -L /etc/letsencrypt/live/proxy.example.com/fullchain.pem /usr/lib/prosody/cert/proxy.example.com/fullchain.pem ;
cp -L /etc/letsencrypt/live/proxy.example.com/privkey.pem /usr/lib/prosody/cert/proxy.example.com/privkey.pem ;

mkdir /usr/lib/prosody/cert/pubsub.example.com
cp -L /etc/letsencrypt/live/pubsub.example.com/fullchain.pem /usr/lib/prosody/cert/pubsub.example.com/fullchain.pem ;
cp -L /etc/letsencrypt/live/pubsub.example.com/privkey.pem /usr/lib/prosody/cert/pubsub.example.com/privkey.pem ;

mkdir /usr/lib/prosody/cert/vjud.example.com
cp -L /etc/letsencrypt/live/vjud.example.com/fullchain.pem /usr/lib/prosody/cert/vjud.example.com/fullchain.pem ;
cp -L /etc/letsencrypt/live/vjud.example.com/privkey.pem /usr/lib/prosody/cert/vjud.example.com/privkey.pem ;

chown root:prosody -R /usr/lib/prosody/cert/

Step 4 - Check configuration, start prosody server and create the admin user

Run prosodyctl check to automatically check your configuration file for issues.

You can safely ignore SRV target xmpp.example.com. contains unknown client port: 443 here because we use SSLH to bind to 443 and not prosody itself.

If all checks passes we can start prosody again and check the status if it was successful.

prosodyctl start
prosodyctl status

Check the logfile for further errors.

less /var/log/prosody/prosody.log

Lets create the admin user.

prosodyctl adduser holu@example.com

You can now log in via any XMPP client.

Step 5 - Compliance Tester (Optional)

You should create a separate user for the tester as you have to submit credentials.

prosodyctl adduser compliance@example.com

Enter the credentials into the Compliance Tester and submit them. You should pass here all tests except the informal tests for XEP-0156, which is not important for ranking nor for the features. The XEP-0077 only passes if you have enabled mod_register in the configuration file. You should not enable it for a private server and create new accounts with prosodyctl. You can also subscribe to periodic reports for this server at the bottom left after you submitted the credentials.

Further help and issue reporting

Prosody XMPP Chatroom: prosody@conference.prosody.im via Webchat: Join without account

Mailing lists: https://prosody.im/discuss

Reporting:

Conclusion

We now have a fully featured state of the art XMPP server. You can start chatting with the most popular clients are Gajim for desktop and Conversations for mobile usage. A new and modern clients is Dino for example. For more clients take a look here.

Please do not forget to update your packages regularly with apt-get update && apt-get upgrade, otherwise prosody does not receive any updates. You can also setup a cronjob for this if you want: Execute crontab -e and add @weekly apt-get update && apt-get upgrade at the bottom.

As noticed below we have all features which are required for 100% in the compliance tester https://compliance.conversations.im/.

Next to this, we have more (security) features:

  • Enforced transport encryption
  • Privacy enhanced push notifications because of disabled message body
  • A opt-in user directory
  • Bidirectional Server-to-Server Connections
  • HSTS header for web
  • BOSH under https://xmpp.example.com:5281/http-bind/
  • Websocket under wss://xmpp.example.com:5281/xmpp-websocket or https://xmpp.example.com:5281/xmpp-websocket

Extra features for the administrator:

  • Notification on new registrations
  • Serverwide announcements to all users
  • Information message when certificates threaten to expire
  • Information message when unencrypted connection from another XMPP server fails

Optional advanced features

Expose prosody via port 443 to connect behind a firewall

On public wifi you are often not allowed to use port 5222. The most hotspots only have port 53(DNS), 80(HTTP) and 443(HTTPS) enabled. We can bypass this blockage or better just "use what we have".

We will use SSLH which is an applicative protocol multiplexer.

In both cases add the following DNS records:

_xmpp-client._tcp.example.com. 14400 IN  SRV 15 1 443 xmpp.example.com.
_xmpps-client._tcp.example.com. 14400 IN SRV 20 1 443 xmpp.example.com.

We also need SSLH

apt-get install sslh

Create the configuration directory:

mkdir /etc/sslh/

Edit /etc/default/sslh and put following inside:

RUN=yes
DAEMON=/usr/sbin/sslh

DAEMON_OPTS="-F /etc/sslh/sslh.cfg"

General information if you run a webserver on the same machine

You cannot bind twice to port 443, we will use SSLH to split the http and xmpp traffic.

NOTE: You have to bind your webserver to localhost (127.0.0.1), this will result in a short downtime of your websites as they are not reachable until SSLH is running. You also will see 127.0.0.1 in the access logfiles from your webserver. Check the guide with transparent proxy below if you want to see the real IP addresses.

  • Apache

    • Edit /etc/apache2/ports.conf and change everywhere Listen 443 to Listen 127.0.0.1:443
    • Check all your VirtualHosts in /etc/apache2/sites-available/ and change <VirtualHost *:443> or <VirtualHost 10.0.0.1:443> to <VirtualHost 127.0.0.1:443>
    • Restart Apache with systemctl restart apache2
  • nginx

    • Check all your listen directives in /etc/nginx/sites-available/ and change listen 443; or listen [::]:443; to listen 127.0.0.1:443;
    • Restart nginx with systemctl restart nginx

With a webserver on the same machine (no transparent proxy)

Edit the configuration file /etc/sslh/sslh.cfg

verbose: false;
foreground: false;
inetd: false;
numeric: false;
transparent: false;
timeout: 5;
log_level: 0;
user: "sslh";
pidfile: "/run/sslh/sslh.pid";

listen:
(
    { host: "xmpp.example.com"; port: "443"; }
);

protocols:
(
   { name: "tls"; host: "localhost"; port: "5223"; alpn_protocols: [ "xmpp-client" ]; log_level: 0;},
   { name: "tls"; host: "localhost"; port: "443";},
   { name: "xmpp";    host: "localhost"; port: "5222"; },
   { name: "timeout"; host: "localhost"; port: "443";}
);

on-timeout: "timeout";

And restart SSLH to apply the changes: systemctl restart sslh.

With a webserver on the same machine (transparent proxy)

You cannot bind twice to port 443, we will use SSLH to split the http and xmpp traffic.

NOTE: You have to bind your webserver to localhost (127.0.0.1), this will result in a short downtime of your websites as they are not reachable until SSLH is running.

Edit the configuration file /etc/sslh/sslh.cfg

verbose: false;
foreground: false;
inetd: false;
numeric: false;
transparent: true;
timeout: 5;
log_level: 0;
user: "sslh";
pidfile: "/run/sslh/sslh.pid";

listen:
(
    { host: "xmpp.example.com"; port: "443"; }
);

protocols:
(
   { name: "tls"; host: "localhost"; port: "5223"; alpn_protocols: [ "xmpp-client" ]; log_level: 0;},
   { name: "tls"; host: "localhost"; port: "443";},
   { name: "xmpp";    host: "localhost"; port: "5222"; },
   { name: "timeout"; host: "localhost"; port: "443";}
);

on-timeout: "timeout";

Edit /etc/sysctl.conf and add at the following to the bottom

net.ipv4.conf.all.route_localnet = 1
net.ipv4.conf.default.route_localnet = 1

Apply the changes with sysctl -p

Install iproute2 and iptables:

apt-get install iproute2 iptables

Create the bash script which deploys the iptables rules for the transparent proxy /usr/local/bin/sslh-transparent-proxy.sh.

#!/bin/bash

# DROP martian packets as they would have been if route_localnet was zero
# Note: packets not leaving the server aren't affected by this, thus sslh will still work
iptables -t raw -A PREROUTING ! -i lo -d 127.0.0.0/8 -j DROP
iptables -t mangle -A POSTROUTING ! -o lo -s 127.0.0.0/8 -j DROP

# Mark all connections made by ssl for special treatment (here sslh is run as user "sslh")
iptables -t nat -A OUTPUT -m owner --uid-owner sslh -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -j CONNMARK --set-xmark 0x01/0x0f

# Outgoing packets that should go to sslh instead have to be rerouted, so mark them accordingly (copying over the connection mark)
iptables -t mangle -A OUTPUT ! -o lo -p tcp -m connmark --mark 0x01/0x0f -j CONNMARK --restore-mark --mask 0x0f

# Configure routing for those marked packets
ip rule add fwmark 0x1 lookup 100
ip route add local 0.0.0.0/0 dev lo table 100

Mark it as executable with chmod +x /usr/local/bin/sslh-transparent-proxy.sh

Source: github.com/sslh#transparent-proxy-support

Edit /etc/rc.local and add

bash /usr/local/bin/sslh-transparent-proxy.sh

at the bottom of the file.

Without a webserver

Edit the configuration file /etc/sslh/sslh.cfg

verbose: false;
foreground: false;
inetd: false;
numeric: false;
transparent: false;
timeout: 5;
log_level: 0;
user: "sslh";
pidfile: "/run/sslh/sslh.pid";

listen:
(
    { host: "xmpp.example.com"; port: "443"; }
);

protocols:
(
   { name: "tls"; host: "localhost"; port: "5223"; alpn_protocols: [ "xmpp-client" ]; log_level: 0;},
   { name: "tls"; host: "localhost"; port: "5281";},
   { name: "xmpp";    host: "localhost"; port: "5222"; },
   { name: "timeout"; host: "localhost"; port: "5281";}
);

on-timeout: "timeout";

And restart SSLH to apply the changes: systemctl restart sslh.

XEP-0156: Discovering Alternative XMPP Connection Methods (HTTP)

Although XMPP specifies the use of TCP as the method of connecting to an XMPP server, alternative connection methods exist, including the BOSH (XEP-0124) method (for which XMPP Over BOSH (XEP-0206) is the XMPP profile) and the websocket subprotocol. For some of these methods, it is necessary to discover further parameters before connecting, such as the HTTP URL of an alternative connection manager.

General information

We will create two files host-meta and host-meta.json. Both files have to be located under the domain example.com in the folder /.well-known, you cannot use a subdomain here. If have example.com pointed to another servers IP address you have to deploy the files there.

(Click to expand) Content of host-meta
<?xml version='1.0' encoding='utf-8'?>
<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>
  <Link rel="urn:xmpp:alt-connections:xbosh"
        href="https://xmpp.example.com:5281/http-bind" />
  <Link rel="urn:xmpp:alt-connections:websocket"
        href="wss://xmpp.example.com:5281/xmpp-websocket" />
</XRD>
(Click to expand) Content of host-meta.json
{
  "links": [
    {
      "rel": "urn:xmpp:alt-connections:xbosh",
      "href": "https://xmpp.example.com:5281/http-bind"
    },
    {
      "rel": "urn:xmpp:alt-connections:websocket",
      "href": "wss://xmpp.example.com:5281/xmpp-websocket"
    }
  ]
}

If you have prosody installed without a webserver and exposed via port 443 you can remove :5281 in both host-meta files.

Otherwise you keep it as it is or you deploy a reverse proxy for both. We will not explain in this tutorial on how to do this.

With a webserver (nginx)

Add both files from above to your document root in the folder .well-known. Create the folder if it does not exist as below.

mkdir /var/www/example.com/.well-known

And change permissions to your www (www-data by default) user:

chown www-data:www-data -R /var/www/example.com/.well-known/

We also need to set the Header Access-Control-Allow-Origin "*" in our configuration for the domain example.com. Server configurations are located under /etc/nginx/sites-available/*.

location /.well-known/host-meta {
    default_type 'application/xrd+xml';
    add_header Access-Control-Allow-Origin '*' always;
}
location /.well-known/host-meta.json {
    default_type 'application/jrd+json';
    add_header Access-Control-Allow-Origin '*' always;
}

To apply these changes reload nginx with systemctl reload nginx.

With a webserver (Apache)

Add both files from above to your document root in the folder .well-known. Create the folder if it does not exist as below.

mkdir /var/www/example.com/.well-known

And change permissions to your www (www-data by default) user:

chown www-data:www-data -R /var/www/example.com/.well-known/

We also need to set the Header Access-Control-Allow-Origin "*" in our virtual host for the domain example.com. Virtual hosts are located under /etc/apache2/sites-available/*

<Location ~ "/\.well-known/host-meta(\.json)?">
    Header set Access-Control-Allow-Origin "*"
</Location>

To apply these changes reload Apache with systemctl reload apache2.

Without a webserver

Add "http_files"; in the configuration file /etc/prosody/prosody.cfg.lua to the array modules_enabled = { }. Outside the modules_enabled array add

http_files_dir = "/var/www/prosody/"

and save the configuration file.

Now you have to create the folder .well-known with mkdir -p /var/www/prosody/.well-known and add both files from above into it. Change permissions with chown root:prosody -R /var/www/prosody/ and restart prosody prosodyctl restart.

IRC Gateway with Biboumi

Biboumi is a Free, Libre and Open Source XMPP gateway that connects to IRC servers and translates between the two protocols. Its goal is to let XMPP users take part in IRC discussions, using their favourite XMPP client.

You can find more detailed information about the installation progress in the biboumi documentation.

Want to contribute?

Get Rewarded: Get up to €50 in credit! Be a part of the community and contribute. Do it for the money. Do it for the bragging rights. And do it to teach others!

Report Issue
Try Hetzner Cloud

Get 20€ free credit!

Valid until: 31 December 2024 Valid for: 3 months and only for new customers
Get started
Want to contribute?

Get Rewarded: Get up to €50 credit on your account for every tutorial you write and we publish!

Find out more