I wanted a message broker for a side project without paying for managed Kafka or wrestling with RabbitMQ clustering. NATS was the obvious answer—until I tried wiring up JetStream, token auth, WebSocket for the browser, and Traefik routing on my own. So I packaged the whole thing as a Dokploy Compose template.
The Problem
Spinning up NATS sounds easy until you actually need it in production:
-
nats.confsyntax is fine, but plumbing env vars through Docker Compose takes trial and error - Browser clients need the WebSocket port exposed through a reverse proxy with TLS
- The monitoring endpoint on port 8222 is wide open by default
- Every tutorial stops at "it runs locally"—nothing covers a real self-hosted deploy
The Solution: dokploy-nats
A single Git repo you point Dokploy at. It gives you NATS 2.10 with JetStream, token auth, WebSocket, and a monitoring endpoint—all driven by environment variables, all routed through Traefik.
services:
nats:
image: nats:2.10.24-alpine
command: ["-c", "/etc/nats/nats.conf"]
volumes: [./nats.conf:/etc/nats/nats.conf:ro, nats-data:/data]
That's the core. Everything else is environment variables you set in the Dokploy UI.
How It Works
-
Dokploy clones the repo and runs
docker-compose upwith your env vars injected -
nats.confinterpolates env vars at startup—server name, auth token, JetStream limits, ports -
Traefik labels route traffic to
nats-monitor.yourdomain(HTTP dashboard) andnats-ws.yourdomain(WebSocket) - A named volume persists JetStream data so streams survive container restarts
No bash scripts, no manual nats-server flags, no hand-rolled Compose files.
Get Started in 5 Minutes
You configure:
-
NATS_AUTH_TOKEN— generate withopenssl rand -base64 32 -
NATS_JS_MAX_FILE— how much disk JetStream can use (e.g.10G) -
NATS_WS_PORT— WebSocket port behind Traefik (e.g.8080) -
Traefik domains —
nats-monitor.example.comandnats-ws.example.com
What You Get
| Feature | Port | Purpose |
|---|---|---|
| Native TCP | 4222 | Standard NATS clients (Go, Node, Python) |
| HTTP monitoring | 8222 | Health checks, connection stats, JetStream |
| WebSocket | 8080 | Browser clients, mobile apps |
| JetStream storage | — | Persistent streams, KV, object store |
Connecting from a Client
The repo includes a working Node.js example with Fastify + a worker using NATS request/reply over JetStream:
nats context save dokploy \
--server wss://nats-ws.yourdomain.com \
--token "$NATS_AUTH_TOKEN"
nats sub demo # in one terminal
nats pub demo "hello" # in another
The examples/node/ folder demonstrates the request/reply pattern between an HTTP API and background workers, streaming execution events back to the browser over WebSocket.
Why This Works
- Env vars, not hardcoded config — same image, same compose file, different deployments
- Traefik labels included — TLS and routing handled by Dokploy's built-in proxy
- JetStream out of the box — durable streams, KV store, no extra setup
-
Healthcheck baked in —
wget /healthzso Dokploy knows when to restart it - WebSocket native — browser clients work without an extra bridge
What's your go-to message broker for side projects—NATS, Redis Pub/Sub, or something heavier? I'd love to hear what's working for you.

Top comments (0)