Skip to the text

Field notes

XMPP for field crews when the network fails

Jabber and XMPP as the fallback messaging layer for field crews: presence, stanzas, self-hosted servers and what survives a weak link.

A field crew that loses its usual chat service still needs to move short text between members, and the fallback that has held up longest is the open messaging protocol known as Jabber, now XMPP. It runs over a single TCP stream, tolerates high latency better than most modern clients assume, and can be self-hosted on a small server that the crew controls. The rest of this article covers what the protocol actually does, how presence works, and where a self-hosted deployment tends to break.

What the protocol does with a connection

XMPP is a streaming XML protocol. A client opens a TCP connection to a server, negotiates TLS, authenticates, then binds a resource to a bare JID. From that point the connection carries three stanza types: `message`, `presence` and `iq`. Everything else in the protocol is built on those three.

The `message` stanza is fire-and-forget. It carries a body, a subject, a thread identifier and a type attribute (`chat`, `groupchat`, `headline`, `normal`, `error`). There is no delivery guarantee at the protocol level, which matters in the field: a message sent while the link is down is either stored server-side for later delivery or lost, depending on the server configuration and the client's use of message archives.

The `iq` stanza is a request and response pair. It carries a unique `id`, a `type` of `get`, `set`, `result` or `error`, and a payload namespace. Service discovery, roster retrieval, version queries and in-band registration all ride on `iq`. If an `iq` gets no reply within the client's timeout, the client is expected to treat the request as failed rather than retry indefinitely.

The `presence` stanza is the one field crews notice most. It broadcasts availability, and it is also the mechanism by which roster subscriptions are established. A reader who wants the full picture of how these three stanzas fit together, including JID construction and subscription states, will find the protocol walkthrough at open messaging with XMPP useful as a reference while configuring a client.

How does presence work across a roster?

Presence is not a status string. It is a subscription relationship. A JID appears in your roster only after a subscription handshake: you send a `subscribe` presence to the contact, the contact's server routes it, the contact approves, and both sides then exchange `presence` stanzas with a `type` of `available` or `unavailable`.

The subscription states are `none`, `to`, `from` and `both`. A roster entry with `to` means you receive that contact's presence but they do not receive yours. `both` is the usual state for a working pair. The distinction matters when a crew wants to publish its own availability to a dispatcher without exposing the dispatcher's status to every member.

Presence also carries a priority value from -128 to 127. When the same bare JID is connected from several resources, the server routes incoming messages to the resource with the highest priority, or to all resources with a non-negative priority if the client requests it. A phone at the edge of coverage and a laptop at the base station can therefore share one JID, with the laptop taking priority when it is online.

Directed presence is the less obvious part. A client can send `presence` with a `to` attribute to a specific JID without adding that JID to its roster. The recipient sees the presence, but the sender does not appear in the recipient's roster. This is how a crew can announce itself to a coordination account for the duration of a job and then send `unavailable` when the job ends.

What a self-hosted server has to get right

Three server implementations cover most self-hosted deployments: ejabberd, Prosody and Openfire. All three handle the core protocol, and the differences show up in configuration surface, resource use and extension support.

Prosody is written in Lua and is the lightest of the three to run on a small VPS. Its configuration file is short, and TLS certificates are declared per virtual host. ejabberd is written in Erlang, handles large numbers of concurrent connections well, and exposes a management API that is useful when a crew wants to provision accounts from a script. Openfire is Java-based and ships with an administrative web interface, which reduces the amount of command-line work during initial setup.

Two things break self-hosted XMPP more often than anything else. The first is DNS. A server needs either an A record for the domain in the JID or an SRV record at `_xmpp-client._tcp` pointing to the real host and port. A missing or stale SRV record produces connection failures that look like authentication problems. The second is TLS. Certificates must match the domain in the JID, not the hostname of the machine, and clients that require a valid chain will refuse a self-signed certificate unless it is installed on the device.

A third, quieter problem is federation. A self-hosted server can talk to the public XMPP network, but only if its DNS, TLS and server-to-server ports are reachable. A crew that only needs internal messaging can disable server-to-server entirely and keep the deployment closed.

Which client fits a field device?

Client choice on mobile is constrained by battery, background execution and the operating system's treatment of long-lived sockets. On Android, Conversations and Monocles Chat both implement OMEMO and handle reconnects after the radio drops. On iOS, the options are fewer and background delivery depends on push notifications routed through the server, which means a self-hosted deployment needs a push component or the client will not wake reliably.

On a laptop, Gajim and Dino are the common choices. Gajim has the broader plugin set and a roster that handles large contact lists; Dino is smaller and uses GTK, which suits a minimal field machine. Both support OMEMO, the double-ratchet encryption scheme used for end-to-end encrypted XMPP messaging.

For a crew, the practical test is not feature count. It is whether the client reconnects without user action after a network transition, whether it queues outgoing messages while offline, and whether it can be configured once and then left alone. A client that requires a manual reconnect after every tunnel is worse than no client at all.

What the standards history explains

The protocol began as Jabber in 1999, with the original `jabberd` server. The IETF published the core specifications as RFC 3920 and RFC 3921 in 2004, and the revised versions, RFC 6120 and RFC 6121, in 2011. The name Jabber remained with the original company while the protocol itself became XMPP, which is why both terms appear in documentation and why the distinction is not a matter of version.

Extensions live in the XEP series, managed through the XMPP Standards Foundation. A XEP moves through states from Experimental to Draft to Final, and a client or server advertises support through service discovery rather than a version number. Multi-user chat is XEP-0045; the newer MIX work is XEP-0369. Encryption with OMEMO is XEP-0384.

The historical record matters for one practical reason. Documentation written before 2004 describes a protocol that no longer matches the RFCs, and configuration advice from that period often assumes ports and authentication flows that current servers reject. When a setting does not work, checking whether the source predates RFC 6120 is a fast way to decide whether to keep reading.

Where the fallback actually helps

The case for XMPP in a field kit is not that it is faster or richer than the alternatives. It is that the protocol is small, documented in public RFCs, and implementable on a server the crew controls. A single small VPS with Prosody, a valid certificate and correct SRV records will carry text between a handful of devices over a link that would defeat a heavier client.

A ruggedized laptop open on the tailgate of a pickup at dusk, its screen showing a contact roster, with a handheld radio and a folded paper map beside it under the truck's dome light.
A ruggedized laptop open on the tailgate of a pickup at dusk, its screen showing a contact roster, with a handheld radio and a folded paper map beside it under the truck's dome light.

What it will not do is compensate for a link that is down. Presence stops updating, messages queue or fail, and the roster shows stale states until the connection returns. The value is in the recovery: when the link comes back, the client reconnects, re-sends presence, and the crew sees who is reachable again without anyone re-establishing a session by hand. The same question is worked through in live video signal chain.