Mercure.rocksSponsored by Les-Tilleuls.coop
Contribute!

Configuration

The Mercure.rocks hub is a custom build of the Caddy web server including the Mercure.rocks module.

Read Caddy web server's getting started guide to learn the basics.

While all supported ways to configure Caddy are also supported by the Mercure.rocks Hub, the easiest method is to use a Caddyfile. A default Caddyfile is provided in the archive containing the Mercure.rocks Hub.

A minimal Caddyfile for the Mercure hub looks like this:

# The address of your server
localhost {
	mercure {
		# Publisher JWT key
		publisher_jwt !ChangeThisMercureHubJWTSecretKey!
		# Subscriber JWT key
		subscriber_jwt !ChangeThisMercureHubJWTSecretKey!
	}

	respond "Not Found" 404
}

Caddy will automatically generate a Let's Encrypt TLS certificate for you, so you can use HTTPS by default. To disable HTTPS, prefix the server name with http://:

http://my-domain.test:3000 {
    # ...
}

Note that HTTPS is automatically disabled if you set the server port to 80.

Directives

The following Mercure-specific directives are available:

DirectiveDescriptionDefault
publisher_jwt <key> [<algorithm>]the JWT key and algorithm to use for publishers, can contain placeholders
subscriber_jwt <key> [<algorithm>]the JWT key and algorithm to use for subscribers, can contain placeholders
publisher_jwks_urlthe URL of the JSON Web Key Set (JWK Set) URL (provided by identity providers such as Keycloak or AWS Cognito) to use for validating publishers JWT (take precedence over publisher_jwt)
subscriber_jwks_urlthe URL of the JSON Web Key Set (JWK Set) URL to use for validating subscribers JWT (take precedence over subscriber_jwt)
anonymousallow subscribers with no valid JWT to connectfalse
publish_origins <origins...>a list of origins allowed publishing, can be * for all (only applicable when using cookie-based auth)
cors_origins <origin...>a list of allowed CORS origins, (troubleshoot CORS issues)
cookie_name <name>the name of the cookie to use for the authorization mechanismmercureAuthorization
subscriptionsexpose the subscription web API and dispatch private updates when a subscription between the Hub and a subscriber is established or closed. The topic follows the template /.well-known/mercure/subscriptions/{topicSelector}/{subscriberID}
heartbeatinterval between heartbeats (useful with some proxies, and old browsers), set to 0s disable40s
transport <name> [{ <options...> }]The transport to use. Options are transport-specific. See also the cluster modebolt://mercure.db
dispatch_timeout <duration>maximum duration of the dispatch of a single update, set to 0s disable5s
write_timeout <duration>maximum duration before closing the connection, set to 0s disable600s
protocol_version_compatibilityversion of the protocol to be backward compatible with (only version 7 is supported)disabled
demoenable the UI and expose demo endpoints
uienable the UI but do not expose demo endpoints
topic_selector_cache <maxEntriesPerShard> [<shardCount>]Topic Selector cache configuration (pass -1 to disable the cache, and 0 for an unlimited number of entries)10000 256
subscriber_list_cache_size <maxSize>Subscriber list cache size, pass 0 for unlimited100000
transport_url <url>Deprecated: use transport instead. URL representation of the transport to use. Use local://local to disable the history, (example bolt:///var/run/mercure.db?size=100&cleanup_frequency=0.4), see also the cluster modebolt://mercure.db

See also the list of built-in Caddyfile directives.

Environment Variables

The provided Caddyfile and Docker image offer convenient environment variables:

Environment variableDescriptionDefault value
GLOBAL_OPTIONSthe global options block to inject in the Caddyfile, one per line
CADDY_EXTRA_CONFIGthe snippet or the named-routes options block to inject in the Caddyfile, one per line
CADDY_SERVER_EXTRA_DIRECTIVESCaddyfile directives
SERVER_NAMEthe server name or addresslocalhost
MERCURE_PUBLISHER_JWT_KEYthe JWT key to use for publishers
MERCURE_PUBLISHER_JWT_ALGthe JWT algorithm to use for publishersHS256
MERCURE_SUBSCRIBER_JWT_KEYthe JWT key to use for subscribers
MERCURE_SUBSCRIBER_JWT_ALGthe JWT algorithm to use for subscribersHS256
MERCURE_EXTRA_DIRECTIVESa list of extra Mercure directives inject in the Caddy file, one per line
MERCURE_LICENSEthe license to use (only applicable for the Enterprise version)

Health Check

The Mercure.rocks Hub provides transport-aware health check endpoints through the Caddy admin API (port 2019 by default):

EndpointDescription
GET /mercure/health/readyReturns 200 if all transports can serve traffic, 503 otherwise. Suitable for readiness probes.
GET /mercure/health/liveReturns 200 if all transports are fundamentally operational, 503 if any has been unhealthy for an extended period. Suitable for liveness probes.
GET /mercure/health/{name}/readyPer-hub readiness check (when using multiple hubs).
GET /mercure/health/{name}/livePer-hub liveness check (when using multiple hubs).

For transports that do not support health checking (e.g. Bolt, Local), the endpoints always return 200.

These endpoints are exposed on the admin API port, not the main HTTP port. The Caddy admin API binds to localhost:2019 by default for security, so Kubernetes probes should run from inside the container using exec:

readinessProbe:
  exec:
    command:
      ["wget", "-q", "--spider", "http://localhost:2019/mercure/health/ready"]
livenessProbe:
  exec:
    command:
      ["wget", "-q", "--spider", "http://localhost:2019/mercure/health/live"]

Alternatively, you can bind the admin API to all interfaces by adding admin 0.0.0.0:2019 to the Caddyfile's global options, and then use httpGet probes — but that exposes the admin API (including /stop and /load) on the pod network.

Here is an example of how to use the health check in a Docker Compose file:

# compose.yaml
services:
  mercure:
    # ...
    healthcheck:
      test:
        [
          "CMD",
          "wget",
          "-q",
          "--spider",
          "http://localhost:2019/mercure/health/ready",
        ]
      timeout: 5s
      retries: 5
      start_period: 60s

Note: The legacy /healthz endpoint on the main HTTP port is deprecated. It only checks that the Caddy process is running, not the transport connection status.

JWT Verification

JWTs can be validated using HMAC and RSA algorithms. In addition, it's possible to use JSON Web Key Sets (JWK Sets)—usually provided by OAuth and OIDC providers such as Keycloak or Amazon Cognito—to validate the keys.

When using RSA public keys for verification, ensure the key is properly formatted and set the correct algorithm as the second parameter of the publisher_jwt or subscriber_jwt directives (for example, RS256).

Here is an example of how to use environment variables with an RSA public key.

Generate keys (if you don't already have them):

ssh-keygen -t rsa -b 4096 -m PEM -f publisher.key
openssl rsa -in publisher.key -pubout -outform PEM -out publisher.key.pub

ssh-keygen -t rsa -b 4096 -m PEM -f subscriber.key
openssl rsa -in subscriber.key -pubout -outform PEM -out subscriber.key.pub

Start the hub:

MERCURE_PUBLISHER_JWT_KEY=$(cat publisher.key.pub) \
MERCURE_PUBLISHER_JWT_ALG=RS256 \
MERCURE_SUBSCRIBER_JWT_KEY=$(cat subscriber.key.pub) \
MERCURE_SUBSCRIBER_JWT_ALG=RS256 \
./mercure run

Bolt Adapter

localhost {
	mercure {
		transport bolt {
			path /data/mercure.db
		}
		...
	}
}
OptionDescription
pathpath of the database file (default: mercure.db)
bucket_namename of the bolt bucket to store events (default: updates)
cleanup_frequencychances to trigger history cleanup when an update occurs, must be a number between 0 (never cleanup) and 1 (cleanup after every publication, default to 0.3)
sizesize of the history (to retrieve lost messages using the Last-Event-ID header), set to 0 to never remove old events (default)

You can visualize and edit the content of the database using boltdbweb.

Legacy URL

This feature is deprecated: use the new transport directive instead.

The Data Source Name (DSN) specifies the path to the bolt database as well as options. All options available as directive except path can be passed.

Below are common examples of valid DSNs showing a combination of available values:

# absolute path to `updates.db`
transport_url bolt:///var/run/database.db

# path to `updates.db` in the current directory
transport_url bolt://database.db

# custom options
transport_url bolt://database.db?bucket_name=demo&size=1000&cleanup_frequency=0.5

Legacy Server

The legacy server is deprecated and will be removed in the next version. Consider upgrading to the Caddy-based build.

The legacy Mercure.rocks Hub is configurable using environment variables (recommended in production, twelve-factor app methodology), command-line flags and configuration files (JSON, TOML, YAML, HCL, envfile and Java properties files are supported).

Environment variables must be the name of the configuration parameter in uppercase. Run ./mercure -h to see all available command-line flags.

Configuration files must be named mercure.<format> (ex: mercure.yaml) and stored in one of the following directories:

  • the current directory ($PWD)

  • ~/.config/mercure/ (or any other XDG configuration directory set with the XDG_CONFIG_HOME environment variable)

  • /etc/mercure

Most configuration parameters are hot-reloaded: changes made to environment variables or configuration files are immediately taken into account, without having to restart the hub.

When using environment variables, lists must be space-separated. As flag parameters, they must be comma-separated.

ParameterDescriptionDefault
acme_cert_dirthe directory where to store Let's Encrypt certificates
acme_hostsa list of hosts for which Let's Encrypt certificates must be issued
acme_http01_addrthe address used by the acme server to listen on (example: 0.0.0.0:8080):http
addrthe address to listen on (example: 127.0.0.1:3000. Note that Let's Encrypt only supports the default port: to use Let's Encrypt, do not set this parameter.:http or :https depending if HTTPS is enabled or not
allow_anonymousallow subscribers with no valid JWT to connectfalse
cert_filea cert file (to use a custom certificate)
key_filea key file (to use a custom certificate)
compressUse HTTP compressionfalse
cors_allowed_originsa space-separated list of allowed CORS origins, can be * for all
debugdebug mode, dangerous, don't enable in production (logs updates' content, why an update is not send to a specific subscriber and recovery stack traces)false
demodemo mode (automatically enabled when debug is true) and enables ui at https://example.com/.well-known/mercure/ui/false
dispatch_timeoutmaximum duration of the dispatch of a single update, set to 0s to disable5s
subscriptionsexpose the subscription web API and dispatch private updates when a subscription between the Hub and a subscriber is established or closed. The topic follows the template /.well-known/mercure/subscriptions/{topicSelector}/{subscriberID}false
heartbeat_intervalinterval between heartbeats (useful with some proxies, and old browsers), set to 0s to disable40s
jwt_keythe JWT key to use for both publishers and subscribers
jwt_algorithmthe JWT verification algorithm to use for both publishers and subscribers, e.g. HS256 or RS512HS256
metrics_enabledEnable the /metrics HTTP endpoint. Provide metrics for Hub monitoring in the OpenMetrics (Prometheus) formatfalse
metrics_addrthe address to listen on127.0.0.1:9764
publish_allowed_originsa list of origins allowed to publish (only applicable when using cookie-based auth)
publisher_jwt_keymust contain the secret key to valid publishers' JWT, can be omitted if jwt_key is set
publisher_jwt_algorithmthe JWT verification algorithm to use for publishers, e.g. HS256 or RS512HS256
read_timeoutmaximum duration for reading the entire request, including the body, set to 0s to disable5s
read_header_timeoutthe amount of time allowed to read request headers, set to 0s to disable5s
subscriber_jwt_keymust contain the secret key to valid subscribers' JWT, can be omitted if jwt_key is set
subscriber_jwt_algorithmthe JWT verification algorithm to use for subscribers, e.g. HS256 or RS512HS256
transport_urlURL representation of the history database. Provided database are null to disable history, bolt to use bbolt (example bolt:///var/run/mercure.db?size=100&cleanup_frequency=0.4)bolt://updates.db
use_forwarded_headersuse the X-Forwarded-For, and X-Real-IP for the remote (client) IP address, X-Forwarded-Proto or X-Forwarded-Scheme for the scheme (http or https), X-Forwarded-Host for the host and the RFC 7239 Forwarded header, which may include both client IPs and schemes. If this option is enabled, the reverse proxy must override or remove these headers or you will be at riskfalse
write_timeoutmaximum duration before closing the connection, set to 0s to disable600s

If acme_hosts or both cert_file and key_file are provided, an HTTPS server supporting HTTP/2 connections will be started. If not, an HTTP server will be started (not secure).