Docker Compose Quick Start

The easiest way to try Waterstream locally is with Docker Compose. This sets up a complete stack — Kafka, Waterstream, and a Kafka web UI — with a single command, with no need to install Confluent Platform or any other dependencies.

Prerequisites

  • Docker with the Compose plugin (v2 or newer).

  • A Waterstream license file (optional) — without one, Waterstream runs in development mode, limited to 1 node and 20 concurrent clients. To remove these limits, request a free development license and place it in the same directory as waterstream.license.

Stack overview

The docker-compose.yml below starts four services:

Service

Purpose

kafka

Apache Kafka in KRaft mode (no ZooKeeper required)

kafka-init

Short-lived container that creates the required Waterstream topics, then exits

waterstream

The Waterstream MQTT broker, listening on port 1883

kafka-ui

Kafka UI web interface on port 8080

Start the stack

  1. Copy the docker-compose.yml below into an empty directory.

  2. (Optional) Place your Waterstream license file in the same directory as waterstream.license.

  3. Run:

    docker compose up
    

Once the stack is ready you should see Waterstream log MQTT server started — the broker is then reachable at localhost:1883. Open http://localhost:8080 to explore topics and messages in Kafka UI.

To stop the stack press Ctrl+C, or run docker compose down to also remove the containers.

docker-compose.yml

services:
  kafka:
    image: apache/kafka:4.2.0
    environment:
      KAFKA_NODE_ID: "1"
      KAFKA_PROCESS_ROLES: "broker,controller"
      KAFKA_LISTENERS: "PLAINTEXT://:9092,CONTROLLER://:9093"
      KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://kafka:9092"
      KAFKA_CONTROLLER_LISTENER_NAMES: "CONTROLLER"
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: "CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT"
      KAFKA_CONTROLLER_QUORUM_VOTERS: "1@kafka:9093"
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: "1"
      CLUSTER_ID: "MkU3OEVBNTcwNTJENDM2Qk"
    healthcheck:
      test: ["CMD-SHELL", "/opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --list"]
      interval: 10s
      timeout: 5s
      retries: 10

  kafka-init:
    image: apache/kafka:4.2.0
    depends_on:
      kafka:
        condition: service_healthy
    entrypoint: ["/bin/bash", "-c"]
    command:
      - |
        /opt/kafka/bin/kafka-topics.sh --bootstrap-server kafka:9092 --create --if-not-exists \
          --topic mqtt_sessions --partitions 5 --replication-factor 1 \
          --config cleanup.policy=compact \
          --config min.compaction.lag.ms=60000 --config delete.retention.ms=600000 &&
        /opt/kafka/bin/kafka-topics.sh --bootstrap-server kafka:9092 --create --if-not-exists \
          --topic mqtt_retained_messages --partitions 5 --replication-factor 1 \
          --config cleanup.policy=compact \
          --config min.compaction.lag.ms=60000 --config delete.retention.ms=600000 &&
        /opt/kafka/bin/kafka-topics.sh --bootstrap-server kafka:9092 --create --if-not-exists \
          --topic mqtt_connections --partitions 5 --replication-factor 1 \
          --config cleanup.policy=delete --config retention.ms=600000 &&
        /opt/kafka/bin/kafka-topics.sh --bootstrap-server kafka:9092 --create --if-not-exists \
          --topic mqtt_messages --partitions 5 --replication-factor 1 \
          --config retention.ms=86400000 &&
        /opt/kafka/bin/kafka-topics.sh --bootstrap-server kafka:9092 --create --if-not-exists \
          --topic __waterstream_heartbeat --partitions 5 --replication-factor 1 \
          --config retention.ms=300000

  waterstream:
    image: waterstreamio/waterstream-kafka:1.6.0
    depends_on:
      kafka-init:
        condition: service_completed_successfully
    environment:
      KAFKA_BOOTSTRAP_SERVERS: "PLAINTEXT://kafka:9092"
      MQTT_PORT: "1883"
      KAFKA_SESSIONS_TOPIC: "mqtt_sessions"
      KAFKA_RETAINED_MESSAGES_TOPIC: "mqtt_retained_messages"
      KAFKA_CONNECTIONS_TOPIC: "mqtt_connections"
      KAFKA_MESSAGES_DEFAULT_TOPIC: "mqtt_messages"
    ports:
      - "1883:1883"
    volumes:
      - ./waterstream.license:/etc/waterstream.license:ro

  kafka-ui:
    image: provectuslabs/kafka-ui:latest
    depends_on:
      - kafka
    ports:
      - "8080:8080"
    environment:
      KAFKA_CLUSTERS_0_NAME: "local"
      KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: "kafka:9092"

Test the setup

Install mosquitto-clients (or any MQTT client) and run:

# Subscribe in one terminal
mosquitto_sub -h localhost -p 1883 -t "test/#" -v

# Publish from another terminal
mosquitto_pub -h localhost -p 1883 -t "test/hello" -m "Hello from Waterstream"

You should see the message appear in the subscriber terminal.

Check http://localhost:8080 to browse the mqtt_messages topic and confirm the message was stored in Kafka.

More configuration options are documented in Waterstream Configuration.