XMPP <-> WhatsApp with eJabberD and Slidge
How I learned to stop worrying and love WhatsApp... not really. This is how I've set up my own XMPP service to be able to talk to WhatsApp using the
slidge-whatsapp
transport module.
WhatsApp Pain
I wish I didn't have to use WhatsApp, I really do, I wish people would switch to
more freedom giving services.
But that isn't the case... "everyone uses WhatsApp", so, long story short,
if I want to stay in touch with people, I need some way of communicating with
WhatsApp, at least for now.
Luckily, there are ways...
History
For a long time I've had a Matrix (synapse
) server that it set up to use
the mautrix-whatsApp
bridge.
This has worked well for many years, and I don't really have any complaints
with it specifically. However, Matrix are making some...
questionable choices,
and honestly, I only use Matrix for the WhatsApp bridge -
running an entire server just for this purpose feels a little... wasteful.
However, I do also run my own XMPP service, and I use this service for communicating with a handful of people. So, if I could get a WhatsApp "bridge" working with XMPP, I will have one app to communicate with almost everyone I know!
Hosting an XMPP server
I run my own ejabberd
server, and I'll have another article about how I do this at
some point. But for the purposes of this article the choice of XMPP service is not
massively important. The WhatsApp transport module is known to work with
both Prosody and eJabberD, so chosing one of those will be best.
Installing a WhatsApp Transport Module
There's a handful of WhatsApp transport modules available for XMPP, but some have seen little maintenance over the last few years. One that still appears to be in active development is slidge-whatsapp, part of a suite of modules based upon the slidge gateway library.
Typically, we should just need to install slidge-whatapp
via the command
pipx install slidge-whatsapp
However, at the time of writing, this does not build on FreeBSD.
If you're using Linux, or have otherwise managed to install slidge-whatsapp
with pipx
, then you can probably skip on to the Configuration
First Error - puccinialin
We'll first be given the error:
$ pipx install slidge-whatsapp
Fatal error from pip prevented installation. Full pip output in file:
/path/to/pipx/logs/cmd_2025-06-16_10.02.59_pip_errors.log
pip seemed to fail to build package:
slixmpp<2,>=1.10.0
Some possibly relevant errors from pip install:
error: subprocess-exited-with-error
ModuleNotFoundError: No module named 'puccinialin'
You may think installing puccinialin
will solve this, but unfortunately it's
not really that causing the issue. Puccinialin is a Rust bootstrapper, so the problem is we don't have rust
installed. We do a pkg install rust
and try again.
Second Error - Go
We also have some GoLang dependencies, so if go
isn't installed we'll hit this error:
$ pipx install slidge-whatsapp
...
pip failed to build package:
slidge-whatsapp
Some possibly relevant errors from pip install:
error: subprocess-exited-with-error
RuntimeError: Cannot find the go executable in $PATH. Make you sure install golang, via your package manager or https://go.dev/dl/
subprocess.CalledProcessError: Command '['/root/.local/pipx/venvs/slidge-whatsapp/bin/python', 'build.py']' returned non-zero exit status 1.
ERROR: Failed to build installable wheels for some pyproject.toml based projects (slidge-whatsapp)
We pkg install go
and carry on...
Third Error - GoPy fails to build
slidge-whatsapp
has a dependency on go-python's gopy module. At the time of writing,
gopy will not build on FreeBSD, so pipx install slidge-whatsapp
will fail.
$ pipx install slidge-whatsapp
...
pip failed to build package:
slidge-whatsapp
Some possibly relevant errors from pip install:
error: subprocess-exited-with-error
subprocess.CalledProcessError: Command '['go', 'install', 'github.com/go-python/gopy@master']' returned non-zero exit status 1.
subprocess.CalledProcessError: Command '['/root/.local/pipx/venvs/slidge-whatsapp/bin/python', 'build.py']' returned non-zero exit status 1.
ERROR: Failed to build installable wheels for some pyproject.toml based projects (slidge-whatsapp)
However, the reason it doesn't build is quite simple - there's no defined process
for in GoPy's main*.go
files for FreeBSD that sets some basic variables up.
We can fix this by editing one file in the gopy
repo, then build and install it
manually.
$ git clone https://github.com/go-python/gopy
$ cd gopy
Find and edit 2 lines in ./main_unix.go
so they change from this
//go:build (linux && !android) || dragonfly || openbsd
// +build linux,!android dragonfly openbsd
to this
//go:build (linux && !android) || dragonfly || openbsd || freebsd
// +build linux,!android dragonfly openbsd freebsd
I have made a pull request on the gopy
repo which will change this upstream.
In time, this step should no longer be necessary.
You can then build and install gopy with the following command (you will of course need the go language installed too)
$ go install .
Installing Slidge-WhatsApp from Source
We now have gopy installed as a go library, but we cannot use pipx
any more as
the slidge-whatsapp
build script has a hard link to install gopy from their repo,
and does not look at our local version.
Another simple fix, we clone the slidge-whatsapp
repo, make a change to the
build script, and build it locally.
$ git clone https://codeberg.org/slidge/slidge-whatsapp
$ cd slidge-whatsapp
In ./build.py
, find this line:
subprocess.run(["go", "install", "github.com/go-python/gopy@master"], check=True)
and comment it out so it doesn't run.
#subprocess.run(["go", "install", "github.com/go-python/gopy@master"], check=True)
As with the change to gopy
previously, this should only be a temporary requirement until
the aforementioned pull request gets accepted.
Slidge recommend (if not using docker containers) that slidge-whatsapp
builds and runs in
a python venv
- which is a very sensible recommendation. There's a number of ways of doing this, but using uv
is a single command way of doing it.
# Install uv
# As root
(root)# pkg install uv
# Non root
# Try to build slidge-whatsapp
$ uv sync --frozen --all-groups --all-extras
More Errors...
We're nearly there! But, uv
is failing with some more errors. The error messages
are long, and require a bit of scrolling to find the issue, but you may see
something like this if you look:
...
not found
6 | #include <mupdf/fitz.h>
| ^~~~~~~~~~~~~~
1 error generated.
...
or
...
ld: error: unable to find library -lgumbo
ld: error: unable to find library -lmujs
clang: error: linker command failed with exit code 1 (use -v to see invocation)
...
and many others. I've gone through them so you don't have to...
We need some dependencies, so let's install them.
Also, I've found some souce code has trouble compiling with clang
;
there's probably a way to solve it but as a shortcut let's just install
gcc
and build using that, setting the CC
envvar when running the uv
command.
(root)# pkg install gcc gmake mupdf gumbo mujs
$ CC=gcc uv sync --frozen --all-groups --all-extras
Built!
slidge-whatsapp
should now be available in $BUILD_DIR/.venv/bin/slidge-whatsapp
, ready for use.
A couple of other runtime dependencies will be required though, so let's install them now.
(root)# pkg install py311-sqlite3 ffmpeg nginx
sqlite3
for database connectivity, ffmpeg
for media handling and nginx
for
media publishing.
Finally, configuration!
The slidge website has some decent documentation, and setting things up boils down to a handful of steps:
- Configure
slidge-whatsapp
to communicate witheJabberD
. - Configure
eJabberD
to allowslidge-whatsapp
, and set privileges. - Set up
nginx
for publishing the sent media.
Configure slidge-whatsapp
A simple slidge-whatsapp
configuration will look like this.
# /usr/local/etc/slidge-whatsapp.ini
server=localhost # you can use your xmpp address here, but communication
# is unencrypted so make sure it's either on the same host,
# or you can encrypt the transmissions between the services
secret=v3rYSecur3 # secret to authenticate the slidge service to ejabberd
# you can just run `openssl rand -base64 32` to get something decent
jid=slidge-whatsapp.my.xmpp.host # should be a subdomain of the ejabberd address
no-upload-path=/var/lib/slidge/attachments # where media will be stored
no-upload-url-prefix=https://my.xmpp.host/slidge/ # the address where an XMPP client
# can find the media
Configure eJabberD
In the ejabberd
configuration, we add a new listener, set up an acl, rules and some module privileges.
# /usr/local/ejabberd/ejabber.yml
#...
listen:
#...
-
port: 5347
module: ejabberd_service
hosts:
slidge-whatsapp.my.xmpp.host:
password: v3rYSecur3 # Same as the secret in slidge-whatsapp.ini
#...
acl:
#...
slidge_acl:
server:
- `slidge-whatsapp.my.xmpp.host`
#...
access_rules:
#...
slidge_rule:
allow: slidge_acl
#...
modules:
#...
mod_roster:
versioning: true
#...
mod_privilege:
roster:
bost: slidge_rule
message:
outgoing: slidge_rule
Configure nginx
The reason we need nginx
is documented here.
I will put a basic nginx
configuration server block below. If you have many sites
in the same nginx configuration, you should adjust this to your needs.
Please also configure certificates for your site here, you should already have
them available for use with ejabberd
anyway.
# /usr/local/etc/nginx/nginx.conf
#...
server {
listen 80;
root /var/www/html; # if you already have nginx serving files…
# the section below is for slidge
location /slidge {
# Must be the same value as slidge's no-upload-path
alias /var/lib/slidge/attachments/;
}
}
#...
Run!
And there we have it. We can restart ejabberd
and run slidge-whatsapp
with
command parameter to use the config file:
$ slidge-whatsapp -c /usr/local/etc/slidge-whatsapp.ini
You can also use an init script to run this as a daemon. My init script is in my rc.d scripts repo
We should them start to communicate with each other in their respective log files.
Connect clients
All that's left is to connect up our XMPP client, and we'll be good to go.
The Documentation on Slidge's website talks through this, but to summarise, you can either send a
message saying "register" to the slidge-whatsapp.my.xmpp.host
account, or
in something like gajim
, go to Accounts > $Account > Discover Services
,
select "WhatsApp (slidge)" and click "Register". Then just follow the standard
WhatsApp "Linked Devices" process.
Done!
And that's that. If things aren't working, we can just check the output of the slidge-whatsapp
command (or the log file if you're using daemon
) and solve what's going wrong.
Step-by-Step. Commands only
The whole thing, narrowed down to a handful of commands:
- Install Dependencies
(root)# pkg install rust go gcc gmake git py311-sqlite3 ffmpeg nginx mupdf mujs gumbo uv
- Build
gopy
(may become irrelevant in the future)
$ git clone https://github.com/go-python/gopy
$ cd gopy
$ sed -i '' 's/|| openbsd/|| openbsd || freebsd/' main_unix.go
$ sed -i '' 's/dragonfly openbsd/dragonfly openbsd freebsd/' main_unix.go
$ go install .
- Build
slidge-whatsapp
$ git clone https://codeberg.org/slidge/slidge-whatsapp
$ cd slidge-whatsapp
$ grep -v -E "subprocess.+gopy" build.py > build.py.patched
$ cp build.py.patched build.py
$ CC=gcc uv sync --frozen --all-groups --all-extras
- Configure
slidge-whatsapp
- Configure
ejabberd
- Configure
nginx
- [Re]Start Services
- Connect Clients