summaryrefslogtreecommitdiff
path: root/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'index.html')
-rwxr-xr-xindex.html855
1 files changed, 855 insertions, 0 deletions
diff --git a/index.html b/index.html
new file mode 100755
index 0000000..ab6b6e2
--- /dev/null
+++ b/index.html
@@ -0,0 +1,855 @@
+<!DOCTYPE html>
+<html
+ lang="en">
+<head>
+<title>Setting up a XMPP server with a web client (converse.js+nginx+prosody on Debian)</title>
+<link rel='stylesheet'
+ type='text/css' href='styles.css'>
+<meta
+ charset='utf-8'/>
+</head>
+<body>
+<h1>Setting up a XMPP server with a web client (converse.js+nginx+prosody on Debian)</h1>
+<small>[<a
+ href='partage.les-miquelots.net/blog/2021/index.html#setting-up-a-xmpp-server-with-a-web-client-conversejsnginxprosody-on-debian'>link</a>&mdash;<a href='index.html'>standalone</a>]</small>
+<p><b>27/05/2021</b>: add the <samp>http_altconnect</samp> module to prosody config to avoid errors whining about <samp>/.well-known/host-meta</samp> not being present<br>
+<p><b>22/05/2021</b>: don't enable OMEMO by default, we let the users make its own choices and it can be better
+for multi-device history. I improved the apt command too (with <samp>-y --no-install-recommends</samp>).<br><br>
+
+<p>Hi everyone,<br><br>
+<p>Today we're going to install a XMPP server with a web client that is capable to
+send invites links to ease the onboarding of your friends and family.<br>
+I won't explain what is XMPP in great details, because it's outside the scope of this
+guide and some people will explain <i>faaar</i> better than me. I'm thinking about <a
+href="https://www.goffi.org/b/S%C3%A0T_DOTCLEAR_IMPORT_BLOG_default_goffi_99%3A2015%2F06%2F24%2FParlons-XMPP-%C3%A9pisode-1-les-bases">these
+articles on goffi.org (french blog)</a>. For english readers, the <a href="https://wiki.xmpp.org/web/Technology_overview" target="_blank" rel="noopener">official wiki</a> is a good start.<br>
+<b>tl;dr</b>: it's a protocol made of various standards and it's possible to build
+ secure decentralized instant messaging networks with it. There are possibilities
+ to create public and private rooms too, like any popular modern instant messaging software.
+<br><br>
+
+<p><div id="guide-sommaire">
+ <u>Table of matters:</u>
+ <ol>
+ <li><a href="#xmpp-guide-prereq">Prerequisites</a></li>
+ <li><a href="#xmpp-guide-dnszone">DNS zone configuration</a></li>
+ <li><a href="#xmpp-guide-iptables">Firewall configuration</a></li>
+ <li><a href="#xmpp-guide-pkgs">Packages setup</a></li>
+ <li><a href="#xmpp-guide-certs">Certificates setup</a></li>
+ <li><a href="#xmpp-guide-confpkgs">Packages configuration</a></li>
+ <li><a href="#xmpp-guide-con">Discovering the webclient</a></li>
+ <li><a href="#xmpp-guide-genlinks">Invite links generation</a></li>
+
+ <li><a href="#xmpp-guide-remarks">Remarks</a></li>
+ <li><a href="#xmpp-guide-docs">Documentations</a></li>
+ <li><a href="#xmpp-guide-thanks">Thanks</a></li>
+
+
+ </ol>
+ </div>
+ <br><br>
+
+<h3 id="xmpp-guide-prereq"><a href="#xmpp-guide-prereq">1.
+Prerequisites</a></h3>
+
+<p>Enough talking, this is what we're going to install:
+<ul>
+ <li><samp>certbot</samp>: to generate certificates to secure client=&gt;server and server&lt;=&gt;server communication.</li>
+ <li><samp>prosody</samp>: the XMPP server and the most important piece.</li>
+ <li><samp>nginx</samp>: reverse proxy that'll handle <span
+ style="color:green"><b>HTTPS</b></span> and connecting to the XMPP web client.</li>
+ <li><samp>conversejs</samp>: the web client for our XMPP server.</li>
+ <li><samp>libjs-bootstrap4 libjs-jquery</samp>: the
+ <samp><a
+ href="https://modules.prosody.im/mod_invites.html#external-dependencies"
+ target="_blank" rel="noopener" >mod_invites</a></samp> module for Prosody needs
+ these CSS and Javascript libraries for UI.
+ <li><samp>hg</samp>: thanks to it we'll clone the prosody module repo and keep it updated .</li>
+</ul><br>
+
+<p>Agree on a domain name: you'll replace mentions of <samp>example.com</samp> in this
+guide by your chosen domain name. You'll also need subdomains: one for the web client, <samp>chat.example.com</samp>
+, one for groups chats, <samp>salons.example.com</samp>, and finally another for uploading files <samp>f.example.com</samp>.<br>
+Don't forget to add type A records for these subdomains too.
+<br><br>
+
+<h3 id="xmpp-guide-dnszone"><a href="#xmpp-guide-dnszone">2. DNS zone configuration</a></h3>
+<p>First, stay on the DNS zone configuration of your registrar, we'll add some SRV and TXT type entries
+to ease XMPP clients and servers communications with us (more details about this
+<a href="https://wiki.xmpp.org/web/SRV_Records">on the XMPP wiki</a> or <a
+href="https://prosody.im/doc/dns">prosody docs</a>):
+<pre>
+_xmpp-client._tcp.example.com 86400 SRV 1 1 5222 example.com.
+_xmpps-client._tcp.example.com 86400 SRV 1 1 5223 example.com.
+_xmpp-server._tcp.example.com 86400 SRV 1 1 5269 example.com.
+_xmppconnect.example.com TXT _xmpp-client-xbosh=https://chat.example.com/http-bind
+_xmppconnect.example.com TXT _xmpp-client-websocket=wss://chat.example.com/xmpp-websocket
+</pre>
+
+<p><b>NB:</b> the left <samp>example.com</samp> is the XMPP <i>domain</i>, the one
+on the right is the <i>server</i> that'll actually answer requests and you'll need a
+type A record for it, not a CNAME. These records can come in handy when you want
+"clean" users adresses like <u>you@example.com</u> but <samp>example.com</samp> is used for something
+else, for example a website or mailserver, and the XMPP server is set up on <samp>xmpp.example.com</samp> .<br>
+If that's the case, change the <samp>example.com</samp> on the right to <samp>xmpp.example.com</samp>.<br><br>
+
+
+<h3 id="xmpp-guide-iptables"><a href="#xmpp-guide-iptables">3. Firewall configuration</a></h3>
+<p><b><u>IMPORTANT</u>:Log in as root before running the commands in this tutorial.</b>
+We'll then configure the <samp>iptables</samp> rules to avoid eating our fingers
+in rage and confusion later. I'm assuming your default <samp>iptables</samp> policy is set to
+<samp>DROP</samp> and you have some rules set allowing you to SSH into your server:
+<pre>
+iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 5222 -j ACCEPT # client&lt;=&gt;server comms
+iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 5223 -j ACCEPT # same as above but for encrypted ones
+iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 5269 -j ACCEPT # server&lt;=&gt;servers comms
+iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT # for access to webclient
+iptables -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT # HTTPS
+iptables -A OUTPUT -p udp -m udp --dport 53 -j ACCEPT # DNS requests
+iptables -A OUTPUT -p tcp -m tcp --dport 80 -j ACCEPT # useful for updating packages and letsencrypt
+iptables -A OUTPUT -p tcp -m tcp --dport 443 -j ACCEPT # same as above but we HTTPS
+
+iptables-save &gt; /etc/iptables/iptables.rules
+
+
+# pareil pour l'ipv6
+ip6tables -A INPUT -p tcp -m state --state NEW -m tcp --dport 5222 -j ACCEPT
+ip6tables -A INPUT -p tcp -m state --state NEW -m tcp --dport 5223 -j ACCEPT
+ip6tables -A INPUT -p tcp -m state --state NEW -m tcp --dport 5269 -j ACCEPT
+ip6tables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
+ip6tables -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
+ip6tables -A OUTPUT -p udp -m udp --dport 53 -j ACCEPT
+ip6tables -A OUTPUT -p tcp -m tcp --dport 80 -j ACCEPT
+ip6tables -A OUTPUT -p tcp -m tcp --dport 443 -j ACCEPT
+
+ip6tables-save &gt; /etc/iptables/ip6tables.rules
+systemctl enable --now iptables # enable iptables services so rules persists after reboots
+</pre><br>
+
+<h3 id="xmpp-guide-pkgs"><a href="#xmpp-guide-pkgs">4. Packages setup</a></h3>
+
+<p>Next, install <samp>prosody</samp> from
+ <a href="https://prosody.im/doc/installing_from_source">sources</a> or
+<a href="https://prosody.im/download/start">your package manager</a>.
+Two birds one stone, we'll install other needed packages too:
+<pre>sudo apt-get install -y --no-install-recommends prosody nginx-full \
+certbot python3-certbot-nginx \
+mercurial libjs-bootstrap4 libjs-jquery</pre><br>
+
+<p>We'll now clone the <samp>prosody-modules</samp> repo from source. Some distro package managers haven't always this one up to date (looking at you, Debian, stable branch). Execute the following:
+<pre>
+hg clone https://hg.prosody.im/prosody-modules/ /usr/lib/prosody/modules/
+</pre>
+<p>And here below is an updating script that you can put on your <samp>/etc/cron.daily/</samp> folder if it exists, or root crontab. On my server, I created the following file at <samp>/usr/local/sbin/maj_prosodymods.sh</samp>:
+<pre>
+#!/bin/sh
+MODDIR="/usr/lib/prosody/modules/"
+
+if test -d $MODDIR; then
+ cd $MODDIR
+ hg pull --update
+else
+ mkdir -p /usr/lib/prosody
+ hg clone https://hg.prosody.im/prosody-modules/ $MODDIR
+fi
+</pre>
+<p>Don't forget to flip the executable bit with <samp>chmod +x</samp>...
+<br><br>
+
+<p>Then, we'll download <samp>converse.js</samp>.
+On Debian Buster as of 23-05-2021 there isn't an official
+package for it, so we'll whip up another script that we can
+put in a crontab. On my server, I created the file <samp>/usr/local/sbin/update_conversejs.sh</samp> with the following:
+<pre>
+#!/bin/sh
+TEMPDIR="$(mktemp -d)"
+LOG=/var/log/update_conversejs.log # update log path
+WWWDIR='/var/www/chat.example.com' # where static and js files will be downloaded
+WWWUSER='www-data' # this value will differ on the
+ # distro you're using: it'll be 'http' for
+ # Arch Linux nginx for example.
+
+mkdir -p $WWWDIR/dist
+cd $TEMPDIR
+printf "\n\n$(date) - INFO - Starting updating conversejs..." | tee -a $LOG
+CURL_ERR=$(curl -s \ # get latest release tarball
+ https://api.github.com/repos/conversejs/converse.js/releases/latest | \
+ grep -o "https://.*\.tgz" | \
+ grep converse\.js- | \
+ xargs curl -fsOJL) || \
+ (printf "\n$(date) - ERR - Updating conversejs failed." | tee -a $LOG &amp;&amp; exit)
+
+# download libsignal for OMEMO support in conversejs webclient
+if test -e "$WWWDIR/dist/libsignal-protocol.min.js"; then
+ printf "\n$(date) - TOK - Libsignal already installed, skipping." | tee -a $LOG
+else
+ curl -fsOJL \
+ https://cdn.conversejs.org/3rdparty/libsignal-protocol.min.js || \
+ (printf "\n$(date) - ERR - Updating libsignal-protocol-javascript failed." | \
+ tee -a $LOG)
+ cp libsignal*.js $WWWDIR/dist/
+fi
+
+tar xzf *.tgz
+cp -rf package/dist $WWWDIR/
+sed "s/fullscreen\.html/index\.html/g" package/manifest.json &gt; $WWWDIR/manifest.json
+chown $WWWUSER:$WWWUSER -R $WWWDIR/
+chmod 755 -R $WWWDIR/
+rm -rf $TEMPDIR
+printf "\n$(date) - TOK - Done." | tee -a $LOG
+</pre>
+<p>Execute this script after fitting it to your taste, it'll make you
+save time for <a href="#xmpp-guide-confpkgs">step 6</a> because you won't have to create the <samp>$WWWDIR</samp>
+
+<h3 id="xmpp-guide-certs"><a href="#xmpp-guide-certs">5. Certificates setup</a></h3>
+
+<p>It's time to launch certbot to get our certificates.
+I'm assuming and I hope that you already have set up A records for
+the main domain <samp>example.com</samp> and subdomains too (<samp>chat.example.com</samp>, <samp>f.example.com</samp> and <samp>salons.example.com</samp>) in your registrar DNS zone:
+<pre>certbot certonly --agree-tos --nginx --deploy-hook "prosodyctl --root cert import /etc/letsencrypt/live" -d chat.example.com -d example.com -d f.example.com -d salons.example.com </pre>
+<p>Once it executes successfully, the certificates should be in
+<samp>/etc/letsencrypt/live</samp>.
+<br><br>
+
+
+<h3 id="xmpp-guide-confpkgs"><a href="#xmpp-guide-confpkgs">6. Packages configuration</a></h3>
+
+<p>It's time we dive into <samp>prosody</samp> config files.<br>
+Open the file <samp>/usr/lib/prosody/net/http/server.lua</samp>, we'll modify it
+in order to ease connecting nginx with the http interface of prosody (BOSH). In the
+file, find the following line:
+<pre>
+headers = { date = date_header, connection = response_conn_header };
+</pre>
+<p>and replace it by:
+<pre>
+headers = { date = date_header, connection = response_conn_header,
+ access_control_allow_origin = "example.com" };
+-- if 'example.com' dont fix it, replace it by '*'. Remember that your
+-- XMPP server domain name goes here.
+</pre><br>
+
+<p>Then, we'll configure the script that'll allow us to send files to others.
+Execute this:
+<pre>
+mkdir -p /var/www/upload
+chown www-data:www-data /var/www/upload # l'utilisateur de nginx peut
+ # diff&eacute;rer selon la distrib, faites gaffe
+mkdir -p /usr/local/lib/perl
+wget -O /usr/local/lib/perl/upload.pm https://raw.githubusercontent.com/weiss/ngx_http_upload/master/upload.pm
+</pre>
+<p>Open the downloaded file <samp>upload.pm</samp> and search for
+a line like this: <samp>my $external_secret = 'it-is-secret'</samp>.
+Replace <samp>it-is-secret</samp> by a strong passphrase without backslashes
+or quotes to avoid crashing the script due to syntax error later.<br>
+Save or write it down somewhere, it'll be useful very soon.
+<br><br>
+
+<p>Let's now get to write the <samp>prosody</samp> configuration file
+<samp>/etc/prosody/prosody.cfg.lua</samp> with the following:
+<pre>
+admins = { "you@example.com" }
+
+-- For more information see: https://prosody.im/doc/libevent
+-- use_libevent = true
+
+plugin_paths = { "/usr/lib/prosody/modules" }
+
+modules_enabled = {
+
+ -- Generally required
+ "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
+
+ -- Not essential, but recommended
+ "carbons"; -- Keep multiple clients in sync
+ "carbons_copies";
+ "carbons_copies_adhoc";
+ "pep"; -- Enables users to publish their avatar, mood, activity, playing music and more
+ "private"; -- Private XML storage (for room bookmarks, etc.)
+ "blocklist"; -- Allow users to block communications with other users
+ "vcard4"; -- User profiles (stored in PEP)
+ "vcard_legacy"; -- Conversion between legacy vCard and PEP Avatar, vcard
+ "smacks";
+ "bookmarks"; -- old module but compatible with most clients
+ --"bookmarks2";
+ "presence"; -- see user status (online, offline, etc)
+ "offline";
+
+ -- Nice to have
+ "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
+ "register"; -- Allow users to register on this server using a client and change passwords
+ "mam"; -- Store messages in an archive and allow users to access it
+ "csi";
+ "csi_simple"; -- Simple Mobile optimizations
+ "csi_battery_saver";
+ "vjud"; -- recherche d'utilisateurs dans les salons
+
+ -- Admin interfaces
+ "admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands
+
+ -- HTTP modules
+ "bosh"; -- Enable BOSH clients, aka "Jabber over HTTP"
+ "websocket"; -- XMPP over WebSockets
+ "http_altconnect"; -- BOSH and WebSocket connection endpoints discoverable via HTTP
+
+ -- Other specific functionality
+ "posix"; -- POSIX functionality, sends server to background, enables syslog, etc.
+ "limits"; -- Enable bandwidth limiting for XMPP connections
+ "groups"; -- Shared roster support
+ "server_contact_info"; -- Publish contact information for this service
+ "announce"; -- Send announcement to all online users
+ "welcome"; -- Welcome users who register accounts
+ "watchregistrations"; -- Alert admins of registrations
+ "motd"; -- Send a message to users when they log in
+ --"legacyauth"; -- Legacy authentication. Only used by some old clients and bots.
+ --"proxy65"; -- Enables a file transfer proxy service which clients behind NAT can use
+}
+
+-- These modules are auto-loaded, but should you want
+-- to disable them then uncomment them here:
+modules_disabled = {
+ -- "offline"; -- Store offline messages
+ -- "c2s"; -- Handle client connections
+ -- "s2s"; -- Handle server-to-server connections
+}
+
+motd_text = [[Hi everyone ! Welcome to my XMPP server. Have an happy chat !]]
+welcome_message = "It seems it's your first logging in, $username. Welcome and enjoy your stay at $host."
+
+daemonize = false;
+pidfile = "/run/prosody/prosody.pid";
+trusted_proxies = { "127.0.0.1", "::1" }
+
+-- Force certificate authentication for server-to-server connections
+c2s_require_encryption = true -- client to server require encryption
+s2s_require_encryption = true -- server to server require encryption
+s2s_secure_auth = true
+authentication = "internal_hashed"
+
+-- mam settings
+archive_expires_after = "never" -- permanent message history
+
+log = {
+ -- Log files (change 'info' to 'debug' for debug logs):
+ info = "/var/log/prosody/prosody.log";
+ error = "/var/log/prosody/prosody.err";
+ -- Syslog:
+ { levels = { "error" }; to = "syslog"; };
+}
+
+-- http and certificate shenanigans
+certificates = "certs"
+
+-- Include "conf.d/*.cfg.lua"
+
+legacy_ssl_ports = { 5223 }
+-- http_ports = { 5280 }
+-- http_interface = { "*" }
+-- https_ports = { 5281 }
+-- https_interfaces { "*" }
+
+
+cross_domain_bosh = { "https://chat.example.com" }
+cross_domain_websocket = { "https://chat.example.com" }
+consider_bosh_secure = true
+consider_websocket_secure = true
+allow_registration = true -- needed for mod_invites
+registration_invite_only = true -- registration is only permitted through invites
+vjud_mode = "opt-in" -- public search is opt-in
+
+-- https://prosody.im/security/advisory_20210512/
+gc = {
+ speed = 500;
+}
+c2s_stanza_size_limit = 256 * 1024
+s2s_stanza_size_limit = 512 * 1024
+
+limits = {
+ c2s = {
+ rate = "10kb/s";
+ };
+ s2sin = {
+ rate = "3kb/s";
+ };
+}
+-- https://prosody.im/security/advisory_20210512/
+
+ssl = {
+ key = "certs/example.com.key";
+ certificate = "certs/example.com.crt";
+}
+
+VirtualHost "example.com"
+ invites_page = "https://chat.example.com/invite?{invite.token}"
+ webchat_url = "https://chat.example.com/"
+ http_external_url = "https://chat.example.com/"
+ invite_expiry = 86400 * 7
+ http_paths = {
+ invites_page = "/invite";
+ invites_register_web = "/register";
+ }
+
+ modules_enabled = {
+ "invites";
+ "invites_adhoc";
+ "invites_page";
+ "invites_register";
+ "invites_register_web";
+ "http_libjs";
+ }
+
+ contact_info = {
+ abuse = { "mailto:you@example.com", "xmpp:you@example.com" };
+ admin = { "mailto:you@example.com", "xmpp:you@example.com" };
+ security = { "mailto:you@example.com", "xmpp:you@example.com" };
+ support = { "mailto:you@example.com", "xmpp:you@example.com" };
+ };
+
+ https_certificate = "certs/example.com.crt";
+ ssl = {
+ key = "certs/example.com.key";
+ certificate = "certs/example.com.crt";
+ }
+
+ Component "f.example.com" "http_upload_external"
+ http_upload_external_base_url = "https://f.example.com/"
+ http_upload_external_secret = "its-a-secret"
+ http_upload_external_file_size_limit = 104857600 -- limite de &agrave; 100Mo pour les envois de pjs
+ ssl = {
+ key = "certs/f.example.com.key";
+ certificate = "certs/f.example.com.crt";
+ }
+
+ Component "salons.example.com" "muc"
+ name = "Salons (chatrooms) chez example.com"
+ modules_enabled = { "muc_mam", "vcard_muc" }
+ muc_room_default_language = "fr"
+ muc_log_expires_after = "never" -- perm hist for gcs
+ log_all_rooms = true
+ muc_log_by_default = true
+ muc_log_presences = false
+ restrict_room_creation = "admin" -- only admin can create gcs
+ ssl = {
+ key = "certs/salons.example.com.key";
+ certificate = "certs/salons.example.com.crt";
+ }
+</pre>
+<p>As you can guess the <samp>its-a-secret</samp> value there must be replaced
+by the passphrase you wrote down earlier.<br>
+Some of you probably have noticed that the user <u>you@example.com</u>
+was listed as an admin, so let's create him with the following command line:
+<pre>
+prosodyctl check # checks config file
+prosodyctl adduser you@example.com # adapt to your username@domain
+</pre><br>
+
+<p>We'll now start to configure our web client, <samp>converse.js</samp>. Create
+ <samp>/var/www/chat.example.com/index.html</samp> with the following text:
+<pre>
+&lt;!DOCTYPE html&gt;
+&lt;html class="no-js" lang="en"&gt;
+ &lt;head&gt;
+ &lt;title&gt;Converse&lt;/title&gt;
+ &lt;meta charset="utf-8"/&gt;
+ &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"/&gt;
+ &lt;meta name="description" content="Converse XMPP/Jabber Chat"/&gt;
+ &lt;meta name="keywords" content="xmpp chat webchat converse.js" /&gt;
+ &lt;link rel="manifest" href="/manifest.json"&gt;
+ &lt;link type="text/css" rel="stylesheet" media="screen" href="/dist/converse.min.css" /&gt;
+ &lt;script src="/dist/libsignal-protocol.min.js"&gt;&lt;/script&gt;
+ &lt;script src="/dist/converse.min.js"&gt;&lt;/script&gt;
+ &lt;/head&gt;
+ &lt;body class="converse-fullscreen"&gt;
+ &lt;noscript&gt;You need to enable JavaScript to run the Converse.js chat app.&lt;/noscript&gt;
+ &lt;div id="conversejs-bg"&gt;&lt;/div&gt;
+ &lt;script&gt;
+ /*
+ @licstart
+ This is free and unencumbered software released into the public domain.
+
+ Anyone is free to copy, modify, publish, use, compile, sell, or
+ distribute this software, either in source code form or as a compiled
+ binary, for any purpose, commercial or non-commercial, and by any
+ means.
+
+ In jurisdictions that recognize copyright laws, the author or authors
+ of this software dedicate any and all copyright interest in the
+ software to the public domain. We make this dedication for the benefit
+ of the public at large and to the detriment of our heirs and
+ successors. We intend this dedication to be an overt act of
+ relinquishment in perpetuity of all present and future rights to this
+ software under copyright law.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+
+ For more information, please refer to &lt;http://unlicense.org/&gt;
+ @licend
+ */
+ converse.initialize({
+ auto_away: 300, // in seconds
+ auto_list_rooms: true,
+ auto_reconnect: true,
+ auto_xa: 600, // extended away, in seconds
+ bosh_service_url: 'https://chat.example.com/http-bind/',
+ csi_waiting_time: 60, // smartphone battery optimizations
+ enable_smacks: true,
+ locked_domain: example.com, // xmpp server that the client will only be allowed to connect to
+ message_archiving: 'always',
+ persistent_store: 'IndexedDB', // jcbrand said it'll be fast in 8.0.0 and better than localStorage
+ play_sounds: true,
+ theme: 'concord', // dark theme
+ view_mode: 'fullscreen',
+ websocket_url: 'wss://chat.example.com/xmpp-websocket', // can be unstable, if you got problems
+ // don't hesitate to comment it
+ });
+ &lt;/script&gt;
+ &lt;/body&gt;
+&lt;/html&gt;
+</pre><br>
+
+<p>This guide is almost done ! We now need to do the nginx config files.<br>
+Let's start with <samp>/etc/nginx/sites-enabled/example.com.conf</samp>:
+<pre>
+server {
+ listen 80;
+ server_name example.com;
+
+ location / {
+ return 301 https://$host$uri;
+ }
+}
+
+server {
+ listen 443 ssl;
+ server_nam example.com;
+ ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
+
+ proxy_set_header Access-Control-Allow-Origin 'chat.example.com';
+
+ # this block is for the prosody's http_altconnect module
+ location ~* host-(meta|meta\.json) {
+ proxy_pass http://example.com:5280$uri;
+ proxy_http_version 1.1;
+ }
+}
+</pre><br>
+
+<p>Next, let's continue with
+ <samp>/etc/nginx/sites-enabled/f.example.com.conf</samp>, it's the config file for
+ uploading files:
+<pre>
+perl_modules /usr/local/lib/perl; # Path to upload.pm.
+perl_require upload.pm;
+
+server {
+ listen 80;
+ server_name f.example.com;
+ location / {
+ return 301 https://$host$request_uri;
+ }
+}
+
+server {
+ # Specify directives such as "listen", "server_name", and TLS-related
+ # settings for the "server" that handles the uploads.
+ listen 443 ssl http2;
+ server_name f.example.com;
+
+ ssl_certificate /etc/letsencrypt/live/f.example.com/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/f.example.com/privkey.pem;
+ # Uploaded files will be stored below the "root" directory. To minimize
+ # disk I/O, make sure the specified path is on the same file system as
+ # the directory used by Nginx to store temporary files holding request
+ # bodies ("client_body_temp_path", often some directory below /var).
+ root /var/www/upload;
+ index index.html;
+ # Specify this "location" block (if you don't use "/", see below):
+ location / {
+ perl upload::handle;
+ }
+
+ # Upload file size limit (default: 1m), also specified in your XMPP
+ # server's upload module configuration (see below):
+ client_max_body_size 100m;
+}
+</pre>
+
+<p>Execute <samp>nginx -t</samp> to test the config files created so far.
+Once no errors are detected create
+ <samp>/etc/nginx/sites-enabled/chat.example.com.conf</samp>:
+<pre>
+server {
+ listen 80;
+ server_name chat.example.com;
+
+ location / {
+ return 301 https://$host$uri;
+ }
+}
+
+server {
+ listen 443 ssl http2;
+ ssl_certificate /etc/letsencrypt/live/chat.example.com/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/chat.example.com/privkey.pem;
+ root /var/www/chat.example.com;
+ index index.html;
+
+ # XMPP BOSH
+ location ^~ /http-bind {
+ proxy_pass https://example.com:5281/http-bind;
+ proxy_http_version 1.1;
+ proxy_set_header Host example.com;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_buffering off;
+ tcp_nodelay on;
+ }
+
+ # XMPP HTTP-Upload
+ location ^~ /upload {
+ proxy_pass https://f.example.com; proxy_http_version 1.1;
+ proxy_set_header Host example.com;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_set_header X-Forwarded-For $remote_addr;
+ proxy_buffering off;
+ tcp_nodelay on;
+ }
+
+ # XMPP Websockets
+ location /xmpp-websocket {
+ proxy_pass http://example.com:5280/xmpp-websocket;
+ proxy_http_version 1.1;
+ proxy_buffering off;
+ proxy_set_header Connection "Upgrade";
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Host $host;
+ proxy_set_header X-Forwarded-For $remote_addr;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_read_timeout 900s;
+ }
+
+ # XMPP Account invite
+ location ^~ /invite {
+ proxy_pass https://example.com:5281/invite;
+ proxy_http_version 1.1;
+ proxy_set_header Host example.com;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_set_header X-Forwarded-For $remote_addr;
+ proxy_buffering off;
+ tcp_nodelay on;
+ }
+
+ # XMPP account register
+ location ^~ /register {
+ proxy_pass https://example.com:5281/register;
+ proxy_http_version 1.1;
+ proxy_set_header Host example.com;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_set_header X-Forwarded-For $remote_addr;
+ proxy_buffering off;
+ tcp_nodelay on;
+ }
+
+ # sur mon vps debian j'ai eu besoin de &ccedil;a pour
+ # que les pages d'invitation soit bien
+ # format&eacute;es
+ location = /share/bootstrap4/css/bootstrap.min.css {
+ alias /usr/lib/nodejs/bootstrap/dist/css/bootstrap.min.css;
+ }
+
+ location = /share/jquery/jquery.min.js {
+ alias /usr/lib/nodejs/jquery/dist/jquery.min.js;
+ }
+
+ location = /share/bootstrap4/js/bootstrap.min.js {
+ alias /usr/lib/nodejs/bootstrap/dist/js/bootstrap.min.js;
+ }
+
+}
+</pre>
+<p>Execute again <samp>nginx -t</samp> to spot any troubles with your
+config files. Once all is OK, add the line
+<pre>
+# XMPP server domain name here, i.e it
+# could be xmpp.example.com in your case
+127.0.0.1 example.com
+</pre>
+
+<p>in your <samp>/etc/hosts</samp>.<br>
+Restart <samp>nginx</samp> and <samp>prosody</samp>:
+<pre>
+systemctl start prosody nginx
+# or
+prosodyctl start &amp;&amp; nginx -s reload
+</pre><br>
+
+<h3 id="xmpp-guide-con"><a
+href="#xmpp-guide-con">7. Discovering the webclient</a></h3>
+
+<p>Let's see the results of our work! Open a web browser and navigate
+to <a href="https://chat.example.com">https://chat.example.com</a>, YMMV.
+You should see something like this:
+<a href="img/0conversejs_login.png"><img
+src="img/0conversejs_login.png"></a>
+
+<p><b>Small trick</b>: if you want to login as
+<u><samp>you@example.com</samp></u>, you can omit the right part of your adress like
+this:<br>
+<a href="img/0conversejs_logintrick.png"><img
+src="img/0conversejs_logintrick.png"></a>
+<p>It's thanks to the
+<samp><a
+href="https://conversejs.org/docs/html/configuration.html?highlight=locked_domain#locked-domain"
+target="_blank" rel="noopener">locked_domain</a></samp> parameter.<br>
+
+Once logged in your view should be like this:<br>
+<a href="img/0conversejs_main.png"><img
+src="img/0conversejs_main.png"></a>
+
+<p>You can then start to use XMPP and join or create group chats, add friends and chat
+with them from there !<br><br>
+
+<h3 id="xmpp-guide-genlinks"><a href="#xmpp-guide-genlinks">8. Invite links generation</a></h3>
+
+<p>The really interesting thing is that we can create invite links from
+Converse.js thanks to the <samp>admin_adhoc</samp> module.<br>
+To do so, left click on the gear icon on the top left next to your
+username, then click <u>Commands</u>.
+In the <u>'On which entity do you want to run commands?'</u> field, type
+in your XMPP server domain name and left click <u>'List available commands'</u>.
+You should have something similar to this:<br>
+<a href="img/0conversejs_adhoc1.png"><img
+src="img/0conversejs_adhoc1.png"></a><br>
+
+<p>Scroll down a bit and left click on <u>"Create new contact invite"</u>:<br>
+<a href="img/0conversejs_adhoc2.png"><img
+src="img/0conversejs_adhoc2.png"></a><br>
+
+<p>An invite link has been created ! You can now copy and send it to your
+friends, family, etc...<br>
+Once opened, the link will lead to this kind of page:
+<a href="img/0conversejs_invitepage.png"><img
+src="img/0conversejs_invitepage.png"></a><br>
+<p>The web page auto-detects your OS platform and will
+suggest you compatible XMPP software to download. In the
+case you're on a smartphone, the links will download the apps
+on their respective stores and continue the registration
+after opening thanks to the <u>Invite URI</u>.<br>
+The text squared in red in the bottom left, <u>'register an account manually'</u>,
+allows you to register via the web browser. It's handy when you want to create
+an account and test it later. Here how it looks:<br>
+<a href="img/0conversejs_register1.png"><img
+src="img/0conversejs_register1.png"></a><br>
+
+<p>As you can see I started to fill in the form: once submitted succesfully,
+ you'll be greeted with this:
+<a href="img/0conversejs_register2.png"><img
+src="img/0conversejs_register2.png"></a><br>
+
+<p>A page confirming your registration is shown, with the possibility to view your chat adress and password again to
+write them down somewhere. The user can then log in with
+Converse.js by clicking on the <u>"Log in via web"</u> button.
+Once logged in, you will be added to his roster (because we did a <i>contact</i> invite) and he can start to chat with you.<br>
+<a href="img/0conversejs_chatting.png"><img
+src="img/0conversejs_chatting.png"></a><br>
+
+<h3 id="xmpp-guide-remarks"><a href="#xmpp-guide-remarks">9. Remarks</a></h3>
+<p>The guide ends there! I'll get back from time to time to fix some typos and inconstencies when I spot them.
+I've got some notes and remarks:
+<ul style="list-style:disclosure-closed">
+ <li>OMEMO encrypted chats don't seem readable between converse.js clients.
+ The sender can read it fine, but if the recipient only uses converse.js, there's
+ an high probability he sees the dreaded <u>I sent you an OMEMO encrypted message but your client doesn't seem to support that...</u> message.
+ From my experience, Dino and Gajim can decrypt these chats just fine. I've maybe
+ misconfigured something ?</li>
+ <li>Due to reliance on the browser cache to display last messages, I recommend
+ to dedicate a browser (and maybe ideally a browser <i>profile</i>) to your converse.js
+ client if you like having a consistent messaging history.</li>
+ <li>File encryption via OMEMO isn't implemented yet (source: @jcbrand in <a href="xmpp:discuss@conference.conversejs.org?join">discuss@conference.conversejs.org</a>).
+ <li>If you want to translate the invites pages in your language,
+ look into the source code of <samp>mod_invites_pages</samp>,
+ <samp>mod_register_web</samp> and <samp>mod_register_apps</samp>.</li>
+</ul>
+
+
+<h3 id="xmpp-guide-docs"><a href="#xmpp-guide-docs">10. Documentations</a></h3>
+
+<p>Those links greatly helped me:
+ <ul style="list-style:square">
+ <li><b>Converse.js</b>: <a
+ href="https://conversejs.org/docs/html/index.html" target="_blank"
+ rel="noopener">General</a>, <a
+ href="https://conversejs.org/docs/html/configuration.html#configuration-settings"
+ target="_blank"
+ rel="noopener">config and initilization</a><br>
+ Reading the HTML source code of<a
+ href="https://inverse.chat" target="_blank" rel="noopener">https://inverse.chat</a>
+
+ </li>
+ <li><b>Prosody</b>: <a
+ href="https://prosody.im/doc" target="_blank" rel="noopener">General</a>, <a
+ href="https://prosody.im/doc/setting_up_bosh" target="_blank"
+ rel="noopener">BOSH+Nginx</a>,
+ <a href="https://prosody.im/doc/websocket" target="_blank"
+ rel="noopener">Websockets+Nginx</a>,
+ <a href="https://modules.prosody.im/xeps.html" target="_blank"
+ rel="noopener">Links between XEPs and modules</a>, <a
+ href="https://modules.prosody.im/mod_invites.html" target="_blank"
+ rel="noopener">mod_invites docs</a>, <a
+ href="https://modules.prosody.im/mod_http_upload_external.html"
+ target="_blank" rel="noopener">mod_http_upload_external docs</a> and Holger's implementation ,<a
+ href="https://github.com/weiss/ngx_http_upload" target="_blank"
+ rel="noopener">upload.pm</a>.</li>
+ <li><b>XMPP</b>: <a href="https://wiki.xmpp.org/web/Main_Page" target="_blank" rel="noopener">the Wiki</a>, <a href="https://compliance.conversations.im/" target="_blank" rel="noopener">compliance tester</a>.
+ </ul>
+
+
+<h3 id="xmpp-guide-thanks"><a href="#xmpp-guide-thanks">11.
+Thanks</a></h3>
+
+<p>This wouldn't have been possible without free software and their contributors. Thanks you so much.<br>
+To be more specific:
+<ol style="list-style:square">
+ <li><a href="https://blog.laxu.de">laxu.de</a>, author of
+ <a href="https://blog.laxu.de/2018/09/08/conversejs-prosody/">
+ https://blog.laxu.de/2018/09/08/conversejs-prosody/</a> which walks through the patching of <samp>net/http/server.lua</samp> and gives some related nginx configuration snippets</li>
+ <li><a href="https://qorg11.net/">qorg</a> for <a href="https://kill-9.xyz/guides/xmpp_server" target="_blank" rel="noopener">his XMPP guide</a>, in particular the part dealing about <samp>mod_http_upload_external</samp>
+ <li> <a
+ href="https://wiki.xmpp.org/web/Jan-Carel_Brand_Application_2021"
+ target="_blank" rel="noopener">jcbrand</a>, creator and main developer of <a
+ href="https://conversejs.org/" target="_blank"
+ rel="noopener">Converse.js</a>. Very quick to respond to questions
+ relating to XMPP and Converse.js in <a href="xmpp:discuss@conference.conversejs.org?join">discuss@conference.conversejs.org</a>.</li>
+ <li><a href="xmpp:holger@jabber.fu-berlin.de?message">Holger Weiß</a>,
+ a developer working on the ejabberd XMPP server and admin of
+ <a
+ href="xmpp:ejabberd@conference.process-one.net?join">ejabberd@conference.process-one.net</a> who took his time
+ to help me (<a href="https://partage.les-miquelots.net/engver/blog/reminder-when-setting-up-a-xmpp-server-with-prosody.html">problem and fix here</a>).</li>
+</ol><br>
+
+<p>See you soon and have a great day ! If you have any questions, remarks, suggestions or improvements to point out, don't hesitate to message me via XMPP or email at <u>lionel ( @ ) les-miquelots ( . ) net</u>.
+<footer>by <strong><a href='http://partage.les-miquelots.net/'>Miquel Lionel</a></strong></footer>
+</body>
+
+</html>