Activity Publishing
Vexillum can publish a live activity feed from your reflector. The feed says which instances are running, who is connected, and which calls start and end. It can go to two kinds of destination:
- the VexDV public directory, which lists reflectors and their live activity on activity.vexdv.io;
- your own MQTT 5 broker, if you want the feed for your own dashboards, bots, logging, or anything else, with or without the public directory.
You can use either, both, or neither.
What the feed contains
Section titled “What the feed contains”The feed has two kinds of message:
- Events, as they happen: an instance starting or stopping, a client or peer connecting or disconnecting, a call starting or ending.
- State documents, retained on the broker and re-sent about once a minute. They give the complete current picture, so a newcomer doesn’t have to replay history.
It covers:
- your installation’s name, status (online or offline), software version, and running instances;
- for each instance: its state, connected callsigns, active calls, and bridges. Only designated bridges are reported as bridges, and their calls are marked with the bridge’s label. When a bridge relays a call between two instances on this server, the relayed call also names the call it came from and the first call of the chain, so every leg of one transmission can be grouped. An undesignated bridge looks like an ordinary client;
- each instance’s descriptor, meaning how to connect to it. This includes its display
name, description, protocol, modules or talkgroup, public endpoints, and whether a VAFM
passphrase is required. It comes from settings you already have: the reflector callsign
(M17, D-Star), YSF room name and description, DMR name and talkgroup, the NXDN or P25
talkgroup (shown as a name like
TG 31665), and each mode’s public endpoint.
Never published, anywhere: client IP addresses or ports, listen or bind addresses, passwords and passphrases, file paths, internal error messages, and DMR GPS position or talker alias.
Profiles
Section titled “Profiles”Each destination publishes one of two profiles:
| Private profile | Public profile | |
|---|---|---|
| Used by | your own brokers (the default) | the VexDV public directory, and any of your own brokers you set to profile = "public" |
| Instances | all of them | only instances you advertise (see below) |
| Endpoints | all configured public endpoints | endpoints with private, loopback, or link-local addresses removed |
| Extra detail | yes (for example transport, repeater and software IDs, per-call source IDs, frame counts) | no |
Your installation ID
Section titled “Your installation ID”Every Vexillum installation that publishes has a permanent installation ID, a UUID. It identifies your reflector in every feed, and in the public directory it is what your publishing certificate is issued for.
It is created the first time you enable any destination, and stored in Vexillum’s database. To see it:
Choosing what is public
Section titled “Choosing what is public”Before enabling the public directory, decide which instances should appear in it. In the admin interface, open Publishing:
- Public Advertising lists every instance with an Advertised switch. Everything is off by default, and only advertised instances reach the public directory.
- The Public Endpoints column shows exactly which connection addresses would be published for each instance. Endpoints with private, loopback, or link-local addresses are withheld automatically and shown as withheld.
Set each instance’s public endpoint in its configuration (on the instance’s page in the admin interface). This is the address users should connect to, as a hostname or public IP and port:
| Mode | Setting |
|---|---|
| M17, DMR, YSF, NXDN, P25 | public_endpoint |
| D-Star (DExtra) | dextra_public_endpoint |
| VAFM | udp_public_endpoint, tcp_public_endpoint, tls_public_endpoint, dtls_public_endpoint, ws_public_endpoint, wss_public_endpoint (one per transport you run) |
An instance without a public endpoint can still be advertised. It then appears with its activity but no connection details.
Publishing to the VexDV public directory
Section titled “Publishing to the VexDV public directory”The public directory authenticates each reflector with its own TLS client certificate. Vexillum generates the private key on your server, and the key never leaves it. To get the first certificate, you file an enrollment request from your server and confirm your email address; a directory administrator checks your callsign and approves it, and Vexillum then installs the certificate by itself. After that, Vexillum renews the certificate on its own.
1. Enable it
Section titled “1. Enable it”Add to vexillum.toml, then restart Vexillum:
display_name is how your installation is labelled in the directory; it can be up to 64
characters. Without it, the directory uses runtime.name. Set it if your runtime name is
something you’d rather keep internal.
Vexillum finds the directory’s servers by itself. Until you enroll, it waits and says so, both in the log and on the Publishing page:
2. Request enrollment
Section titled “2. Request enrollment”Run this as the account Vexillum runs as, so the service can read what it writes. Use your own callsign and an email address you can read now:
The directory administrators use the callsign and email to check that the request comes from a licensed amateur, typically against your QRZ or HamQTH listing. Using the address shown there makes approval quicker.
3. Verify your email
Section titled “3. Verify your email”The email, from [email protected], has an 8-character verification code, valid for 24
hours. Check that its key fingerprint matches the one request printed, then run:
The code is typed as shown, but case, spaces and hyphens don’t matter. It only works on the server that filed the request. Five wrong codes cancel the request; file a new one.
4. Wait for approval
Section titled “4. Wait for approval”There’s nothing more to do. An administrator reviews the request, usually within a day or two, and emails you the decision. Once it is approved, Vexillum (checking about every 10 minutes) installs the certificate and connects; the public row on the Publishing page turns healthy, and your advertised instances appear on activity.vexdv.io. Until then, the Publishing page shows where the request stands.
To see it yourself, or to install an approved certificate straight away:
If the request is rejected, the email and publisher status give the reason. Correct the
details and run publisher request again.
Enrolling with a code instead
Section titled “Enrolling with a code instead”The directory administrators can also give you a one-time enrollment code, for
example if you can’t receive email at the address you’d like to use. Email your
installation ID (vexillum publisher id), callsign and reflector name to
, then:
Paste the code when prompted and press Enter. You can also pipe it in, or use
-code-file with a file only you can read. The command never accepts the code as an
argument, so it doesn’t end up in your shell history or the process list. Vexillum never
stores it.
Renewal
Section titled “Renewal”Certificates are valid for 90 days. While Vexillum runs, it renews automatically about 30 days before expiry (with some random spread), then switches to the new certificate without dropping out. There’s nothing to schedule.
To renew immediately, for example before a long maintenance window:
If Vexillum is switched off for so long that the certificate expires, renewal is no longer
possible. Enroll again with publisher request -replace (see below).
Where the credential lives
Section titled “Where the credential lives”By default the credential is stored in a publisher directory next to Vexillum’s
database. To keep it elsewhere, such as /var/lib/vexillum/publisher, set:
- Only the Vexillum service account should be able to read it. Vexillum creates it with
mode
0700, and the private key0600. It refuses to use a key that other users can read. - Back it up with the database. The credential belongs to that database’s installation ID. It’s no use to any other installation.
- Don’t run two servers with the same credential. The directory allows one connection per installation, so two copies keep disconnecting each other.
Old credentials are kept for a week after they expire, then cleaned up automatically.
Stopping, and starting again
Section titled “Stopping, and starting again”- To stop publishing an instance, switch its Advertised toggle off.
- To stop publishing altogether, set
[activity.public] enabled = falseand restart. The directory then shows your reflector as offline. - To leave the directory for good, ask the directory administrators to remove your installation.
If your certificate is lost, has expired, or has been revoked (for example after a server
compromise), Vexillum logs that the broker refused it, and renewal fails with
credential_revoked or credential_expired. Enroll again:
then verify the emailed code as in step 3. A running Vexillum installs the new certificate once it is approved and reconnects on its own.
Publishing to your own MQTT broker
Section titled “Publishing to your own MQTT broker”To send the feed somewhere of your own, add one [[activity.mqtt]] block per broker. Any
MQTT 5 broker works (Mosquitto, EMQX, HiveMQ, and others).
Restart Vexillum after changing it. Brokers are independent: one being down doesn’t
affect the others or the public directory. While a broker is unreachable, messages queue,
bounded by queue_max_items and queue_max_age. The latest state is re-sent in full when
it comes back.
Topics
Section titled “Topics”For a prefix of vexillum, everything is under
vexillum/v1/<installation_id>/:
| Topic | Contents | Retained |
|---|---|---|
…/events |
every event, as it happens | no |
…/state |
installation state: status, version, list of instances | yes |
…/state/<mode>.<instance> |
one instance’s state, e.g. …/state/m17.main |
yes |
…/status |
online / offline. Also the MQTT last will, so it reads offline if Vexillum disappears |
yes |
All messages are JSON, with QoS 1. Each carries a schema version, which is 1. New
fields can appear in later releases, so consumers should ignore fields they don’t
recognize. When an instance is deleted, or stops being published, its retained state is
cleared with an empty message.
Broker permissions
Section titled “Broker permissions”Vexillum only publishes; it never subscribes. It needs publish permission on
<prefix>/v1/<installation_id>/# and nothing else. For example, in Mosquitto:
Your consumers, such as a dashboard, a bot, or a logger, subscribe to
vexillum/v1/+/#, or to a single installation’s tree.
Private or public profile?
Section titled “Private or public profile?”Leave profile = "private" for your own tools: you get every instance and all the detail.
Use profile = "public" for a broker whose feed you share with others. It then carries
exactly what the public directory would get, and only for advertised instances.
Checking the feed locally
Section titled “Checking the feed locally”To watch activity without any broker, set:
Every event is then written to Vexillum’s log.
Monitoring
Section titled “Monitoring”The Publishing page shows one row per destination. The public directory appears as
public. Each row shows:
- Status: healthy, or failing;
- Queued, Sent, Errors, Rejected, Dropped: the delivery counters;
- Last Error: the most recent problem, and when it happened.
The same information goes to Vexillum’s log.
Troubleshooting
Section titled “Troubleshooting”| You see | Meaning | What to do |
|---|---|---|
the public service requires enrollment |
Public directory enabled, not enrolled yet | Request enrollment |
enrollment request … is waiting for email verification |
The request was filed but not verified | Run publisher verify with the emailed code; check spam; or file a new request |
enrollment request … is waiting for approval |
Verified; an administrator hasn’t decided yet | Wait for the decision email |
enrollment request … was rejected: … |
An administrator turned it down, for the reason given | Correct the details and file a new request |
enrollment request … is expired, or verification failed |
The code lapsed after 24 hours, the decision after 30 days, or five wrong codes were entered | File a new request |
HTTP 409, request_in_review |
This installation already has a request waiting for a decision | Wait for it; to change its details, ask the administrators to reject it |
HTTP 401, invalid_verification_code |
The code was mistyped (the message says how many tries remain) | Copy it again from the newest email |
HTTP 400, bad_request: callsign … or email … |
The callsign or email address isn’t valid | Use your plain callsign (portable forms like VE3/N0CALL are fine) and a plain address |
the service does not take enrollment requests |
The directory only accepts enrollment codes | Enroll with a code |
publisher credential … is unusable: … is accessible to other users |
The private key’s permissions were loosened | chmod 600 the key, or re-enroll |
publisher credential … is unusable: certificate is for "…", not this installation |
The credential belongs to a different database’s installation ID | Restore the matching database, or re-enroll |
certificate expired … re-enroll |
Vexillum was off past the certificate’s expiry | publisher request -replace |
remote error: tls: revoked certificate |
The directory has revoked this credential | publisher request -replace |
refused by the enrollment service (HTTP 401, invalid_enrollment) |
The enrollment code is wrong, already used, expired, or for another installation ID | Check publisher id; ask for a new code, or use publisher request |
already enrolled |
A working credential is already installed | Nothing to do, or -replace to enroll again on purpose |
A private broker shows failing |
The broker is unreachable, or refused the login | Check url, credentials, TLS settings, and the broker’s log |
Rejected keeps rising |
The broker refuses messages, often a missing publish permission | Check the broker’s ACL for <prefix>/v1/<installation_id>/# |
| An instance is missing from the public directory | It isn’t advertised | Switch Advertised on under Publishing |
| An endpoint shows as withheld | It is a private, loopback, or link-local address | Set a public hostname or IP as the instance’s public endpoint |
Current status
Section titled “Current status”Activity publishing is new. The feed format is versioned (v1 in topics, schema: 1 in
messages), and later releases only add fields within a version. Check the release notes
when upgrading.