self-hosted-xmpp-server.md (10449B)
1 Title: Self hosted XMPP server (on OpenBSD) 2 Author: paco 3 Date: 2019-04-25 4 Type: article 5 6 _Update 2020-12-15: I've adapted [this ansible role][12] to match my needs. You 7 can take a look at it [here][13]. This is running on 6.8-current._ 8 9 Tested on OpenBSD 6.5 (prosody version 0.11.2) 10 11 ## Intro 12 13 Self-hosting an instant messaging service is quite simple. This guide shows how 14 to do it using OpenBSD as a base system and XMPP as the messaging protocol. 15 16 The end result is an End-to-End encrypted chat system for 1:1 or multi-user 17 conversations. 18 19 The software used for the server is [prosody][1], and it's all based on 20 [this guide][2]. 21 22 For the clients, I've tried [Gajim][3] for the desktop (works for Windows, 23 Linux and *BSD), [Conversations][4] on the phone (Android) and [profanity][5] 24 on the terminal (works almost everywhere). There's a client for iOS called 25 [ChatSecure][8], but I have not tried it. 26 27 ## Rationale 28 29 I used to host my messaging services back in the day. People stopped using this 30 for some reason, and then came all the Whatsapp and co. So all that was 31 forgotten. 32 33 Although I never used whatsapp, on recent times I've been testing some instant 34 messaging systems, but none of them were good enough. In the end, all rely on 35 central systems, often owned by companies that have to make money from 36 somwhere. Most of the times is you (one way or another) even if they say the 37 service is free. 38 39 I wanted something simple, client independent, secure (well, as secure as 40 possible ...), easy to use from the client point of view and easy to manage 41 from the server part. My goal is to replace things like Signal that I use with 42 my family and friends. 43 44 XMPP is federated, just like email is. And with recent extensions like easy to 45 use End-to-End encryption and http file sharing it's a viable solution for 46 resilient and secure instant messaging system, that does not spy on you (no 47 more than encrypted email for instance). 48 49 For now is not a complete replacement, as it does not provide VoIP, but is a 50 start. I may look for voice alternatives or dig deeper for a jabber client that 51 supports voice. 52 53 ## Previous steps (DNS and TLS) 54 55 Some DNS configuration is needed for this guide. If you are not using file 56 uploads or multi-user chat, then is probably fine if your root dns name points 57 to the machine that will host the xmpp server. If not, you'll have to define 58 some SRV records, and also any record you may use for the mentioned services. 59 It may look like this (config depends on your DNS provider): 60 61 _xmpp-client._tcp 1800 IN SRV 5 0 5222 server.mydomain.com. 62 _xmpp-server._tcp 1800 IN SRV 5 0 5269 server.mydomain.com. 63 64 This will tell xmpp clients and other servers trying to reach your accounts 65 where (host and port) to knock. 66 67 In this particular case I configured also multi-user chat and http file 68 uploads, so I defined `uploads`, `proxy` and `groups` as `CNAME` of the 69 server's `A` record. 70 71 I also configured `acme-client(1)` and `httpd(8)` to get certificates from 72 letsencrypt, so all communications client/server and server/server is 73 encrypted. 74 75 How to do that is out of the scope of this guide, just read the man pages, it's 76 quite easy to do. The only detail to take into account is that is better to 77 have all the domains/subdomains with its own cert and into separated folders 78 containing the certificate and the private key. This important for certificate 79 import on prosody later on. So I ended up configuring it to store certs on a 80 structure like: 81 82 /etc/ssl/letsencrypt/ 83 |-- mydomain.com 84 | |-- cert.pem 85 | |-- fullchain.pem 86 | `-- privkey.pem 87 |-- groups.mydomain.com 88 | |-- cert.pem 89 | |-- fullchain.pem 90 | `-- privkey.pem 91 ... 92 93 ## Server install 94 95 Install the server is as easy as: 96 97 $ doas pkg_add prosody 98 99 ## Server config 100 101 So here comes the fun part. 102 103 First you should get the community modules. Some of them provide functionality 104 that is needed on any modern IM system. 105 106 The way to do that is cloning the [mercurial][6] repository. I did not want to 107 have it installed on my server, so I cloned it on my desktop machine and synced 108 to the server. So, on my desktop I did: 109 110 hg clone https://hg.prosody.im/prosody-modules/ prosody-modules 111 112 Then I uploaded it to `/usr/local/lib/prosody-modules/` on the server. 113 Here's the important parts I changed from the config files and why: 114 115 Community modules location: 116 117 plugin_paths = { "/usr/local/lib/prosody-modules" } 118 119 List of globally enabled modules: 120 121 modules_enabled = { 122 "roster"; -- Allow users to have a roster. Recommended ;) 123 "saslauth"; -- Authentication for clients and servers. Recommended if you want to log in. 124 "tls"; -- Add support for secure TLS on c2s/s2s connections 125 "dialback"; -- s2s dialback support 126 "disco"; -- Service discovery 127 "carbons"; -- Keep multiple clients in sync 128 "pep"; -- Enables users to publish their mood, activity, playing music and more 129 "private"; -- Private XML storage (for room bookmarks, etc.) 130 "blocklist"; -- Allow users to block communications with other users 131 "vcard"; -- Allow users to set vCards 132 "version"; -- Replies to server version requests 133 "uptime"; -- Report how long server has been running 134 "time"; -- Let others know the time here on this server 135 "ping"; -- Replies to XMPP pings with pongs 136 "register"; -- Allow users to register on this server using a client and change passwords 137 "mam"; -- Store messages in an archive and allow users to access it 138 "admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands 139 "server_contact_info"; -- Publish contact information for this service 140 "vcard4"; 141 "vcard_legacy"; 142 "smacks"; -- XEP-0198: Stream Management, keep chatting even when the network drops for a few seconds 143 "csi_simple"; 144 "bookmarks"; 145 "cloud_notify"; -- XEP-0357: Push Notifications. 146 } 147 148 Disable registration, as this will not be a public server. This is the default, 149 but just check it just in case. 150 151 allow_registration = false 152 153 Force clients to use encrypted connections 154 155 c2s_require_encryption = true 156 157 Force servers to use encrypted connections. 158 159 s2s_require_encryption = true 160 161 162 Force certificate authentication for server-to-server connections. This may 163 bring problems with servers that use self-signed certificates. Today nobody 164 should be using that, as there are alternatives like letsencrypt but, if you 165 have some server you want to talk to that uses self-signed certs, check 166 `s2s_insecure_domains` 167 168 s2s_secure_auth = true 169 170 Location of directory to find certificates in (relative to main config file), 171 on OpenBSD that's `/etc/prosody/certs` 172 173 certificates = "certs" 174 175 Virtual host. You can have many, for many domains. In my case this is just one 176 personal domain. I limited the uploads to 9MB, but you can set up any other 177 limit. Keep in mind that there's a 10MB limit for `http_max_content_size` 178 179 VirtualHost "mydomain.com" 180 Component "uploads.mydomain.com" "http_upload" 181 http_upload_file_size_limit = 1024 * 1024 * 9 -- 9MB upload limit 182 Component "groups.mydomain.com" "muc" 183 modules_enabled = { "muc_mam", "vcard_muc" } 184 Component "proxy.mydomain.com" "proxy65" 185 186 At this point you can import the certificates you got from letsencrypt (or from 187 any other CA), with the command: 188 189 prosodyctl --root cert import /etc/letsencrypt/letsencrypt 190 191 That will copy all needed files to `/etc/prosody/certs` so they are accessible 192 to the prosody daemon. Now you can start the daemon: 193 194 doas rcctl start prosody 195 196 To make it permanent on boot, add it to the `pkg_scripts` on 197 `/etc/rc.conf.local`. 198 199 Also remember to open ports on the firewall (pf or any other you may have in 200 front of your server). They are: 201 202 5000 --> for proxying large file transfers between clients 203 5222 --> for client to server 204 5269 --> server to server 205 5281 --> default https port for http file transfers 206 207 ## Add accounts and client config. 208 209 In order to add an account to your new server just execute: 210 211 prosodyctl adduser user@mydomain.com 212 213 You'll be asked for the new password and that's it ! 214 215 On the client side is usually enough to enter the jid (jabber id, in this 216 example `user@mydomain.com`) and the password. As we configured the necessary 217 dns records earlier, the client will discover to which server and port to 218 contact to. 219 220 ## OMEMO 221 222 [OMEMO Multi-End Message and Object Encryption][7] is an extension to XMPP that 223 provides encryption for 1:1 and multi-user chats. 224 225 This is key for a secure chat system. Some of the most popular xmpp clients 226 already support it. Conversations, for instance, has it enabled by default. 227 Do not forget to set it up on your client. 228 229 OMEMO trusts devices on first use, then you should check the key fingerprints 230 to see if the person you're talking to is who it claims to be. 231 232 Is a good practice to publish those fingerprints on some place public, like you 233 would do with your GnuPG public key. In fact you could sign those to provide 234 some proof of ownership. 235 236 On Conversations, for instance, you can later verify a contact fingerprint via 237 a QR code. From that moment no other key will be allowed for that contact if 238 you do not explicitly allow it. I think all clients should support that ... 239 240 ## Conclusion 241 242 Now you should have a working XMPP server. It can not only be used for IM, but 243 also for notifications on your scripts using the libraries for your language of 244 choice. Here you have some examples in [perl][9], [python][10] and [golang][11] 245 246 [1]: https://prosody.im 247 [2]: https://homebrewserver.club/configuring-a-modern-xmpp-server.html 248 [3]: https://gajim.org/ 249 [4]: https://conversations.im/ 250 [5]: http://www.profanity.im/ 251 [6]: https://www.mercurial-scm.org/ 252 [7]: https://en.wikipedia.org/wiki/OMEMO 253 [8]: https://chatsecure.org/ 254 [9]: https://metacpan.org/pod/Net::XMPP 255 [10]: https://lab.louiz.org/poezio/slixmpp 256 [11]: https://github.com/FluuxIO/go-xmpp 257 [12]: https://github.com/cullum/dank-selfhosted/tree/master/roles/prosody 258 [13]: https://e1e0.net/repo/prosody_ansible_role.tar.gz