Mercure 1.0 alpha is available. Check out the new docs
Sponsored by Les-Tilleuls.coop
DocumentationSpecificationCloudDemos
Contribute!

Installation

Pick the install method that matches how you ship the rest of your stack. They all run the same hub.

Skip the infrastructure? Mercure Cloud is the managed version: a hub provisioned in seconds, with TLS, custom domains, and SRE on call. The free tier is sized for prototyping; paid tiers start at €35/month. Same protocol as the open-source hub, so your code doesn't change if you migrate later.

The Mercure.rocks Hub is a custom build of the Caddy web server with the Mercure module. Anything Caddy can do, this binary can do too: TLS, HTTP/3, compression, reverse proxying, Prometheus metrics.

# Docker (recommended)
docker run \
    -e MERCURE_PUBLISHER_JWT_KEY='!ChangeThisMercureHubJWTSecretKey!' \
    -e MERCURE_SUBSCRIBER_JWT_KEY='!ChangeThisMercureHubJWTSecretKey!' \
    -p 80:80 -p 443:443 \
    dunglas/mercure

HTTPS is on by default. Caddy issues a Let's Encrypt certificate for the configured SERVER_NAME. To disable HTTPS (typically when running behind a reverse proxy), set SERVER_NAME=:80.

For local development, set MERCURE_EXTRA_DIRECTIVES=playground, which enables anonymous subscriptions and the debug UI:

# Docker (recommended)
docker run \
    -e MERCURE_EXTRA_DIRECTIVES=playground \
    -p 80:80 -p 443:443 \
    dunglas/mercure

The hub is then available at https://localhost, with the debug UI at https://localhost/.well-known/mercure/debug/.

The image's HEALTHCHECK queries the transport-aware /mercure/health/ready endpoint on the Caddy admin API.

Docker Compose

# compose.yaml
services:
  mercure:
    image: dunglas/mercure
    restart: unless-stopped
    environment:
      # Uncomment to disable HTTPS (use behind a reverse proxy)
      #SERVER_NAME: ':80'
      MERCURE_PUBLISHER_JWT_KEY: "!ChangeThisMercureHubJWTSecretKey!"
      MERCURE_SUBSCRIBER_JWT_KEY: "!ChangeThisMercureHubJWTSecretKey!"
      # Uncomment to run in development mode (insecure playground)
      #MERCURE_EXTRA_DIRECTIVES: playground
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - mercure_data:/data
      - mercure_config:/config

volumes:
  mercure_data:
  mercure_config:

The /data volume holds the BoltDB history; /config holds Caddy's autosaved configuration. See Docker deployment for healthchecks and rootless mode.

Kubernetes (Helm)

# Kubernetes (Helm)
helm repo add mercure https://charts.mercure.rocks
helm install my-release mercure/mercure

The chart ships SSE-appropriate defaults (terminationGracePeriodSeconds: 660, surge updates) so rolling deploys don't reconnect every client at once. See Kubernetes deployment for values, probes, and rootless setup.

Mercure hub prebuilt binary

Download an archive for your OS from the release page and extract it.

# Mercure Hub Prebuilt Binary
MERCURE_EXTRA_DIRECTIVES='playground' \
./mercure run --config Caddyfile

The hub binds to https://localhost. To run in production mode (no anonymous subscribers, no debug UI), drop the MERCURE_EXTRA_DIRECTIVES='playground' line.

macOS users: the binary is quarantined on first run. Strip the attribute once with xattr -d com.apple.quarantine ./mercure.

Windows users: Windows Defender Firewall will prompt on first start. Allow on both public and private networks. Whitelist mercure.exe if you run additional security software.

If port 80 or 443 is taken (Apache, NGINX, Skype), set SERVER_NAME=:3000 (or any free port) before starting.

Mercure on arch Linux

# Mercure on Arch Linux
yay -S mercure

Available on the AUR. Or makepkg -sri against the PKGBUILD if you don't use an AUR wrapper.

Custom Caddy build

If you need other Caddy modules in the same binary (rate limiting, OAuth, custom storage), build with xcaddy:

# Custom Caddy build
xcaddy build \
  --with github.com/dunglas/mercure/caddy

Or use the Caddy download page to assemble a build in the browser.

Embedding the Mercure hub in a Go binary

Mercure is also a Go library. See pkg.go.dev/github.com/dunglas/mercure. You'd typically reach for it when you want to ship a hub as part of a larger Go binary; for everything else the standalone server is simpler.

A hub built without a publisher key leaves the publish endpoint unauthenticated (the protocol's closed-network deployment mode): such a hub must never be reachable from untrusted networks. The Caddy module refuses this configuration unless the embedding application opts in with AllowNoPublish.

Verify the Mercure hub installation

# Verify the Mercure Hub Installation
curl -i https://localhost/.well-known/mercure

You should see 405 Method Not Allowed: the hub only accepts GET (subscribe) and POST (publish) on this endpoint. Anything else means the hub answered.

Mercure installation next steps

  • Quickstart: first subscribe, first publish.

  • Configuration: directives and environment variables.

  • Authorization: minting JWTs that actually pass validation.