call_end

    • chevron_right

      Erlang Solutions: Reliability is a Product Decision

      news.movim.eu / PlanetJabber • 2 days ago • 6 minutes

    Reliability is often treated as something that can be improved once a system is live. When things break, the focus shifts to monitoring, incident response, and recovery, with the belief that resilience can be strengthened over time as scale reveals weaknesses.

    In reality, most of it is set much earlier.

    Long before a system faces sustained demand, its underlying design has already shaped how it will respond under pressure. Choices about service boundaries, data handling, deployment models, and fault management influence whether a problem stays contained or spreads.

    The conversation is gradually moving from reliability to resilience because distributed systems rarely operate without failure. The more useful question is how a platform continues running when parts of it inevitably fail. The sections that follow explore how early architectural decisions shape that outcome, why their impact becomes more visible at scale, and what it means to build resilience from the beginning rather than react to it later.

    Early Decisions Create Long-Term Behaviour

    Large-scale failures rarely emerge without warning. What appears sudden at scale is often the predictable outcome of structural decisions made earlier, when different commercial pressures shaped priorities.

    In the early stages of a product, the focus is understandably on delivering value quickly, reducing development friction, and validating the market. These are rational business decisions. However, architecture chosen primarily for speed can quietly define the operational ceiling of the system, setting limits that only become visible once demand increases.

    Systems Behave as They Were Built to Behave

    Outages are often described as “unexpected events,” but distributed systems typically respond to pressure in ways that reflect their design. How services communicate, how state is shared, where dependencies sit, and how failure is managed all influence whether disruption remains contained within a single component or spreads across the wider platform.

    Research from Google’s Site Reliability Engineering work shows that around 70% of outages are caused by changes to a live system, such as configuration updates, deployments, or operational changes, rather than by hardware failures. Similarly, the Uptime Institute’s Annual Outage Analysis identifies configuration errors and dependency failures as leading causes of major disruption.

    These findings are unsurprising. In distributed environments, dependencies increase and recovery paths become harder to trace, which means that architectural shortcuts that once seemed minor can have disproportionate impact under sustained load. Systems tend to fail along the structural lines already drawn into them, and those lines are shaped by early design decisions, even when those decisions were commercially sensible at the time.

    Trade-offs That Compound Over Time

    Architectural decisions are rarely made under ideal conditions. Early on, speed to market matters, simplicity reduces friction, and shipping is the priority. A tightly coupled service can help teams move faster, a single-region deployment keeps things straightforward, and limited observability may feel acceptable when traffic is still modest.

    But overtime, these trade-offs compound.

    • Limited isolation between services makes it easier for problems in one area to affect others.
    • Shared infrastructure can create hidden dependencies that only become visible under heavy demand.
      Concentrated regional deployments increase the impact of a local outage or cloud disruption.
    • Observability that felt sufficient at launch can fall short when trying to understand complex behaviour at scale.

    At a smaller scale, these constraints can go largely unnoticed. As usage increases and demand becomes less predictable, they start to shape how the system responds under pressure. What once felt manageable begins to show its limits.

    This is rarely about a lack of technical ability. It is simply what happens as complexity builds over time. Every system reflects the trade-offs made in its early stages, whether those choices were deliberate or just practical at the time.

    When Architecture Becomes Business Exposure

    As systems grow in scale and complexity, the way they are built starts to show up in practical ways. When services are tightly connected, recovery takes longer. When failures are not well contained, a problem in one area can disrupt others. Incidents become harder to resolve and more expensive to manage.

    The cost of disruption is not abstract. ITIC’s 2023 Hourly Cost of Downtime Survey reports that more than 90% of mid-size and large enterprises estimate a single hour of downtime costs over $300,000, and roughly 41% place that figure between $1 million and $5 million per hour. At that level, even short-lived incidents carry material financial impact.

    For organisations that rely on digital platforms to generate revenue, those numbers represent missed transactions, operational strain, and damage to customer trust. At that point, system design is no longer just an engineering decision. It becomes a business decision with measurable financial consequences.

    When Failure Is Public

    Some systems fail quietly, disrupting internal workflows or back-office processes with limited external visibility. Others operate in real time, where performance issues are experienced directly by customers, investors, and partners.

    In sectors such as entertainment, demand is often synchronised and predictable. Premieres, sporting events, ticket releases, and major launches concentrate traffic into specific windows, placing simultaneous pressure on application layers, databases, and third-party services. These moments are not unusual spikes; they are built into the operating model. Platforms designed for large-scale engagement are expected to handle peak demand as part of normal business activity.

    That expectation changes the stakes. When performance degrades in these environments, it is noticed immediately and often publicly. Frustration spreads quickly, confidence can shift in hours, and what might have been an operational issue becomes a visible business problem.

    In this context, resilience shapes whether a high-demand event reinforces confidence in the platform or exposes its limits. When failure is experienced directly by users, it moves beyond internal metrics and becomes part of the customer experience itself.

    Designing for Resilience

    If failure is inevitable in distributed systems, then resilience has to be built in from the start. It cannot be something added later when the first serious incident forces the issue.

    Resilient systems are structured so that problems stay contained. A fault in one component should not automatically take others down with it, and services should be able to keep operating even when parts of the system are degraded. External dependencies will fail. Traffic will spike. The design needs to account for that reality.

    This way of thinking shifts the focus. Instead of trying to prevent every possible issue, teams concentrate on limiting the impact when something goes wrong. Speed still matters, but so does the ability to grow without introducing instability.

    Technology choices can support that approach. Elixir programming language , running on the BEAM, was designed for environments where downtime had real consequences. Its structure reflects that:

    • Applications are made up of many small, independent processes rather than large, tightly connected components.
    • Failures are expected and handled locally.
    • Supervision and recovery are built into the runtime so the wider system keeps running.

    No language guarantees reliability, but tools built around fault tolerance make it easier to create systems that continue operating under pressure.

    To conclude

    By the time serious issues appear at scale, most of the important decisions have already been made.

    Failure is part of running distributed systems. What matters is whether problems stay contained and whether the platform keeps operating when something goes wrong.

    Thinking about resilience early makes growth easier later. It helps protect revenue, maintain trust, and avoid the instability that forces costly redesigns.If you are building distributed platforms where reliability directly affects performance and reputation, now is the time to treat resilience as a core design decision. Get in touch to discuss how to build it into your architecture from the start.

    The post Reliability is a Product Decision appeared first on Erlang Solutions .

    • chevron_right

      JMP: Google Wants to Control Your Device

      news.movim.eu / PlanetJabber • 24 February 2026 • 4 minutes

    Today we join with other organizations in signing the open letter to Google about their plans to require all Android app developers to register centrally with Google in order to distribute applications outside the Google Play Store.  You should go read the letter, it is quite well done. We want to talk a little bit additionally about why sideloading (aka installing apps on your own device, or “directly installing” as the letter puts it) is important to us

    In early fall of 2024 Google Play decided to remove and ban the Cheogram app from their store.  Worse, since it had been listed by Play as “malware” Google’s Play Protect system began warning existing users that they should uninstall the existing app from their devices.  This was, as you might imagine, very bad for us.  No new customers could get the app and existing customers were contacting support unsure how to get back into their account after being tricked into removing it.

    After a single submission to Google Play appealing this decision, they came back very quickly affirming “yes, this app seems to be malware.” No indication of why they thought that, just a decision. At this point the box we could use to submit new appeals also went away.  With no appeals process available and requests to what little support Google has going totally ignored, it was not clear if we were ever going to be able to distribute our app in the Play Store again.  After months of being delisted we finally got a lucky break.  In talking with some of our contacts at the Software Freedom Conservancy , they offered to write to some of their contacts deep inside Google and ask if there was anything that could be done. When their contact pushed internally at Google to get more information, suddenly the app was re-activated in the Play Store

    I want to be clear here. We did not change the app. We did not upload a new build. This app Google had been so very, very sure was “malware” was fully reinstated and available to customers again the moment a human being bothered to actually look at it. It was of course obvious to any human looking at the app that it is not malware and so they restored it to the store immediately. They never replied to that final request, and no details about what happened were ever made available. From that point on Google has essentially pretended that this never happened and the app was always great and in the Play Store. If we had not been able to get in contact with a human and really push them to take a look, however, we would never have been reinstated.

    Despite our good fortune, we still lost months of potential business over this. Of course you’ve heard stories like this before. Stories of Play Store abuse are a dime a dozen and most of them don’t have the “happy” ending ours does. What does this have to do with “sideloading” and the open letter? Well, despite all the months of lost business, and despite all the existing customers being told to uninstall their app if they had got it from Play Store, we lost no more than 10% of our customers and continued to onboard new ones during the entire time.  How is this possible?  The main reason is direct installs (“sideloading”).  The majority of our customers get the app from our preferred sources on F-Droid and Itch . These customers were not told by Play Protect to remove their app. During the time we were delisted from Play Store we removed the link to Play Store from our website and new customers were instructed to use F-Droid. Of course we still lost some business here, some people were unable or unwilling to use F-Droid or other direct install options, but the damage was far, far less than it might have otherwise been.

    What Google is proposing would allow them to ban anyone from creating apps which may be directly installed without their approval. One of the reasons they say they need to do this is to protect people from malware! Yet even if this was the narrow purpose of a ban it would still routinely catch apps which are not nefarious in any way, just as ours wasn’t. Furthermore, with all apps and developers registered in their system, a ban under these new rules could result in everyone being told to uninstall the app by Play Protect, and not just those who got it from Play Store to begin with. This would leave app developers who are erroneously marked by Google as malware with no options, no recourse, no way to appeal, and praying there is a friend of a friend who knows someone deep in Google who can poke the right button. This is just not an acceptable future for the world’s largest mobile platform.

    • chevron_right

      ProcessOne: Fluux Messenger 0.13.0 - Native TCP Connection & Complete EU Language Coverage

      news.movim.eu / PlanetJabber • 12 February 2026 • 2 minutes

    Fluux Messenger 0.13.0 - Native TCP Connection & Complete EU Language Coverage

    We&aposre excited to announce Fluux Messenger 0.13.0, featuring native TCP connections, complete European language coverage, and significant performance improvements.

    Also, we recently passed the first 100 stars on GitHub. Thank you for your support and for believing in open, sovereign messaging !

    Fluux Messenger 0.13.0 - Native TCP Connection & Complete EU Language Coverage

    What&aposs New

    Native TCP Connection Support on Desktop

    Desktop users can now connect directly to XMPP servers via native TCP through our WebSocket proxy implementation. This means lower latency, better reliability, and native protocol handling. No more browser limitations.

    We believe that&aposs a nice milestone worth a blog post . Until now, desktop users needed their XMPP server to support WebSocket connections. With v0.13.0, you can connect to any standard XMPP server. We estimate this will enable 80% of users who couldn&apost connect before to finally use Fluux Messenger with their existing servers.

    Complete European Union Language Coverage

    Fluux Messenger now supports all 26 EU languages, making it truly pan-European. From Bulgarian to Swedish, Croatian to Maltese, we&aposve got you covered. Languages include:

    • Bulgarian, Croatian, Czech, Danish, Dutch, English, Estonian, Finnish, French, German, Greek, Hungarian, Icelandic, Irish, Italian, Latvian, Lithuanian, Maltese, Norwegian, Polish, Portuguese, Romanian, Slovak, Slovenian, Spanish, Swedish.

    Dynamic locale loading means faster initial startup while maintaining comprehensive language support.

    If you spot any translation issues, feel free to contribute on our GitHub repository .

    Clipboard Image Paste

    Paste images directly from your clipboard with Cmd+V (macOS) or Ctrl+V (Windows/Linux). Copy from anywhere, paste into Fluux. It (should) just work ;). Tested and confirmed with Safari&aposs "Copy Image" feature and system clipboard operations so far.

    Clear Local Data on Logout

    New privacy option to completely clear local data when logging out. Perfect for shared devices or when you need a fresh start.

    Performance & Reliability Improvements

    • Smarter Message History Loading - We&aposve completely redesigned our Message Archive Management (MAM) strategy. Message history now loads intelligently based on your scrolling behavior and available data, reducing unnecessary server requests.

    • Better Resource Management - Fixed duplicate avatar fetches when hashes haven&apost changed, reducing bandwidth usage and improving profile picture loading times.

    • Rock-Solid Scroll Behavior - Media loading no longer disrupts your scroll position. The scroll-to-bottom feature now works reliably, even when images and files are loading.

    • Better Windows Tray - Improved tray behavior on Windows for a more native experience.

    macOS Sleep Recovery - Fixed layout corruption that could occur after your Mac woke from sleep.

    UI & UX Polish

    • Consistent attachment styling across light and dark themes
    • Fixed sidebar switching with Cmd+U keyboard shortcut
    • Improved new message markers - position correctly maintained when switching conversations
    • Better context menus - always stay within viewport bounds, no more cut-off menus
    • Markdown preview accuracy - bold and strikethrough now properly shown in message previews

    Linux Packaging

    Improved Linux packaging using native distribution tools for better integration with your system package manager.

    Developer Experience

    Centralized notification state with viewport observer provides better performance and more reliable notification handling across the application.


    Get Fluux Messenger

    Download for Windows , macOS , or Linux in the latest Release page.

    Source code is available at : GitHub


    Your messages, your infrastructure : no vendor lock-in.
    Sovereign by design. Built in Europe, for everyone.

    • chevron_right

      ProcessOne: rocket ejabberd 26.02

      news.movim.eu / PlanetJabber • 11 February 2026 • 2 minutes

    🚀 ejabberd 26.02

    Contents:

    ChangeLog

    • Fixes issue with adding hats data in presences send by group chats ( #4516 )
    • Removes mod_muc_occupantid modules, and integrates its functionality directly into mod_muc ( #4521 )
    • Fixes issue with reset occupant-id values after restart of ejabberd ( #4521 )
    • Improves handling of mediated group chat invitations in mod_block_stranger ( #4523 )
    • Properly install mod_invites templates in make install call ( #4514 )
    • Better errors in mod_invites ( #4515 )
    • Accessibility improvements in mod_invites ( #4524 )
    • Improves handling of request with invalid url encoded values in request handled by ejabberd_http
    • Improves handling of invalid responses to disco queries in mod_pubsub_serverinfo
    • Fixes conversion of MUC room configs from ejabberd older than 21.12
    • Fixes to autologin in WebAdmin

    If you are upgrading from a previous version, there are no changes in SQL schemas, configuration, API commands or hooks.

    Notice that mod_muc now incorporates the feature from mod_muc_occupantid , and that module has been removed. You can remove mod_muc_occupantid in your configuration file as it is unnecessary now, and ejabberd simply ignores it.

    Check also the commit log: https://github.com/processone/ejabberd/compare/26.01...26.02

    Acknowledgments

    We would like to thank the contributions to the source code and translations provided by:

    And also to all the people contributing in the ejabberd chatroom, issue tracker...

    Improvements in ejabberd Business Edition

    Customers of the ejabberd Business Edition , in addition to all those improvements and bugfixes, also get the following change:

    • Change default_ram_db from mnesia to p1db when using p1db cluster_backend

    ejabberd 26.02 download & feedback

    As usual, the release is tagged in the Git source code repository on GitHub .

    The source package and installers are available in ejabberd Downloads page. To check the *.asc signature files, see How to verify ProcessOne downloads integrity .

    For convenience, there are alternative download locations like the ejabberd DEB/RPM Packages Repository and the GitHub Release / Tags .

    The ecs container image is available in docker.io/ejabberd/ecs and ghcr.io/processone/ecs . The alternative ejabberd container image is available in ghcr.io/processone/ejabberd .

    If you consider that you&aposve found a bug, please search or fill a bug report on GitHub Issues .

    • chevron_right

      Mathieu Pasquet: slixmpp v1.13.2 (and .1)

      news.movim.eu / PlanetJabber • 8 February 2026

    Version 1.13.0 has shipped with a packaging bug that affects people trying to build wheels using setuptools. 1.13.1 is an attempt to fix that (made packaging from git work somehow), and 1.13.2 is the correct fix thanks to one single additional character.

    There are no other changes, and pypi wheels are not affected because they are built in CI with uv .

    Links

    You can find the new release on codeberg , pypi , or the distributions that package it in a short while.

    Previous version: 1.13.0 .

    • chevron_right

      JMP: Newsletter: Referral Event!

      news.movim.eu / PlanetJabber • 3 February 2026 • 2 minutes

    Hi everyone

    Welcome to the latest edition of your pseudo-monthly JMP update!

    In case it’s been a while since you checked out JMP, here’s a refresher: JMP lets you send and receive text and picture messages (and calls) through a real phone number right from your computer, tablet, phone, or anything else that has a Jabber client.  Among other things, JMP has these features: Your phone number on every device; Multiple phone numbers, one app; Free as in Freedom; Share one number with multiple people.

    This month begins JMP’s 2026 referral event! From now until June 1st, everyone you refer to JMP rewards you triple ! That’s three free months of service for every person who signs up and pays.

    For those who haven’t explored the referral system much, a short refresher on how it works. In your account settings there is a command Refer a friend for free credit . You will be presented with a message that reads like so:

    This code will provide credit equivalent to one month of service to anyone after they sign up and pay: CODE These remaining codes are single use and give the person using them a free month of JMP service. You will receive credit equivalent to one month of service after someone uses any of your codes and their payment clears.

    When someone uses this code during their signup process with JMP, they will sign up and pay as usual. But after they pay, they will get a free month deposited to their initial balance as well . Once their payment clears (about 90 days for a credit card transaction) your account will also get a month’s worth of credit deposited. Except for referrals which reward during this event, it will be three months! This code is appropriate for publishing publicly and can be used over and over again.

    Under this message in the command result is a list of invite codes. If you are out of invite codes, you can always ask JMP support for more as well. These codes are each single-use and give the one person who uses them a free month of JMP service right away. They don’t pay anything. Then, if they pay, and once their payment clears (about 90 days for a credit card transaction) your account will also get a month’s worth of credit deposited. Except for referrals which reward during this event, it will be three months! These codes are appropriate for giving to trusted friends or family members, and each code can only be used once.

    To learn what’s happening with JMP between newsletters, here are some ways you can find out:

    Thanks for reading and have a wonderful rest of your week!

    • chevron_right

      ProcessOne: Introducing Fluux Messenger: A Modern XMPP Client Born from a Holiday Coding Session

      news.movim.eu / PlanetJabber • 28 January 2026 • 4 minutes

    Introducing Fluux Messenger: A Modern XMPP Client Born from a Holiday Coding Session

    It was mid-December 2025, just before the Christmas break. My favorite XMPP client had broken on the main branch I was using. Frustrated, rather than waiting for a fix, I decided I wanted to give another try at working on a client. This time, I would be using the opportunity to explore a new set of tools I was curious about: TypeScript, React, and Tauri.

    What started as a weekend experiment quickly turned into something more. Using AI tools to accelerate the initial setup, I found myself totally absorbed in the work. Days blurred together as features took shape. By early January, what had been a personal scratch project had become a surprisingly capable desktop client.

    When I demonstrated it to my coworkers at ProcessOne, their reaction was unanimous: this was worth pursuing seriously. We decided to put the entire company behind the effort. Today, we&aposre sharing the first public release of Fluux Messenger .

    More Than Just Another Chat Client

    At ProcessOne, we&aposve spent over two decades building messaging infrastructure. Our XMPP server, ejabberd, has powered some of the world&aposs largest messaging deployments. But we&aposve always approached messaging from the server side. Fluux Messenger represents something new for us, bringing that same engineering philosophy to the client.

    The key innovation isn&apost in the UI (though we&aposre proud of it). It&aposs in what lies beneath: the Fluux SDK .

    The Fluux SDK: Bridging Two Worlds

    Anyone who has built an XMPP client knows the challenge. XMPP is event-driven, signal-based, asynchronous. Modern UI frameworks expect reactive state, typed data, and predictable updates. There&aposs an impedance mismatch between these two worlds.

    The Fluux SDK is our answer. It provides a high-level TypeScript API that handles all XMPP complexity internally. Developers work with clean types and reactive state, not XML stanzas. The SDK maintains local cache, manages reconnection, and handles synchronization intelligently. It&aposs not a passive pipe between server and UI; it&aposs an active participant that makes the client easier to develop and more resilient.

    As an example, the client is not telling the SDK which presence it wants to publish when stepping away from the computer, but it will signal to the SDK that it is inactive. The SDK is responsible for doing the right thing.

    This three-tiered architecture, Server -> Headless client (SDK) -> UI, lets us apply the same design principles that made ejabberd scalable to the client side. Distributed logic, local-first responsiveness, server-side efficiency.

    What Fluux Messenger Offers Today

    The current release (v0.11.1) already includes substantial functionality:

    • Reliable connection and message management
    • Cross-platform desktop app for Windows, macOS, and Linux, built on Tauri for a lightweight native experience
    • Web version : It works great on the Web as well.
    • 40+ XMPP extensions (XEPs) implemented, including message archive management, multi-user chat, HTTP file upload, message carbons, and reactions
    • MUC support with @mentions notification and bookmarks
    • Local message cache storage using IndexedDB with automatic sync on reconnect
    • Built-in XMPP console for developers and power users who want to see what&aposs happening under the hood
    • Preliminary admin capabilities letting you manage your ejabberd server directly from the client (But this is still mostly a work in progress).
    • 8 languages supported out of the box
    • Light and dark modes with theme system to come
    Introducing Fluux Messenger: A Modern XMPP Client Born from a Holiday Coding Session

    What I envision for Fluux Messenger is to follow the steps of major projects like Obsidian or VSCode . In my wildest dreams, I expect Fluux Messenger to become as configurable and versatile as those tools.

    The Road Ahead

    This is an ambitious project. The roadmap stretches far into the future, and we&aposre just getting started. Our plans include mobile support through PWA and eventually native apps, expansion to other frameworks (Vue, Svelte), and Kotlin Multiplatform for Android and iOS.

    But ambitious doesn&apost mean closed. Fluux Messenger is open source under AGPL-3.0. We believe that modern, privacy-respecting messaging shouldn&apost require vendor lock-in. Connect to any XMPP server. Host it yourself.

    I used AI to bootstrap this project and accelerate my learning phase. Many developers do now. But we are crafters at ProcessOne, and we want to own the responsibility for great code. Those who know me will tell you I&aposll be relentless until I master React and TypeScript, and they know I will. Fast.

    A Continuation of ejabberd&aposs Vision

    Fluux Messenger represents the client-side continuation of what we started with ejabberd over twenty years ago. The same principles, scalability, reliability, clean architecture, now flow from server to client. If you&aposve trusted ejabberd to power your messaging infrastructure, we hope you&aposll trust Fluux Messenger to be the interface your users deserve.

    This is the beginning of an exciting journey. We hope you&aposll join us.


    Get started

    If you share our vision for clean, reactive messaging APIs, we&aposd love to collaborate. Reach out and let&aposs grow the Fluux community together.

    • chevron_right

      ProcessOne: rocket ejabberd 26.01

      news.movim.eu / PlanetJabber • 21 January 2026 • 19 minutes

    🚀 ejabberd 26.01

    This release is the result of three months of development, implementing those new features, and fixing bugs.

    Release Highlights:

    If you are upgrading from a previous version, there are no mandatory changes in SQL schemas, configuration, API commands or hooks. However new mod_invites uses a new table in databases, see below.

    Other contents:

    Below is a detailed breakdown of the improvements and enhancements:

    Database Serialization

    This feature adds new way for migrating data between database backends by exporting data from one backend to a file and importing that into different backend (or possibly to same backend but on different machine).

    Migrating data using this can be executed by first exporting all data with export_db command, changing configuration of ejabberd and switching modules to use new database backend, and then importing previously exported data using import_db command.

    This mechanism works by calling those new command from ejabberdctl, for exporting data:

    • ejabberdctl export_db <host name> <path to directory where exported files should be placed>
    • ejabberdctl export_db_abort <host name>
    • ejabberdctl export_db_status <host name>

    and for importing:

    • ejabberdctl import_db <host name> <path to directory with exported data>
    • ejabberdctl import_db_abort <host name>
    • ejabberdclt import_db_status <host name>

    Exporting and importing work in background after starting them from ejabberdctl (commands executed by ejabberdctl have time limit for how long they can work, with this setup there should be not issue with export or import getting aborted by that), and current progress of background operation can be tracked by calling corresponding *_db_status command. Operation in progress can be also aborted by executing *_db_abort command.

    Roster Invites and Invite-based Account Registration

    Until now the canonical method to register an account in ejabberd was to let anybody register accounts using In-Band Registration (IBR) ( mod_register ) or Web Registration ( mod_register_web ), and then try to limit abuse with access limitations or CAPTCHAs . Often this process got abused, with the result that account registration had to be disabled and rely on manual registration by administrators.

    The new mod_invites implements support for invite-based account registration: administrators can generate invitation URLs, and send them to the desired users (by email or whatever). Then the user that receives an invitation can visit this invitation URL to register a new account.

    On top of that, mod_invites lets you create Roster Invites: you can send a link to some other person so they can connect to you in a very user-friendly and intuitive way that doesn&apost require any further interaction. If account creation is allowed, these links will also allow to setup an account in case the recipient doesn&apost have one yet.

    Relevant links:

    Quick setup:

    1. If using SQL storage for the modules and have disabled the update_sql_schema toplevel option, then create manually the SQL table , see below.

    2. If you plan to use the landing page included with mod_invites , install JavaScript libraries jQuery version 3.7.1 and Bootstrap version 4.6.2 . This example configuration will assume they are installed in /usr/share/javascript . The ejabberd container image already includes those libraries. Some quick examples, in case you need some help:

      • Debian and related:

        apt install libjs-jquery libjs-bootstrap4
        
      • AlpineLinux and other operating systems where you can install npm , for example:

        apk -U add --no-cache nodejs npm ca-certificates
        
        npm init -y \
          && npm install --silent jquery@3.7.1 bootstrap@4.6.2
        
        mkdir -p /usr/share/javascript/jquery
        mkdir -p /usr/share/javascript/bootstrap4/{css,js}
        cp node_modules/jquery/dist/jquery.min.js /usr/share/javascript/jquery/
        cp node_modules/bootstrap/dist/css/bootstrap.min.css /usr/share/javascript/bootstrap4/css/
        cp node_modules/bootstrap/dist/js/bootstrap.min.js /usr/share/javascript/bootstrap4/js/
        
      • Generic method using the included script:

        tools/dl_invites_page_deps.sh /usr/share/javascript
        
    3. Configure ejabberd to serve the JavaScript libraries in path /share ; serve mod_invites in any path of your selection; and enable mod_invites with some basic options. Remember to setup mod_register to allow registering accounts using mod_invites. For example:

      listen:
        - port: 5443
          ip: "::"
          module: ejabberd_http
          tls: true
          request_handlers:
            /invites: mod_invites
            /share: mod_http_fileserver
      
       modules:
        mod_http_fileserver:
          docroot:
            /share: /usr/share/javascript
        mod_invites:
          access_create_account: configure
          landing_page: auto
        mod_register:
          allow_modules:
            - mod_invites
      
    4. There are many ways to generate invitations:

      • Login with an admin account, then you can execute Ad-Hoc Commands like "Invite User" and "Create Account"
      • If mod_adhoc_api is enabled, you can execute equivalent API Commands generate_invite and generate_invite_with_username
      • Run those API Commands from the command-line, for example: ejabberdctl generate_invite localhost
    5. All those methods give you an invitation URL that you can send it to the desired user, and looks like

      https://localhost:5443/invites/Yrw5nuC1Kpxy9ymbRzmVGzWQ
      
    6. The destination user (or yourself) can visit that invitation URL and follow the instructions to register the account and download a compatible client.

    If the user has installed already a compatible XMPP client, you don&apost no need to install JavaScript libraries and setup a landing page. In that case, when generating an invitation you will get only the XMPP URI; when the user opens that URI in a web browser, it will automatically open the XMPP client and the corresponding registration window.

    Probably you don&apost want to expose the port directly, then you need to setup Nginx or Apache to act as a "reverse" proxy and change your landing_page parameter accordingly, for example just https://@HOST@/invites/{{ invite.token }}

    Notice that the landing page can be fully translated using the existing ejabberd localization feature .

    🚀 ejabberd 26.01

    SQL table for mod_invites

    There is a new table invite_token in SQL schemas, used by the new mod_invites . If you want to use this module, there are two methods to update the SQL schema of your existing database:

    If using MySQL or PosgreSQL, you can enable the option update_sql_schema and ejabberd will take care to update the SQL schema when needed: add in your ejabberd configuration file the line update_sql_schema: true

    Notice that support for MSSQL in mod_invites has not yet been implemented or tested.

    If you are using other database, or prefer to update manually the SQL schema:

    • MySQL singlehost schema:

      CREATE TABLE invite_token (
          token text NOT NULL,
          username text NOT NULL,
          invitee text NOT NULL DEFAULT (&apos&apos),
          created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
          expires timestamp NOT NULL,
          type character(1) NOT NULL,
          account_name text NOT NULL,
          PRIMARY KEY (token(191))
      ) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
      
      CREATE INDEX i_invite_token_username USING BTREE ON invite_token(username(191));
      
    • MySQL multihost schema:

      CREATE TABLE invite_token (
          token text NOT NULL,
          username text NOT NULL,
          server_host varchar(191) NOT NULL,
          invitee text NOT NULL DEFAULT &apos&apos,
          created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
          expires timestamp NOT NULL,
          type character(1) NOT NULL,
          account_name text NOT NULL,
          PRIMARY KEY (token(191)),
      ) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
      
      CREATE INDEX i_invite_token_username USING BTREE ON invite_token(username(191));
      
    • PostgreSQL singlehost schema:

      CREATE TABLE invite_token (
          token text NOT NULL,
          username text NOT NULL,
          invitee text NOT NULL DEFAULT &apos&apos,
          created_at timestamp NOT NULL DEFAULT now(),
          expires timestamp NOT NULL,
          "type" character(1) NOT NULL,
          account_name text NOT NULL,
          PRIMARY KEY (token)
      );
      CREATE INDEX i_invite_token_username ON invite_token USING btree (username);
      
    • PostgreSQL multihost schema:

      CREATE TABLE invite_token (
          token text NOT NULL,
          username text NOT NULL,
          server_host text NOT NULL,
          invitee text NOT NULL DEFAULT &apos&apos,
          created_at timestamp NOT NULL DEFAULT now(),
          expires timestamp NOT NULL,
          "type" character(1) NOT NULL,
          account_name text NOT NULL,
          PRIMARY KEY (token)
      );
      
      CREATE INDEX i_invite_token_username_server_host ON invite_token USING btree (username, server_host);
      
    • SQLite singlehost schema:

      CREATE TABLE invite_token (
          token text NOT NULL,
          username text NOT NULL,
          invitee text NOT NULL DEFAULT &apos&apos,
          created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
          expires timestamp NOT NULL,
          type character(1) NOT NULL,
          account_name text NOT NULL,
          PRIMARY KEY (token)
      );
      
      CREATE INDEX i_invite_token_username ON invite_token(username);
      
    • SQLite multihost schema:

      CREATE TABLE invite_token (
          token text NOT NULL,
          username text NOT NULL,
          server_host text NOT NULL,
          invitee text NOT NULL DEFAULT &apos&apos,
          created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
          expires timestamp NOT NULL,
          type character(1) NOT NULL,
          account_name text NOT NULL,
          PRIMARY KEY (token)
      );
      
      CREATE INDEX i_invite_token_username_server_host ON invite_token(username, server_host);
      

    New replaced_connection_timeout toplevel option

    The new replaced_connection_timeout toplevel option enables new session to wait for termination of session that it replaces.

    This should mitigate problems where old session presences unavailable sometimes were delivered after new session sent it&aposs presence available.

    Improved mod_http_fileserver docroot option

    mod_http_fileserver is a module to serve files from the local disk over HTTP, useful if you just want to serve some HTML or binary files that don&apost need PHP, and don&apost need to setup or configure a separate full-blown web server.

    Now the docroot option may be a map of paths to serve, allowing this module to serve several paths with different directories for different purposes.

    For example, let&aposs serve some public content from /var/service/www , also shared JavaScript libraries, and for base URL let&aposs serve from /var/www :

    listen:
      -
        port: 5280
        module: ejabberd_http
        request_handlers:
          /pub/content: mod_http_fileserver
          /share: mod_http_fileserver
          /: mod_http_fileserver
    modules:
      mod_http_fileserver:
        docroot:
          /pub/content: /var/service/www
          /share: /usr/share/javascript
          /: /var/www
    

    Notice that ejabberd includes many modules that serve web services, that may be useful to save you from setting up a full-blown web server, see ejabberd_http .

    Supported XEP versions

    ejabberd supports close to 90 XMPP extension protocols (XEPs) , either directly implemented in ejabberd source code, in the libraries that implement many of the internal features, or in other ejabberd modules available in other repositories like ejabberd-contrib .

    Those XEPs are updated regularly to bring major improvements, minor changes, fixing typos, editorial or cosmetic changes... and this requires a regular review of those XEP updates in the software implementations to keep them up to date, or at least to document what exact version of the protocols are implemented.

    In this sense, we have reviewed all the XEP versions that ejabberd and erlang xmpp library were not up-to-date, and have identified which ones are already up-to-date in their DOAP files. Now the pages at XMPP.org describe more accurately the supported protocol versions, see ejabberd at XMPP.org and erlang-xmpp at XMPP.org .

    Erlang, Elixir and Container

    ejabberd can be compiled with Erlang/OTP from 25.0 up to the latest 28.3.1. Regarding Elixir support, ejabberd supports from Elixir 1.14.0 up to the latest 1.19.5

    Right now ejabberd compiles correctly with Erlang/OTP from git development branch and Elixir 1.20.0-RC1, so hopefully compatibility with the upcoming Erlang/OTP 29 and Elixir 1.20 will be easily achievable.

    Binary installers and the ejabberd container now include Erlang/OTP 28.3.1 instead of 27.3, and Elixir 1.19.5 instead of 1.18.4.

    Speaking of the container images , both ejabberd and ecs bring other minor changes: they expose more ports : 5478 UDP (STUN service), 7777 (SOCKS5 file transfer proxy) and 50000-50099 UDP (TURN service).
    The container images in their ejabberd.yml file use new macros PORT_TURN_MIN , PORT_TURN_MAX , and STARTTLS_REQUIRED that you can setup easily without modifying ejabberd.yml , see macros in environment .

    Improved ERL_DIST_PORT

    ejabberd uses Erlang Distribution in the ejabberdctl shell script and also for building a cluster of ejabberd nodes.

    That Erlang Distribution has historically used the epmd program to assign listening ports and discover ports of other nodes to connect. The problems of using epmd are that:

    • epmd must be running all the time in order to resolve name queries
    • epmd listens in port 4369
    • the ejabberd node listens in a random port number

    How to avoid epmd since Erlang/OTP 23.1 and ejabberd 22.10 ? Simply set the ERL_DIST_PORT environment variable in the ejabberdctl.cfg file:

    ERL_DIST_PORT=5210
    

    Since now, ejabberdctl passes arguments to Erlang to listen for erlang distribution connections in TCP port 5210, and establish erlang distribution connections to remote ports 5210. That way you know exactly, in advance, what port number to open in the firewall or container.

    This ejabberd release introduces some small improvements that facilitate using the ERL_DIST_PORT environment variable:

    • ejabberdctl prints an informative message when it detects that there may be a port number collision, which may happen if you start several ejabberd nodes in the same machine listening in the same ERL_DIST_PORT and same INET_DIST_INTERFACE .

    • When ejabberd is starting, now it prints the address and port number where it listens for erlang distribution:

      [info] ejabberd 26.01 is started in the node ejabberd@localhost in 1.90s
      [info] Elixir 1.19.4 (compiled with Erlang/OTP 28)
      [info] Erlang/OTP 29 [DEVELOPMENT] [erts-16.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [jit:ns]
      
      [info] Start accepting TCP connections at 0.0.0.0:5210 for erlang distribution
      [info] Start accepting TCP connections at [::]:5222 for ejabberd_c2s
      [info] Start accepting TCP connections at [::]:5269 for ejabberd_s2s_in
      ...
      
    • A new make relivectl is introduced, which uses ejabberdctl script to start ejabberd (not like make relive ), and starts ejabberd immediately without building a release (not like make dev ).

    • The ejabberd Documentation site has improved and updated pages about Security , Erlang Distribution , and Clustering .

    New make relivectl

    make relive was introduced in ejabberd 22.05 . It allows to start ejabberd in path _build/relive/ without installing it, by using rebar3 shell and mix run . It automatically compiles code at start and recompiles changed code at runtime . But it doesn&apost use the ejabberdctl script, and doesn&apost read ejabberdctl.cfg , this means that depending on what you are testing, it may not be useful and you had to switch to make dev .

    A new make target is now introduced: make relivectl . This is similar, as it starts ejabberd without requiring installation, using path _build/relivectl/ to store the configuration, database and log files. The benefit over relive is that relivectl uses ejabberdctl and reads ejabberdctl.cfg . The drawback is that it doesn&apost recompile code automatically. The benefit over make dev is that relivectl doesn&apost build an OTP release, so it&aposs faster to start.

    Let&aposs summarize all the make targets related to installation to determine their usage differences:

    make ... install install-rel prod dev relivectl relive
    Writes files in path / / _build/
    prod/
    _build/
    dev/
    _build/
    relivectl/
    _build/
    relive/
    Installs manually uncompress *.tar.gz - - -
    Uninstall with uninstall
    ⚠️ incomplete
    uninstall-rel
    manual remove - - -
    Start tool ejabberdctl ejabberdctl ejabberdctl ejabberdctl ejabberdctl rebar3/mix
    Reads ejabberdctl.cfg
    Recompiles -
    Starts ejabberd - - - -
    Recompiles at runtime - - - -
    Execution time (s.) 13 40 57 35 4 9

    As seen in the table, make install / uninstall seem unnecessary nowadays, because install-rel / uninstall-rel allow to install and uninstall correctly all the files. Maybe in the future the implementation of make install / uninstall could get replaced with make install-rel / uninstall-rel ...

    In the same sense, make dev now apparently falls short between make prod (which is absolutely indispensable to build a full OTP release) and make relive/relivectl (useful, featureful, and fast for development and testing purposes).

    WebAdmin Menu Links

    Do you remember that ejabberd 25.07 introduced a link in WebAdmin to the local Converse.js page in the left menu when the corresponding mod_conversejs is enabled?

    Technically speaking, until now the WebAdmin menu included a link to the first request_handler with mod_conversejs that the admin configured in ejabberd.yml . That link included the authentication credentials hashed as URI arguments if using HTTPS. Then process/2 extracted those arguments and passed them as autologin options to Converse.

    From now, mod_conversejs automatically adds a request_handler nested in WebAdmin subpath. The WebAdmin menu links to that converse URI; this allows to access the HTTP auth credentials, no need to explicitly pass them. process/2 extracts this HTTP auth and passes autologin options to Converse. Now scram password storage is supported too.

    In practice, what does all that mean? Just enable the mod_conversejs module, and WebAdmin will have a private Converse URL for the admin, linked in the WebAdmin menu, with autologin. No need to setup a public request_handler !

    For example, let&aposs configure conversejs only for admin usage:

    listen:
      -
        port: 5443
        module: ejabberd_http
        tls: true
        request_handlers:
          /admin: ejabberd_web_admin
          /ws: ejabberd_http_ws
    
    modules:
      mod_conversejs:
        conversejs_resources: "/home/conversejs/12.0.0/dist"
    

    Of course, you can setup a public request_handler and tell your users to access the corresponding URL:

    listen:
      -
        port: 5443
        module: ejabberd_http
        tls: true
        request_handlers:
          /admin: ejabberd_web_admin
          /public/web-client: mod_conversejs
          /ws: ejabberd_http_ws
    
    modules:
      mod_conversejs:
        conversejs_resources: "/home/conversejs/12.0.0/dist"
    

    With that configuration, what is the corresponding URL ?

    Login to the WebAdmin and look at the left menu: now it displays links to all the configured HTTP services: ejabberd_captcha , ejabberd_oauth , mod_conversejs , mod_http_fileserver , mod_register_web . Also mod_muc_log_http and mod_webpresence from ejabberd-contrib show links in the WebAdmin left menu. Additionally, the menu shows a lock if the page is encrypted HTTPS, and an ! if it is not.

    Acknowledgments

    We would like to thank the contributions to the source code, documentation, and translation provided for this release by:

    And also to all the people contributing in the ejabberd chatroom, issue tracker...

    Improvements in ejabberd Business Edition

    Customers of the ejabberd Business Edition , in addition to all those improvements and bugfixes, also get the following changes:

    • New module mod_push_gate that can act as target service for mod_push , and which can deliver pushes using configured mod_gcm or mod_applepush instances.
    • New module mod_push_templates that can be used to have different push notifications for message class matching configured data patterns.
    • New database conversion routines targeting p1db backends

    ChangeLog

    This is a more complete list of changes in this ejabberd release:

    Compile and Start

    • Remove dependencies, macros and code for Erlang/OTP older than 25
    • Require Elixir 1.14 or higher, that&aposs the lowest we can test automatically
    • ejabberdctl : Support NetBSD and OpenBSD su ( #4320 )
    • ejabberdctl.template : Show meaningful error when ERL_DIST_PORT is in use
    • ejabberd_app : Print address and port where listens for erlang node connections
    • Makefile.in : Add make relivectl similar to relive but using ejabberdctl

    Databases

    • Add db_serialize support in mnesia modules
    • Add db serialization to mod_muc_sql
    • New database export/import infrastructure
    • Add commands for new database export/import
    • Apply timestamp pass in ?SQL_INSERT queries
    • Update p1_mysql to bring fix for timestamp decoding
    • Extend timestamp type handling in sql macros
    • Revert changes to conversion of pgsql int types

    Installer and Container

    • make-binaries : Bump Erlang/OTP 28.3.1 and Elixir 1.19.5
    • Dockerfile : Bump Erlang/OTP 28.3.1 and Elixir 1.19.5
    • Dockerfile : Expose also port 7777 for SOCKS5
    • Dockerfile : Configure TURN ports and expose 5478 50000-50099
    • Dockerfile : Try to fix error with recent freetds Alpine package
    • Container: Setup new macro STARTTLS_REQUIRED to allow easy disabling

    MUC

    • Add muc_online_rooms_count API command
    • Set enable_hats room option true by default
    • Allow vcard queries even when IQ queries are disabled ( #4489 )
    • Announce stable-id feature from XEP-0045 1.31, supported since long ago
    • Fix preload_rooms in case of SQL database ( #4476 )
    • Run new hooks: registering_nickmuc and registered_nickmuc ( #4478 )
    • When deleting account, unregister account&aposs nicks in all MUC hosts ( #4478 )
    • mod_muc_log : Crash in terminate/2 when stopping module ( #4486 )
    • mod_muc_occupantid : Keep salt per MUC service, not individual rooms
    • mod_muc_room : Rewrite hats code that gets xdata values
    • mod_muc_room : Handle hats without definition ( #4503 )
    • mod_muc_room : When user has no hats, don&apost store in hats_users

    WebAdmin

    • ejabberd_http : Run new http_request_handlers_init fold hook
    • ejabberd_http : Add helper get_auto_urls/2 that returns all URLs and TLS
    • ejabberd_web_admin : Add helper functions make_menu_system
    • ejabberd_web_admin : Show menu system only when can view vhosts
    • ejabberd_web_admin : Pass Level in webadmin_menu_system_post and inside hooks
    • mod_conversejs : Improve link to conversejs in WebAdmin ( #4495 )
    • When epmd isn&apost running show explanation in Clustering WebAdmin page
    • Use improved WebAdmin menu system in more modules
    • When building WebAdmin menu system, {URLPATH} in link text is substituted

    Web Services

    • rest : Use separate httpc profile
    • ejabberd_captcha : Use mod_host_meta:get_auto_url/2
    • ejabberd_http : Support repeated module in request_handlers
    • ejabberd_http : Get back handling when BOSH or WS are disabled
    • mod_host_meta : Move get_url functions from mod_host_meta to ejabberd_http
    • mod_host_meta : Allow calling get_url/2 for other modules, not only WebSocket
    • mod_host_meta : Cosmetic rename Module to Handler
    • mod_http_upload : New content_type option similar to mod_http_fileserver ( #4488 )
    • mod_http_upload : Pass ServerHost, not Host which may be "upload.HOST"
    • mod_http_upload : Amend the fix for #4450 to support IDNA correctly ( #3519 )
    • mod_http_fileserver : Support map of paths in docroot option
    • mod_conversejs : Add new Conversejs Paths and ContentTypes ( #4511 )
    • mod_conversejs : Use ContentType functions from mod_http_fileserver ( #4511 )
    • Use /websocket URL in default configuration like mod_conversejs , it&aposs more meaningful

    Core and Modules

    • Add replaced_connection_timeout toplevel option
    • Fix nasty SSL warnings ( #4475 )
    • ejabberd_commands : Show meaningul error message when problem executing command ( #4506 )
    • ejabberd_logger : Append "color clean" only in console template, not file
    • ejabberd_oauth : Log error if oauth_list_tokens executed with unsupported DB ( #4506 )
    • misc : Get back functions and mark them as deprecated
    • mod_adhoc_api : Show nice command name, as WebAdmin already does
    • mod_pubsub : Deliver pubsub notifications to remote servers for nodes with presence based delivery
    • mod_scram_update : Don&apost hard-code iteration count
    • Bump many XEPs versions that are already supported
    • Improve documentation of install_contrib_modules ( #4487 )

    Full Changelog

    https://github.com/processone/ejabberd/compare/25.10...26.01

    ejabberd 26.01 download & feedback

    As usual, the release is tagged in the Git source code repository on GitHub .

    The source package and installers are available in ejabberd Downloads page. To check the *.asc signature files, see How to verify ProcessOne downloads integrity .

    For convenience, there are alternative download locations like the ejabberd DEB/RPM Packages Repository and the GitHub Release / Tags .

    The ecs container image is available in docker.io/ejabberd/ecs and ghcr.io/processone/ecs . The alternative ejabberd container image is available in ghcr.io/processone/ejabberd .

    If you consider that you&aposve found a bug, please search or fill a bug report on GitHub Issues .

    • chevron_right

      Ignite Realtime Blog: IgniteRealtime Heads to Brussels: XSF Summit & FOSDEM 2026

      news.movim.eu / PlanetJabber • 21 January 2026 • 1 minute

    I am excited to share that members of the IgniteRealtime community will be heading to Brussels, Belgium, from January 29th to February 1st to take part in two important events for the open-source and real-time communications ecosystem: the annual XSF Summit and FOSDEM.

    XSF Summit: Connecting the XMPP community

    The XSF Summit , organized by the XMPP Standards Foundation, brings together developers, maintainers, and contributors from across the XMPP ecosystem. IgniteRealtime community members will be there to collaborate with peers, discuss the current state and future direction of XMPP, and share insights from ongoing IgniteRealtime projects.

    These face-to-face discussions are invaluable for aligning on standards, exchanging implementation experience, and strengthening the relationships that keep open, decentralized communication thriving.

    FOSDEM: Celebrating open source at scale

    Following the XSF Summit, our community members will also attend FOSDEM (Free and Open source Software Developers’ European Meeting), one of the largest and most influential open-source conferences in the world.

    FOSDEM is a unique opportunity to:

    • Learn about the latest developments across a wide range of open-source technologies
    • Meet contributors and users from diverse projects and communities
    • Represent IgniteRealtime and real-time communication technologies within the broader open-source ecosystem

    You’ll likely find us at the XMPP & Realtime Lounge (building AW, level 1).

    Meet us in Brussels

    If you’re attending the XSF Summit, FOSDEM, or will be in Brussels during this time, we’d love to connect. These events are a great chance to meet fellow IgniteRealtime users and contributors, exchange ideas, and talk about where we’re headed next.

    We look forward to productive discussions, new connections, and bringing fresh energy and ideas back to the IgniteRealtime community. See you in Brussels! :belgium:

    For other release announcements and news follow us on Mastodon or X

    1 post - 1 participant

    Read full topic