There are a seemingly infinite number of chat protocols, services, and various other ways to interact with other people. Wanting to try something new and experiment a bit, I decided to deploy a Prosody server to a DigitalOcean virtual machine. This turned out to be more time consuming than I expected, despite everyone extolling how “quick, simple, and easy” it is, largely because the docs are lackluster and examples are hard to come by.
I currently use this Prosody instance to receive alerts and messages from the various things running in my lab (e.g. alerts about power outages sent using ntfy), as well as chatting with my wife. Yes, I could use WhatsApp, Telegram, Slack, IRC, Twitter, Signal, SMS, Rocket.Chat, Matrix, RCS, or about a thousand other things, but what fun would that be?
Install
I’m using the smallest DigitalOcean droplet size, which is still massively too large for the amount of resources Prosody needs. To make me feel slightly less wasteful, I’ve also added a WireGuard instance to the VM to provide me with a way to bypass the Pi-Hole filtering on my home network if needed. It’s also my backup if I am traveling and needing a way to protect my internet sessions and my home WireGuard instance isn’t working for whatever reason. I won’t go into the configuration details of WireGuard here, simply follow the existing guide.
After deploying the droplet with CentOS 7, connect using your SSH key.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# apply all updates yum -y update # for whatever reason, RPCbind was enabled on my instance, diable it systemctl disable rpcbind.service rpcbind.socket # sadly, disable selinux since I haven't discovered rules for Prosody sed -i 's/enforcing/disabled/' /etc/sysconfig/selinux # reboot for service adjustments and if the kernel was updated reboot # install epel yum install epel-release # install app and firewall yum install prosody firewalld certbot hg # turn on the firewall systemctl enable --now firewalld # enable the ports we'll need # port 80 is only used for certificate renewal # a future project is to only have it open when doing renewals firewall-cmd --permanent --zone=public --enable-port=80/tcp # used for the proxy firewall-cmd --permanent --zone=public --enable-port=5000/tcp # used for XMPP communication firewall-cmd --permanent --zone=public --enable-port=5222/tcp # used for HTTPS file uploads firewall-cmd --permanent --zone=public --enable-port=5281/tcp firewall-cmd --reload # create the certificates, todo: create a wildcard cert # note that DNS for each of these points to this server certbot certonly --standalone -d chat.domain.name certbot certonly --standalone -d conference.domain.name certbot certonly --standalone -d upload.domain.name certbot certonly --standalone -d proxy.domain.name # configure certbot so that cert renewal works with prosody vim /etc/sysconfig/certbot # replace the line for POST_HOOK with the following: # POST_HOOK="--post-hook 'prosodyctl --root cert import /etc/letsencrypt/live && systemctl restart prosody'" # enable the cert renewal service systemctl enable certbot-renew.timer # download the community modules cd /opt && hg clone https://hg.prosody.im/prosody-modules/ prosody-modules |
Configure
- Create the config files,
/etc/prosody/prosody.cfg.lua
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394-- set any usernames who are/will be adminsadmins = { "admin@chat.domain.name" }-- where we downloaded the community modules toplugin_paths = { "/opt/prosody-modules" }-- standard modules enabled, check the default config file for commentsmodules_enabled = {"roster";"saslauth";"tls";"dialback";"disco";"carbons";"pep";"private";"blocklist";"vcard4";"vcard_legacy";"version";"uptime";"time";"ping";"register";"mam";"admin_adhoc";"groups";"smacks";"smacks_offline";"proxy65";"csi";"csi_simple";"lastactivity";}-- we don't need server-to-server commsmodules_disabled = {"s2s";}-- don't allow users to self-registerallow_registration = false-- force clients to use encrypted connectionsc2s_require_encryption = true-- we aren't using s2s, but just in cases2s_require_encryption = trues2s_secure_auth = true-- store auth hashedauthentication = "internal_hashed"-- only store this many messages for offline archivearchive_expires_after = "1w"-- where to log tolog = {info = "/var/log/prosody/prosody.log";error = "/var/log/prosody/prosody.err";}-- disco offers service discovery, explicitly add the group chatsdisco_items = {{ "conference.domain.name", "group chats" };{ "upload.domain.name", "file uploads" };}-- where certs are storedcertificates = "/etc/pki/prosody/"-- the cert to use for any https service(s), note this isn't necessary-- if none of the http services are enabledhttps_certificate = "/etc/prosody/certs/upload.domain.name.crt"-- straightforward pid file locationpidfile = "/run/prosody/prosody.pid";-- define our serverVirtualHost "chat.domain.name"-- define our group chat serviceComponent "conference.domain.name" "muc"modules_enabled = { "mam_muc", "vcard_muc" }-- help some folks get access from behind a fireall/natComponent "proxy.domain.name" "proxy65"-- allow file uploads (for sending pics/video) via the upload service-- note that we use the certificate for this domain above to prevent-- domain mismatch errorsComponent "upload.domain.name" "http_upload"-- the default limit is 1MB (1024 * 1024), increase to 10MBhttp_upload_file_size_limit = 10485760While we’re here, remove the
example
andlocalhost
configs:1rm /etc/prosody/conf.d/* - Import the certificates
1prosodyctl --root cert import /etc/letsencrypt/live
- Start the server
1systemctl enable --now prosody
- Add the users:
12345prosodyctl adduser admin@chat.domain.nameprosodyctl adduser server1@chat.domain.nameprosodyctl adduser server2@chat.domain.nameprosodyctl adduser server3@chat.domain.nameprosodyctl adduser server4@chat.domain.name
Don’t forget to turn on OMEMO in the client to encrypt messages between users.
Use
As was mentioned in the intro, I use ntfy
to send messages from servers in the homelab. Follow the docs for how to configure with XMPP, then create scripts to send whatever messages you want. For example, I use CyberPower’s PowerPanel Personal client, pwrstatd
, to detect when a power blip happens, which then sends me a message.
1 2 3 4 5 |
# notify on power fail pwrstat -pwrfail -active on -cmd ntfy-pwrfail.sh -shutdown off -delay 60 # notify and shutdown on battery low pwrstat -lowbatt -active on -runtime 300 -cmd ntfy-lowbatt.sh -shutdown on |
The contents of ntfy-pwrfail.sh
and ntfy-lowbatt.sh
are nearly identical, with only the message being different.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#!/bin/sh DATE=`date +'%Y/%m/%d %p %H:%M'` HOST=`hostname` MESSAGE=$( cat << EOL Host: $HOST Time: $DATE The power has been lost! EOL ) ntfy send "$MESSAGE" |