SimpleXMQ: a message broker built on one-way queues
⚙️ SimpleXMQ - A reference implementation of the SimpleX Messaging Protocol for simplex queues over public networks.
At a glance
- What is it?
- SimpleXMQ is the Haskell reference implementation of the SimpleX Messaging Protocol, shipping an SMP server, a client library and an agent that multiplexes duplex conversations over unidirectional queues. It is AGPL-3.0 licensed, currently shipping v7.1.0 betas, and it is infrastructure for people who want to run their own broker rather than rent one.
- Who is it for?
- Adopt SimpleXMQ if you want to run your own message broker for SimpleX style clients, need a Haskell library that speaks the SMP agent protocol, or want a duplex channel built on top of one-way queues. Do not adopt it if you need a general purpose broker with a mature client ecosystem, and read the AGPL-3.0 terms carefully before embedding it in a service you offer to others.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Haskell, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Why a queue protocol instead of a socket
SimpleXMQ is a message broker for unidirectional, simplex queues over public networks. That phrase is the whole design, and it inverts the usual chat server assumption.
In a conventional chat protocol, the server holds a bidirectional connection and both sides can push at any time. In SMP, the server holds queues. A client can send to a queue and receive from a queue, but the two directions are independent and one way. The duplex conversation that a user perceives is assembled above that layer by the agent, which is why the project needs a separate agent component at all.
The protocol itself is deliberately small. It is inspired by the Redis serialization protocol but the documentation notes it is much simpler, with only ten client commands and eight server responses. Small protocol surface is a security property as much as an engineering one, because there is less to get wrong in a parser and less to fuzz.
The implementation is Haskell, and the stated reason is software transactional memory and the concurrency primitives the language provides. For a broker whose job is to move bytes between many concurrent connections, STM gives composable atomicity without manual lock ordering, and that is exactly the kind of problem Haskell's type system is good at keeping honest.
The three components: server, client library, agent
The repository splits into three pieces that you can adopt separately.
The SMP server is the broker itself. It can run on any Linux distribution, including low power and low memory devices, and it needs the OpenSSL library for initialization. The client library is a Haskell package for connecting to SMP servers, and it exposes a functional API for executing commands, delivers messages and notifications through an STM queue, and sends keep-alive commands automatically. That keep-alive behavior is handled inside the library, so a caller does not have to think about idle connection timeouts.
The agent is the piece that turns the one way protocol into something usable. It can be run inside another application, in which case you talk to it over STM queues without serializing and parsing commands and responses at all, and the protocol type used for that is ACommand. Alternatively there is a standalone SMP agent executable that implements the plaintext SMP agent protocol over TCP port 5224, which means you can drive it with telnet and it can be deployed in a private network to share connections between several applications and services.
That last point is a real design choice rather than a convenience. Putting the agent on a private network and letting several local services share it means one set of outbound connections to the public brokers instead of N, which reduces both connection counts and the number of distinct client identities visible to the other side.
Initializing the server and what the server address means
Server initialization is a single command. To generate the keys and certificates for the TLS transport you run smp-server init with a fully qualified domain name, or with an IP for an IP based address. The resulting server address has the form smp://<fingerprint>@<hostname>[:5223], and the fingerprint of the offline certificate is part of that address specifically to protect the client server connection against man in the middle attacks.
That design has a consequence worth understanding before you deploy. The server creates a chain of two certificates at initialization: a self-signed CA certificate, called offline, and a server certificate used for the TLS handshake, called online. The documentation is explicit that you should store the CA private key securely and delete it from the server, because if the server TLS credential is compromised, that key can be used to sign a new one while keeping the same server identity and established connections. The default location of the CA private key is /etc/opt/simplex/ca.key.
On macOS there is a specific trap. The OpenSSL library may have been replaced with LibreSSL, which does not support the required algorithms, so the documentation tells you to check the version first:
openssl versionIf the output says LibreSSL, you need a real OpenSSL, and the documented path on macOS is Homebrew:
brew update
brew install openssl
echo 'PATH="/opt/homebrew/opt/openssl@3/bin:$PATH"' >> ~/.zprofile # or follow whatever instructions brew suggests
. ~/.zprofile # or restart your terminal to start a new sessionAfter that, openssl version should report OpenSSL and smp-server init will work.
In-memory queues with an optional append-only log
The persistence model is the part of the server you have to think about most carefully, because it determines what a restart costs you.
By default the server uses in-memory persistence, with an optional append-only log of created queues. That log is what allows a restart without losing connections. It is also compacted on every server restart, and the compaction permanently removes suspended and removed queues. So the log preserves live connections, not the full history of what the server once held.
The log is enabled by initializing the server with smp-server -l, or by editing the smp-server.ini file created during initialization and uncommenting the enable = on option in the store log section. The documentation also records a behavior change from version 2.3.0: when the store log is enabled, the server additionally saves undelivered messages on exit and restores them on start. That behavior has its own setting, restore_messages, in the same ini file.
There is a sharp edge in that message saving. It works only if the server is stopped with the SIGINT signal, meaning a keyboard interrupt. If the server is stopped with SIGTERM, the messages are not saved. Since SIGTERM is what a systemd service manager or a container runtime sends by default, an orderly-looking shutdown of a managed deployment will drop undelivered messages. If message durability matters to your use, either switch the unit to send SIGINT on stop or disable the restore_messages setting so the behavior is at least predictable rather than silently conditional.
Trying it against the public servers and running the agent
You do not need your own server to evaluate the stack. The documentation offers a local SMP agent against already deployed servers, and publishes three server addresses you can try:
smp://[email protected]smp://[email protected]smp://[email protected]For a first real use, the recommended path is the simplex-chat terminal UI, which the documentation points at as the easiest way to try the SMP agent. If you want to test the agent on its own instead, the standalone executable listens on TCP port 5224 and speaks plaintext, so telnet is enough to poke at it.
For your own deployment there are two documented routes. Run the server yourself, which the documentation says is possible on any Linux distribution and even on low power and low memory devices, or use the Linode StackScript. Either way, openssl is a runtime dependency on Linux, because it is used to generate the server certificates during initialization:
# For Ubuntu
apt update && apt install opensslYou can run the SMP and XFTP servers as Linux processes, optionally under a service manager for booting and restarts.
Building the Haskell binaries in Docker
The repository ships a Dockerfile that shows exactly what a from source build needs, and the dependency list is the practical part of the story. The build stage installs curl, git, build-essential, libgmp3-dev, zlib1g-dev, llvm-18 with its dev package, libnuma-dev and libssl-dev on an Ubuntu 24.04 base, then installs GHC and cabal through ghcup with pinned bootstrap versions:
ENV BOOTSTRAP_HASKELL_GHC_VERSION=9.6.3
ENV BOOTSTRAP_HASKELL_CABAL_VERSION=3.12.1.0The image deliberately does not install Stack, and it copies only the source directories, the cabal project file, Setup.hs, the package description and the LICENSE into the build context before running cabal update and cabal build exe:$APP. The APP build argument is required, and the build fails with a message asking you to specify it if it is missing. The resulting binary is stripped to reduce size.
Building from source is therefore a real toolchain project rather than a one liner. You need GHC 9.6.3 and cabal 3.12.1.0, LLVM 18 and the GMP and NUMA development headers, and Haskell's LLVM usage explains why libnuma-dev and llvm-18 appear in the same install line.
The repository layout also shows the wider project beyond the broker. There are protocol documents under protocol, design notes, plans, rfcs, contributing guides, an xftp-web directory, a cbits directory for C bindings, a CHANGELOG.md, an install.sh, and separate Dockerfile and Dockerfile.build files. The presence of design and rfc directories is a good sign for a protocol implementation, since it means the design decisions are written down somewhere rather than only in commit messages.
AGPL-3.0, v1 breaking changes and a roadmap that is still a roadmap
The licence is AGPL-3.0, which is the single most consequential fact for an engineer evaluating this repository. AGPL extends the copyleft obligation to network use: if you modify the software and offer it to users over a network, you owe them the corresponding source of your modified version. For a broker that others connect to, that is exactly the scenario the licence was written for. If you only run an unmodified server for your own organization, the obligation is much smaller, but if you plan to fork it into a hosted offering, read the licence and consider whether the copyleft fits your business model.
Versioning is currently in beta. The listed releases are v7.1.0-beta.4 on 2026-10-17, v7.1.0-beta.3 on 2026-09-19 and v7.1.0-beta.2 on 2026-09-12. The repository is not archived and the last push was on 2026-10-19.
The project is candid about compatibility. A note in the documentation says v1 is not backwards compatible, but that version negotiation is built into all protocol layers, giving forward compatibility for that version and backwards compatibility for future versions, which will be backwards compatible for at least two versions back. The operational advice for server operators is to deploy a new server to a new host and retire the previous version once it is no longer used, rather than upgrading in place.
The roadmap lists three items: a SimpleX service protocol and application template so that services and chat bots can be built over the SimpleX protocol stack, with a notification service for a mobile app planned first; SMP queue redundancy and rotation in agent connections; and synchronization of SMP agents to share connections and messages between multiple agents, which would allow using multiple devices with simplex-chat. None of these are implemented yet, and the second and third are the ones that would change how you run it today.
Editorial conclusion
Adopt SimpleXMQ if you want to run your own message broker for SimpleX style clients, need a Haskell library that speaks the SMP agent protocol, or want a duplex channel built on top of one-way queues. Do not adopt it if you need a general purpose broker with a mature client ecosystem, and read the AGPL-3.0 terms carefully before embedding it in a service you offer to others. Verify first that your host has OpenSSL rather than LibreSSL, that you can run smp-server init and store the CA private key somewhere safe, and that the version you deploy matches the client library you build against.
Frequently asked questions
How do I install the SimpleXMQ SMP server on macOS?
The server requires OpenSSL for initialization, and the documentation warns that macOS may have LibreSSL, which does not support the required algorithms. Run `openssl version` first, and if it reports LibreSSL, install original OpenSSL through Homebrew and add it to your PATH before running `smp-server init`.
What license is SimpleXMQ released under?
AGPL-3.0. That matters for anyone who modifies the broker and offers it to users over a network, since the copyleft obligation extends to network use.
Does the SimpleXMQ server persist messages across restarts?
The server uses in-memory persistence with an optional append-only log of created queues, enabled with `smp-server -l` or the enable = on option in smp-server.ini. Since version 2.3.0, undelivered messages can be saved on exit and restored on start, but only when the server is stopped with SIGINT, not SIGTERM.
What is the difference between the SMP server, client library and agent in SimpleXMQ?
The server is the broker, the client library connects to SMP servers with a functional API and automatic keep-alives, and the agent manages duplex connections over the one-way queues and can be embedded in another application or run as a standalone process on TCP port 5224.
Is the SimpleXMQ release stable?
The listed releases are v7.1.0 betas, with beta.4 dated 2026-10-17 and the last push on 2026-10-19. The documentation also notes that v1 was not backwards compatible and advises operators to deploy a new server on a new host and retire the old one.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/simplex-chat-simplexmq)Was this useful?