From 8f28c550e70df733d56f485e0ddb530ef1dbe590 Mon Sep 17 00:00:00 2001 From: Ville Turpeinen Date: Fri, 20 Mar 2026 13:21:11 +0200 Subject: [PATCH 1/2] Fix incorrect key for HTTP modules in config The documentation currently shows the HTTPS module setting incorrectly. The correct key is `listener.https.$name$.http_modules`, not `listeners.https.$name$.http_modules` --- configuration/http-listeners.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configuration/http-listeners.md b/configuration/http-listeners.md index ffd5e71..f0faf7c 100644 --- a/configuration/http-listeners.md +++ b/configuration/http-listeners.md @@ -21,10 +21,10 @@ listener.http.default = 127.0.0.1:8888 You can have multiple HTTP(s) listener listening to different port and running different modules: ```text listener.https.default = 127.0.0.1:443 -listeners.https.default.http_modules = vmq_status_http, vmq_health_http, vmq_metrics_http +listener.https.default.http_modules = vmq_status_http, vmq_health_http, vmq_metrics_http listener.https.mgmt = 127.0.0.1:444 -listeners.https.mgmt.http_modules = vmq_mgmt_http +listener.https.mgmt.http_modules = vmq_mgmt_http ``` This configuration snippet defines two HTTPS listeners with different modules. One for default traffic and one for management traffic. It specifies which HTTP modules will be enabled on each listener, allowing for status, health, and metrics information to be retrieved from the default listener and providing a web-based interface for managing and monitoring VerneMQ through the management listener. From f9dc1bea4e1d8cdd8fe7afcaa151dc4560bd19e2 Mon Sep 17 00:00:00 2001 From: Andre Fatton Date: Wed, 12 Aug 2026 09:57:22 +0200 Subject: [PATCH 2/2] Initial documentation updates for VerneMQ release 2.2.0 --- SUMMARY.md | 1 + administration/listeners.md | 17 +++++- clustering/communication.md | 31 +++++++++- configuration/advanced_options.md | 19 +++++- configuration/listeners.md | 86 ++++++++++++++++++++++++++- configuration/options.md | 10 ++++ guides/vernemq-2.2.0.md | 55 +++++++++++++++++ monitoring/health-check.md | 10 ++++ monitoring/prometheus.md | 26 ++++++++ plugindevelopment/sessionlifecycle.md | 38 +++++++++++- plugindevelopment/webhookplugins.md | 7 ++- 11 files changed, 294 insertions(+), 6 deletions(-) create mode 100644 guides/vernemq-2.2.0.md diff --git a/SUMMARY.md b/SUMMARY.md index 2cc1c02..af3f590 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -85,3 +85,4 @@ * [Not a tuning guide](guides/not-a-tuning-guide.md) * [Change Open File Limits](guides/change-open-file-limits.md) * [Migrating to 2.0](guides/migration-to-2-0.md) +* [VerneMQ 2.2.0](guides/vernemq-2.2.0.md) diff --git a/administration/listeners.md b/administration/listeners.md index 53eb344..e7d1fd7 100644 --- a/administration/listeners.md +++ b/administration/listeners.md @@ -50,6 +50,22 @@ You can isolate client connections accepted by a certain listener from other cli To start an MQTT listener using defaults, just set the port and IP address as a minimum. +### Authentication and authorization plugin chains + +Listeners started with `vmq-admin listener start` can define their own authentication and authorization plugin chains. Use `--auth_plugins` for authentication hooks and `--authz_plugins` for authorization hooks. The configured order is preserved. + +```text +vmq-admin listener start address=192.168.1.50 port=1884 --auth_plugins=[vmq_passwd] --authz_plugins=[vmq_acl] +``` + +The same flags can be used when starting WebSocket listeners: + +```text +vmq-admin listener start address=192.168.1.50 port=8888 --websocket --auth_plugins=[vmq_webhooks,vmq_passwd] --authz_plugins=[vmq_webhooks] +``` + +If no listener-specific chain is configured, VerneMQ uses the globally enabled plugin chain. + ## Stopping a listener ```text @@ -69,4 +85,3 @@ vmq-admin listener restart address=192.168.1.50 port=1884 ```text vmq-admin listener delete address=192.168.1.50 port=1884 ``` - diff --git a/clustering/communication.md b/clustering/communication.md index 3622014..1fc6783 100644 --- a/clustering/communication.md +++ b/clustering/communication.md @@ -25,7 +25,36 @@ listener.vmq.clustering = 0.0.0.0:44053 It isn't necessary to configure the same port on every machine, as the nodes will probe each other for this information. {% endhint %} +## Internode MQTT Delivery + +VerneMQ uses MQTT connections between cluster nodes to deliver MQTT messages to subscribers on remote nodes. In most deployments, the defaults should be left unchanged. The following settings are advanced options for deployments that need to tune behavior around slow peers, short disconnects, reconnect handshakes, or unusually large bursts of internode traffic. + +`outgoing_cluster_handshake_ack_timeout` configures how long a node waits for the receiving side to acknowledge an outgoing cluster delivery connection before assuming legacy behavior. The value is in milliseconds and defaults to `250`. + +```text +outgoing_cluster_handshake_ack_timeout = 250 +``` + +`incoming_clustering_buffer_size` limits how many bytes are buffered while parsing incoming internode MQTT traffic. Malformed or oversized cluster frames are rejected instead of being buffered indefinitely. The value is in bytes and defaults to `67108864`. + +```text +incoming_clustering_buffer_size = 67108864 +``` + +`outgoing_clustering_buffer_size` configures how many bytes are buffered when a remote node is temporarily unavailable. The value is in bytes and defaults to `67108864`. + +```text +outgoing_clustering_buffer_size = 67108864 +``` + +`outgoing_clustering_flush_threshold` configures how many pending outgoing bytes are batched before VerneMQ eagerly flushes internode traffic. The value is in bytes and defaults to `65536`. + +```text +outgoing_clustering_flush_threshold = 65536 +``` + +Change these values only after testing with realistic cluster traffic. Setting buffers too low can increase dropped internode traffic during transient disconnects, while setting them too high can increase memory usage under sustained peer or network problems. + **Attributions:** This section, "VerneMQ Inter-node Communication", is a derivative of Security and Firewalls by Riak, used under Creative Commons Attribution 3.0 Unported License. - diff --git a/configuration/advanced_options.md b/configuration/advanced_options.md index cceca73..3837845 100644 --- a/configuration/advanced_options.md +++ b/configuration/advanced_options.md @@ -24,6 +24,24 @@ Specify how queues should process messages, either the `fifo` or `lifo` way, wit queue_type = fifo ``` +## Fanout Sharding + +Fanout sharding can increase throughput and lower backpressure in high-frequency publish scenarios where a topic fanout has to deliver to many subscribers. It splits local fanout work over multiple fanout shards. + +`fanout.shard_count` configures the number of local fanout shards. The default is `1`, which preserves the previous behavior. + +```text +fanout.shard_count = 8 +``` + +`fanout.async_handoff` decouples the publisher from local shard delivery work. This can further reduce publisher backpressure, but local match counts are not exact when async handoff is enabled. The default is `off`. + +```text +fanout.async_handoff = on +``` + +These settings are experimental and should be changed only after load testing with traffic patterns close to production. + ## Max Message Rate Specifies the maximum incoming publish rate per session per second. Depending on the underlying network buffers this rate isn't enforced. Defaults to `0`, which means no rate limits apply. Setting to a value of `2` limits any publisher to 2 messages per second, for instance. @@ -81,4 +99,3 @@ listener.max_connection_lifetime = 25000 ``` It is possible to override the value in auth_on_register(_m5) to a lower limit. - diff --git a/configuration/listeners.md b/configuration/listeners.md index ce557df..4f546bd 100644 --- a/configuration/listeners.md +++ b/configuration/listeners.md @@ -81,6 +81,91 @@ listener.ssl.my_listener.tls_handshake_timeout = 8000 mqtt.connect.timeout = 30000 ``` +## Active Socket Packets + +For TCP and SSL listeners, `active_n` controls how many incoming TCP packets may be delivered before the socket switches back to passive mode. The default value is `1`, which preserves the previous `{active, once}` behavior. Valid values are integers from `1` to `32767`. + +The value can be configured on the protocol level or overridden for a named listener: + +```text +listener.tcp.active_n = 10 +listener.ssl.active_n = 10 + +listener.tcp.my_listener.active_n = 100 +listener.ssl.my_listener.active_n = 100 +``` + +## Per-Listener Authentication and Authorization + +Listeners can define their own authentication and authorization plugin chains. If no per-listener chain is configured, the globally enabled plugin chain is used. The configured order is preserved. + +Configure authentication plugins with `auth_plugins` and authorization plugins with `authz_plugins`: + +```text +listener.tcp.internal = 127.0.0.1:1883 +listener.tcp.internal.auth_plugins = [vmq_passwd] +listener.tcp.internal.authz_plugins = [vmq_acl] + +listener.wss.external = 0.0.0.0:8884 +listener.wss.external.auth_plugins = [vmq_webhooks, vmq_passwd] +listener.wss.external.authz_plugins = [vmq_webhooks] +``` + +This setting is available for TCP, SSL, WebSocket, and secure WebSocket listeners: + +```text +listener.tcp.my_listener.auth_plugins = [vmq_passwd] +listener.ssl.my_listener.auth_plugins = [vmq_passwd] +listener.ws.my_listener.auth_plugins = [vmq_webhooks] +listener.wss.my_listener.auth_plugins = [vmq_webhooks] + +listener.tcp.my_listener.authz_plugins = [vmq_acl] +listener.ssl.my_listener.authz_plugins = [vmq_acl] +listener.ws.my_listener.authz_plugins = [vmq_webhooks] +listener.wss.my_listener.authz_plugins = [vmq_webhooks] +``` + +## Anonymous Access Override + +`allow_anonymous_override` allows a named listener to override a global `allow_anonymous = off` setting. Its main use case is a listener that authenticates clients outside the normal MQTT authentication plugin chain, for example with client certificates. + +The global and listener-specific values are OR'ed together. This means a listener can allow anonymous access when the global setting is `off`, but a listener cannot disable anonymous access when the global setting is `on`. + +```text +allow_anonymous = off + +listener.ssl.mtls = 0.0.0.0:8883 +listener.ssl.mtls.require_certificate = on +listener.ssl.mtls.allow_anonymous_override = on +``` + +The setting is available for TCP, SSL, WebSocket, and secure WebSocket listeners: + +```text +listener.tcp.my_listener.allow_anonymous_override = on +listener.ssl.my_listener.allow_anonymous_override = on +listener.ws.my_listener.allow_anonymous_override = on +listener.wss.my_listener.allow_anonymous_override = on +``` + +## Forward Connection Options + +`forward_connection_opts` passes listener metadata to the extended `auth_on_register` and `auth_on_register_m5` hooks. Enable it if an authentication plugin needs to make decisions based on listener information such as the transport or listener name. + +The setting can be configured on the protocol level or for a named listener: + +```text +listener.tcp.forward_connection_opts = on +listener.ssl.forward_connection_opts = on +listener.ws.forward_connection_opts = on +listener.wss.forward_connection_opts = on + +listener.tcp.my_listener.forward_connection_opts = on +listener.ssl.my_listener.forward_connection_opts = on +listener.ws.my_listener.forward_connection_opts = on +listener.wss.my_listener.forward_connection_opts = on +``` + ## SSL/TLS Support VerneMQ supports different Transport Layer Security (TLS) options, which allow for secure communication between MQTT clients and VerneMQ. @@ -152,4 +237,3 @@ With SSL, you still need to configure authentication and authorization! That is, The default listener `listener.vmq.clustering` is used for distributing MQTT messages among the cluster nodes. {% endhint %} - diff --git a/configuration/options.md b/configuration/options.md index 8d7e31f..ce3f687 100644 --- a/configuration/options.md +++ b/configuration/options.md @@ -24,6 +24,16 @@ max_inflight_messages = 20 Defaults to `20` messages, use `0` for no limit. The inflight window serves as a protection for sessions, on the incoming side. +## Subscriptions per Client + +This option defines the maximum number of subscriptions a client can have. Existing subscriptions can be replaced even after the limit is reached. + +```text +max_subscriptions_per_client = 0 +``` + +Defaults to `0`, which means no limit applies. This setting can be used as a guardrail against clients creating too many subscriptions. + ## Load Shedding The maximum number of messages to hold in the queue above those messages that are currently in flight. Defaults to `1000`. Set to `-1` for no limit. This option protects a client session from overload by dropping messages \(of any QoS\). diff --git a/guides/vernemq-2.2.0.md b/guides/vernemq-2.2.0.md new file mode 100644 index 0000000..d3f9beb --- /dev/null +++ b/guides/vernemq-2.2.0.md @@ -0,0 +1,55 @@ +# VerneMQ 2.2.0 + +VerneMQ 2.2.0 adds runtime compatibility updates, listener-level configuration improvements, performance options, and operational examples. This page summarizes the most relevant user-facing changes and links to the detailed documentation. + +## Runtime Support + +VerneMQ 2.2.0 supports running on Erlang/OTP 28 and Erlang/OTP 29. + +## Fanout Sharding + +Fanout sharding can increase throughput and lower backpressure for high-frequency publishers where local topic fanout has to deliver to many subscribers. The related advanced settings are `fanout.shard_count` and `fanout.async_handoff`. + +See [Advanced Options](../configuration/advanced_options.md#fanout-sharding). + +## Subscription Limit Guardrail + +The new `max_subscriptions_per_client` setting limits how many subscriptions a client can have. A value of `0` keeps the default unlimited behavior. + +See [MQTT Options](../configuration/options.md#subscriptions-per-client). + +## Per-Listener Auth Chains + +MQTT listeners can define their own authentication and authorization plugin chains with `auth_plugins` and `authz_plugins`. This allows different listeners to use different authentication and authorization behavior without changing the global plugin chain. + +See [MQTT Listeners](../configuration/listeners.md#per-listener-authentication-and-authorization) and [Managing Listeners](../administration/listeners.md#authentication-and-authorization-plugin-chains). + +## Forward Connection Options + +`forward_connection_opts` can pass listener metadata to `auth_on_register` and `auth_on_register_m5` hooks. Plugins can use that metadata to implement different behavior based on the listener that accepted the client connection. + +See [MQTT Listeners](../configuration/listeners.md#forward-connection-options) and [Session lifecycle](../plugindevelopment/sessionlifecycle.md#listener-metadata). + +## Listener active_n + +TCP and SSL listeners support `active_n`, which controls how many incoming TCP packets may be delivered before the socket switches back to passive mode. The default is `1`, preserving the previous behavior. + +See [MQTT Listeners](../configuration/listeners.md#active-socket-packets). + +## WebSocket Anonymous Override + +`allow_anonymous_override` is now available for WebSocket and secure WebSocket listeners as well as TCP and SSL listeners. This allows a named listener to override a global `allow_anonymous = off` setting. + +See [MQTT Listeners](../configuration/listeners.md#anonymous-access-override). + +## Cluster and Internode Robustness + +VerneMQ 2.2.0 improves internode MQTT delivery with a connect-ack handshake, bounded inbound buffering, outgoing batching, and larger default outgoing clustering buffers. These settings are advanced and should usually be left at their defaults. + +See [Inter-node Communication](../clustering/communication.md#internode-mqtt-delivery). + +## Prometheus Alert Rules Template + +VerneMQ ships with a minimal Prometheus alert rules template in `metrics_scripts/prometheus/vernemq-alert-rules.yml`. The template is intended as a starting point and should be extended or adapted to the thresholds, labels, severities, and runbooks of each deployment. + +See [Prometheus](../monitoring/prometheus.md#example-alert-rules). diff --git a/monitoring/health-check.md b/monitoring/health-check.md index 0c877b4..221ce54 100644 --- a/monitoring/health-check.md +++ b/monitoring/health-check.md @@ -16,3 +16,13 @@ In addition to the simple `/health` path, the following options are available as With the `ping` or `listeners` option, you can configure a health check for a single node, even if it is part of a cluster. If you want to configure any automated actions based on the health check results, you need to chose an appropriate health check path. For example, you should not use the `/health` check (checking for full cluster consistency) to automatically restart a single node. This is of special importance for Kubernetes deployments. + +## Cluster readiness timeout + +Cluster readiness checks use parallel RPC calls to check cluster nodes. The total timeout for this check is controlled by `cluster_ready_rpc_timeout` and defaults to `5000` milliseconds. + +```text +cluster_ready_rpc_timeout = 5000 +``` + +The timeout applies to the whole readiness check, not once per cluster node. In most deployments, the default should be left unchanged. diff --git a/monitoring/prometheus.md b/monitoring/prometheus.md index 9075028..d612757 100644 --- a/monitoring/prometheus.md +++ b/monitoring/prometheus.md @@ -25,3 +25,29 @@ This tells Prometheus to scrape the VerneMQ metrics endpoint every 5 seconds. Please follow the documentation on the [Prometheus](http://prometheus.io) website to properly configure the metrics scraping as well as how to access those metrics and configure alarms and graphs. +## Example Alert Rules + +VerneMQ ships with a minimal Prometheus alert rules template in `metrics_scripts/prometheus/vernemq-alert-rules.yml`. The template contains baseline alerts for broker availability, scheduler utilization, memory usage, queue drops, socket errors, keepalive expirations, and cluster-related signals. + +The template is intended as a starting point. Extend and adapt thresholds, severities, labels, job matchers, and runbook hints for your own deployment and use cases. + +To install the template, copy it to your Prometheus rules directory and reference it from `prometheus.yml`: + +```yaml +rule_files: + - /etc/prometheus/vernemq-alert-rules.yml +``` + +Validate the rules before reloading Prometheus: + +```text +promtool check rules /etc/prometheus/vernemq-alert-rules.yml +``` + +The example rules assume the default VerneMQ Prometheus namespace: + +```text +prometheus_namespace = vernemq_ +``` + +If you changed `prometheus_namespace`, update the metric name prefixes in the alert rules accordingly. diff --git a/plugindevelopment/sessionlifecycle.md b/plugindevelopment/sessionlifecycle.md index 6d82640..feeb080 100644 --- a/plugindevelopment/sessionlifecycle.md +++ b/plugindevelopment/sessionlifecycle.md @@ -10,6 +10,43 @@ The `auth_on_register` and `auth_on_register_m5` hooks allow your plugin to gran Every plugin that implements the `auth_on_register` or `auth_on_register_m5` hooks are part of a conditional plugin chain. For this reason we allow the hook to return different values depending on how the plugin grants or rejects this client. In case the plugin doesn't know the client it is best to return `next` as this would allow subsequent plugins in the chain to validate this client. If no plugin is able to validate the client it gets automatically rejected. +### Listener metadata + +If `forward_connection_opts` is enabled for a TCP, SSL, WebSocket, or secure WebSocket listener, VerneMQ calls the extended auth hook variant with listener metadata as the last argument. + +```text +listener.tcp.my_listener.forward_connection_opts = on +listener.ssl.my_listener.forward_connection_opts = on +listener.ws.my_listener.forward_connection_opts = on +listener.wss.my_listener.forward_connection_opts = on +``` + +For MQTT 3.x clients, implement `auth_on_register/6` instead of `auth_on_register/5`: + +```erlang +auth_on_register(Peer, SubscriberId, User, Password, CleanSession, Opts) -> + ... +``` + +For MQTT 5 clients, implement `auth_on_register_m5/7` instead of `auth_on_register_m5/6`: + +```erlang +auth_on_register_m5(Peer, SubscriberId, User, Password, CleanStart, Properties, Opts) -> + ... +``` + +`Opts` is a map containing listener information: + +```erlang +#{listener_addr := {127, 0, 0, 1}, + listener_port := 1883, + listener_type := mqtt} +``` + +The `listener_type` value is one of `mqtt`, `mqtts`, `mqttws`, or `mqttwss`. This allows an authentication plugin to choose different authentication behavior depending on the listener that accepted the connection. + +For TLS listeners with client certificates, `Opts` also includes `client_cert`, containing the peer certificate binary returned by `ssl:peercert/1`. The common name is not extracted for this option. + ## on\_auth\_m5 The `on_auth_m5` hook allows your plugin to implement MQTT enhanced authentication, see [Enhanced Authentication Flow](enhancedauthflow.md). @@ -29,4 +66,3 @@ This hook is called if an MQTT 3.1/3.1.1 client using `clean_session=false` or a ## on\_client\_gone This hook is called if an MQTT 3.1/3.1.1 client using `clean_session=true` or an MQTT 5.0 client with the `session_expiry_interval` set to zero closes the connection or gets disconnected by a duplicate client. The hook is specified in the Erlang behaviour [on\_client\_gone\_hook](https://github.com/vernemq/vernemq_dev/blob/master/src/on_client_gone_hook.erl) available in the [vernemq\_dev](https://github.com/vernemq/vernemq_dev) repo. - diff --git a/plugindevelopment/webhookplugins.md b/plugindevelopment/webhookplugins.md index 18719f1..e37c0c3 100644 --- a/plugindevelopment/webhookplugins.md +++ b/plugindevelopment/webhookplugins.md @@ -107,6 +107,12 @@ For detailed information about the hooks and when they are called, see the secti Note, when overriding a **mountpoint** or a **client-id** both have to be returned by the webhook implementation for it to have an effect. {% endhint %} +### Cancellable authentication requests + +For the `auth_on_register` and `auth_on_register_m5` hooks, VerneMQ cancels the in-flight HTTP request if the client connection closes while the webhook call is still waiting for a response. This prevents disconnected clients from leaving authentication webhook calls running until the normal response timeout is reached. + +The endpoint may still receive the HTTP request before cancellation reaches it. Authentication endpoints should therefore treat requests as idempotent and avoid relying on every request producing a completed VerneMQ authentication decision. + ### Responses All hooks, unless stated otherwise, respond with a JSON-encoded payload and a success code of 200. All hooks support responding with "ok", indicated that the request was successful. @@ -807,4 +813,3 @@ vmq_webhooks.webhook3.endpoint = http://127.0.0.1:8080 vmq_webhooks.webhook4.hook = auth_on_subscribe_m5 vmq_webhooks.webhook4.endpoint = http://127.0.0.1:8080 ``` -