Installing & running

Install a package or build the binaries, start the broker, and run it as a systemd service.

Packages

Each release of mercuriod, the broker, mercurioctl, its administration tool, and recado, the command-line client, has .deb and .rpm packages and a plain .tar.gz for x86_64, aarch64 and armv7 Linux. They need glibc 2.18 or later. Download the ones for your system and install them:

# Debian, Ubuntu, Raspberry Pi OS
sudo apt install ./mercuriod_*.deb ./mercurioctl_*.deb ./recado_*.deb

# Fedora, RHEL, openSUSE
sudo dnf install ./mercuriod-*.rpm ./mercurioctl-*.rpm ./recado-*.rpm

The mercuriod packages install the broker as /usr/bin/mercuriod, the sample configuration as /etc/mercurio/config.toml and the systemd unit, create a mercurio system user and group for the service, and recommend mercurioctl. Members of the group may run mercurioctl on the broker's host. The configuration can hold passwords, so only root and the group may read it (0640 root:mercurio). Edits to the configuration are kept across upgrades. The Debian package enables and starts the service. With the RPM, start it yourself:

sudo systemctl enable --now mercuriod

The service runs as mercurio, so files it reads that aren't readable by everyone, such as TLS keys and password files, must belong to that user or its group:

sudo chown root:mercurio /etc/mercurio/server.key
sudo chmod 640 /etc/mercurio/server.key

On armv7, WASM plugins run in wasmtime's interpreter, as its compiler doesn't support 32-bit ARM, so they're slower there.

Building

Mercurio needs a recent stable Rust toolchain. From the repository root:

# Broker, command-line client and libraries
cargo build --release

# Only the broker
cargo build --release --package mercuriod

# Or install the binaries into ~/.cargo/bin
cargo install --path mercuriod
cargo install --path mercurioctl
cargo install --path recado

The binaries end up in target/release/: mercuriod, the broker, mercurioctl, its administration tool, and recado, the command-line client.

Running the broker

mercuriod [OPTIONS]
mercuriod passwd -f <FILE> -u <USER> [-d]
mercuriod dynsec-init -f <FILE> [-u <USER>]
OptionMeaningDefault
-c, --config <FILE>Configuration file/etc/mercurio/config.toml
-l, --listen <ADDR>Override the main listen address, such as 0.0.0.0:1883from the configuration
-v, --verboseLog at debug level
--checkCheck the configuration and exit; see Checking a configuration

Without a file at the default path, the broker starts with the defaults: plain MQTT on 127.0.0.1:1883, no authentication, state in memory. A missing file at a path given with -c is an error.

# Defaults
mercuriod

# Custom configuration, listening on every interface
mercuriod -c ./config.toml -l 0.0.0.0:1883

# Debug logging
mercuriod -v

Subcommands

CommandWhat it does
mercuriod passwd -f FILE -u USERAdds a user to a password file, or changes their password. Prompts for the password.
mercuriod passwd -f FILE -u USER -dRemoves a user.
mercuriod dynsec-init -f FILE [-u USER]Creates a dynamic security file with an administrator, admin by default.

Signals

SignalEffect
SIGTERM, Ctrl+CGraceful shutdown: every client is sent a DISCONNECT saying the server is shutting down, and the broker waits up to five seconds for connections to close.
SIGHUPRereads password files, ACL files, the dynamic security file, the TLS certificates, keys, CAs and CRLs, and the certificate files of [auth.http], without dropping connections. See reloading. mercurioctl broker reload does the same and reports each file. Received while the broker starts, for example while a standby waits for the database, it reloads once the broker serves.

A non-zero exit status means the broker failed to start, for example on an unusable TLS certificate or a port already in use, so service managers notice.

Running as a systemd service

A unit file is provided in mercuriod/contrib/mercuriod.service; the packages install it for you. It runs the broker sandboxed as the mercurio user, with /var/lib/mercurio, which suits the SQLite database, and /var/log/mercurio, for a log file, as its only writable directories, and maps systemctl reload to SIGHUP. Files the broker creates are readable by its user only, and it may keep 65536 files open, as each client connection takes one. It also creates /run/mercurio, where the broker serves its admin socket. Without a mercurio user on the system, systemd creates a temporary one for each run.

The unit is Type=notify: the broker tells systemd it is ready once its listeners are bound and it serves, so systemctl start returns, and units ordered after mercuriod start, only then. A PostgreSQL standby becomes ready when it takes over; until then systemctl status shows it standing by, and as that may last indefinitely, the unit sets no start timeout. On systemctl stop the broker reports that it is stopping before it disconnects its clients.

# Binary, configuration and unit
sudo cp target/release/mercuriod /usr/bin/
sudo mkdir -p /etc/mercurio
sudo cp mercuriod/contrib/config.toml /etc/mercurio/
sudo cp mercuriod/contrib/mercuriod.service /etc/systemd/system/

# Start it now and at boot
sudo systemctl daemon-reload
sudo systemctl enable --now mercuriod

# Status, logs, reload
sudo systemctl status mercuriod
journalctl -u mercuriod -f
sudo systemctl reload mercuriod

The sample configuration lists every option with its default. A minimal production configuration that keeps state on disk and requires passwords:

[server]
host = "0.0.0.0"
port = 1883

[storage]
backend = "sqlite"
path = "/var/lib/mercurio/mercurio.db"

[auth]
enabled = true
allow_anonymous = false
password_file = "/etc/mercurio/passwd"
sudo mercuriod passwd -f /etc/mercurio/passwd -u alice

Next steps