Building & Running

NUTS can be run in three main ways:

  1. As a standalone Caddy binary built with xcaddy or from source.
  2. As a prebuilt Docker image (idcttech/nuts) you pull and run.
  3. Via Docker Compose, which brings up NATS + NUTS together.

Pick whichever matches your environment — they all serve the same SSE endpoints.

Prerequisites


Running Without Docker

Use this path when you already run Caddy on the host or want a single static binary.

1. Build Caddy with NUTS

The simplest way is xcaddy:

xcaddy build --with github.com/ideaconnect/nuts

This produces a caddy binary in the current directory with NUTS compiled in.

Or build from source:

git clone https://github.com/ideaconnect/nuts.git
cd nuts
go build -o caddy ./cmd/caddy

For development with the race detector:

CGO_ENABLED=1 go build -race -o caddy ./cmd/caddy

2. Start NATS with JetStream

nats-server -js -p 4222

3. Create the JetStream stream

nats stream add EVENTS \
  --subjects "events.>" \
  --storage file \
  --retention limits \
  --max-msgs 10000 \
  --max-age 24h \
  --discard old

4. Run Caddy

./caddy run --config Caddyfile

Verify NUTS is loaded:

./caddy list-modules | grep nuts
# expected: http.handlers.nuts

Running With Docker

Option A — Prebuilt image

A multi-architecture image (amd64 / arm64) is published to Docker Hub at idcttech/nuts.

docker pull idcttech/nuts:latest

Pin in production. :latest is updated on every default-branch push. Use idcttech/nuts:<version> once a versioned release is available.

The image expects a Caddyfile mounted at /app/Caddyfile and exposes port 8080:

docker run -d \
  -p 8080:8080 \
  -e NATS_URL=nats://host.docker.internal:4222 \
  --add-host=host.docker.internal:host-gateway \
  -v ./Caddyfile:/app/Caddyfile:ro \
  idcttech/nuts:latest

If NATS runs in the same Docker network, point NATS_URL at its service name (e.g. nats://nats:4222) instead of host.docker.internal.

Option B — NATS in Docker, Caddy locally

Quickly spin up just NATS while keeping a local Caddy binary:

docker run --rm -p 4222:4222 nats:2.12-alpine -js

Option C — Full stack with Docker Compose

The NUTS repository ships a docker-compose.yml that brings up NATS (with JetStream) and a Caddy server with NUTS, ready for development:

git clone https://github.com/ideaconnect/nuts.git
cd nuts

docker compose up -d --build      # start all services
docker compose logs -f            # tail logs
docker compose down -v            # stop and clean up

A production-style Compose file using the prebuilt image looks like:

services:
  nats:
    image: nats:2.12-alpine
    command: ["--jetstream", "--store_dir=/data"]
    volumes:
      - nats-data:/data
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://localhost:8222/healthz"]
      interval: 2s
      timeout: 3s
      retries: 10

  nats-init:
    image: natsio/nats-box:0.19.0
    depends_on:
      nats:
        condition: service_healthy
    entrypoint: ["/bin/sh", "-c"]
    command:
      - |
        nats -s nats://nats:4222 stream add EVENTS \
          --subjects "events.>" --storage file --retention limits \
          --max-msgs 10000 --max-age 24h --discard old --defaults
    restart: "no"

  nuts:
    image: idcttech/nuts:latest    # pin to a version in production
    ports:
      - "8080:8080"
    volumes:
      - ./Caddyfile:/app/Caddyfile:ro
    depends_on:
      nats-init:
        condition: service_completed_successfully

volumes:
  nats-data:

Container Environment Variables

The Caddyfile shipped in the image uses Caddy’s {$NAME:default} substitution for three commonly-overridden values:

Variable Default Caddyfile directive
NATS_URL nats://localhost:4222 nats_url
STREAM_NAME EVENTS stream_name
TOPIC_PREFIX events. topic_prefix

To expose other directives (allowed_origins, max_connections, etc.) through the environment, add matching {$NAME:default} placeholders yourself — NUTS itself does not read environment variables directly.


Using Make

The repository ships a Makefile for common development tasks:

make build           # Build the Caddy binary
make test            # Run all tests (unit + functional)
make test-unit       # Run unit tests with embedded NATS
make test-functional # Run BDD tests with Docker
make docker-up       # Start Docker services
make docker-down     # Stop Docker services
make clean           # Clean build artifacts
make help            # Show all available commands

A convenience script sets up the development environment in one step:

./scripts/setup-dev.sh

This starts NATS with JetStream and creates the test stream automatically.