Signoz standalone docker-compose with Traefik config

This is a sample docker-compose.yml configuration for deploying SigNoz in a standalone mode using Traefik as a reverse proxy. This setup assumes you have Traefik already configured to handle incoming requests and route them to the appropriate services. See Simple Traefik docker-compose setup with Lets Encrypt Cloudflare DNS-01 & TLS-ALPN-01 & HTTP-01 challenges for how we setup Traefik.

First, create a directory for the service to reside in. We’ll use /opt/services/signoz for this example.

Now clone the signoz repository which contains some of the essential configs.

clone-signoz-repo.sh
mkdir -p /opt/services/signoz
cd /opt/services/signoz
git clone https://github.com/SigNoz/signoz.git

Generate a random SIGNOZ_JWT_SECRET using pwgen and write .env in one step:

generate-signoz-jwt-secret.sh
cd /opt/services/signoz
# install pwgen if missing (Debian/Ubuntu)
sudo apt-get update && sudo apt-get install -y pwgen
# create .env with a strong random secret (64 chars)
echo SIGNOZ_JWT_SECRET=$(pwgen -s 64 1) > .env

Now create docker-compose.yml in /opt/services/signoz with the following content (this is essentially the official example with added Traefik labels and directories mapped as volumed). Ensure to modify your domain name settings in the Traefik labels accordingly. (search for mydomain.com)

Important: The gRPC forwarding currently doesn’t work.

docker-compose.yml
x-common: &common
  restart: unless-stopped
  logging:
    options:
      max-size: 50m
      max-file: "3"
x-clickhouse-defaults: &clickhouse-defaults
  !!merge <<: *common
  image: clickhouse/clickhouse-server:25.5.6
  tty: true
  labels:
    signoz.io/scrape: "true"
    signoz.io/port: "9363"
    signoz.io/path: "/metrics"
  depends_on:
    init-clickhouse:
      condition: service_completed_successfully
    zookeeper-1:
      condition: service_healthy
  healthcheck:
    test:
      - CMD
      - wget
      - --spider
      - -q
      - 0.0.0.0:8123/ping
    interval: 30s
    timeout: 5s
    retries: 3
  ulimits:
    nproc: 65535
    nofile:
      soft: 262144
      hard: 262144
  environment:
    - CLICKHOUSE_SKIP_USER_SETUP=1
x-zookeeper-defaults: &zookeeper-defaults
  !!merge <<: *common
  image: signoz/zookeeper:3.7.1
  user: root
  labels:
    signoz.io/scrape: "true"
    signoz.io/port: "9141"
    signoz.io/path: "/metrics"
  healthcheck:
    test:
      - CMD-SHELL
      - curl -s -m 2 http://localhost:8080/commands/ruok | grep error | grep null
    interval: 30s
    timeout: 5s
    retries: 3
x-db-depend: &db-depend
  !!merge <<: *common
  depends_on:
    clickhouse:
      condition: service_healthy
    schema-migrator-sync:
      condition: service_completed_successfully
services:
  init-clickhouse:
    !!merge <<: *common
    image: clickhouse/clickhouse-server:25.5.6
    container_name: signoz-init-clickhouse
    command:
      - bash
      - -c
      - |
        version="v0.0.1"
        node_os=$$(uname -s | tr '[:upper:]' '[:lower:]')
        node_arch=$$(uname -m | sed s/aarch64/arm64/ | sed s/x86_64/amd64/)
        echo "Fetching histogram-binary for $${node_os}/$${node_arch}"
        cd /tmp
        wget -O histogram-quantile.tar.gz "https://github.com/SigNoz/signoz/releases/download/histogram-quantile%2F$${version}/histogram-quantile_$${node_os}_$${node_arch}.tar.gz"
        tar -xvzf histogram-quantile.tar.gz
        mv histogram-quantile /var/lib/clickhouse/user_scripts/histogramQuantile
    restart: on-failure
    volumes:
      - ./signoz/deploy/common/clickhouse/user_scripts:/var/lib/clickhouse/user_scripts/
  zookeeper-1:
    !!merge <<: *zookeeper-defaults
    container_name: signoz-zookeeper-1
    #   - "2181:2181"
    # ports:
    #   - "2888:2888"
    #   - "3888:3888"
    volumes:
      - ./zookeeper-1:/bitnami/zookeeper
    environment:
      - ZOO_SERVER_ID=1
      - ALLOW_ANONYMOUS_LOGIN=yes
      - ZOO_AUTOPURGE_INTERVAL=1
      - ZOO_ENABLE_PROMETHEUS_METRICS=yes
      - ZOO_PROMETHEUS_METRICS_PORT_NUMBER=9141
  clickhouse:
    !!merge <<: *clickhouse-defaults
    container_name: signoz-clickhouse
    # ports:
    #   - "9000:9000"
    #   - "8123:8123"
    #   - "9181:9181"
    volumes:
      - ./signoz/deploy/common/clickhouse/config.xml:/etc/clickhouse-server/config.xml
      - ./signoz/deploy/common/clickhouse/users.xml:/etc/clickhouse-server/users.xml
      - ./signoz/deploy/common/clickhouse/custom-function.xml:/etc/clickhouse-server/custom-function.xml
      - ./signoz/deploy/common/clickhouse/user_scripts:/var/lib/clickhouse/user_scripts/
      - ./signoz/deploy/common/clickhouse/cluster.xml:/etc/clickhouse-server/config.d/cluster.xml
      - ./clickhouse:/var/lib/clickhouse/
      # - ./signoz/deploy/common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
  signoz:
    !!merge <<: *db-depend
    image: signoz/signoz:${VERSION:-v0.101.0}
    container_name: signoz
    command:
      - --config=/root/config/prometheus.yml
    # ports:
    #  - "8080:8080" # signoz port
    #   - "6060:6060"     # pprof port
    volumes:
      - ./signoz/deploy/common/signoz/prometheus.yml:/root/config/prometheus.yml
      - ./signoz/deploy/common/dashboards:/root/config/dashboards
      - ./signoz_sqlite:/var/lib/signoz/
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.signoz.rule=Host(`signoz.mydomain.com`)"
      - "traefik.http.routers.signoz.entrypoints=websecure"
      - "traefik.http.routers.signoz.tls.certresolver=cloudflare"
      - "traefik.http.routers.signoz.tls.domains[0].main=signoz.mydomain.com"
      - "traefik.http.routers.signoz.tls.domains[0].sans=*.signoz.mydomain.com"
      - "traefik.http.services.signoz.loadbalancer.server.port=8080"
    environment:
      - SIGNOZ_ALERTMANAGER_PROVIDER=signoz
      - SIGNOZ_TELEMETRYSTORE_CLICKHOUSE_DSN=tcp://clickhouse:9000
      - SIGNOZ_SQLSTORE_SQLITE_PATH=/var/lib/signoz/signoz.db
      - DASHBOARDS_PATH=/root/config/dashboards
      - STORAGE=clickhouse
      - GODEBUG=netdns=go
      - TELEMETRY_ENABLED=true
      - DEPLOYMENT_TYPE=docker-standalone-amd
      - DOT_METRICS_ENABLED=true
      - SIGNOZ_JWT_SECRET=${SIGNOZ_JWT_SECRET}
    healthcheck:
      test:
        - CMD
        - wget
        - --spider
        - -q
        - localhost:8080/api/v1/health
      interval: 30s
      timeout: 5s
      retries: 3
  otel-collector:
    !!merge <<: *db-depend
    image: signoz/signoz-otel-collector:${OTELCOL_TAG:-v0.129.8}
    container_name: signoz-otel-collector
    command:
      - --config=/etc/otel-collector-config.yaml
      - --manager-config=/etc/manager-config.yaml
      - --copy-path=/var/tmp/collector-config.yaml
      - --feature-gates=-pkg.translator.prometheus.NormalizeName
    volumes:
      - ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
      - ./signoz/deploy/common/signoz/otel-collector-opamp-config.yaml:/etc/manager-config.yaml
    environment:
      - OTEL_RESOURCE_ATTRIBUTES=host.name=signoz-host,os.type=linux
      - LOW_CARDINAL_EXCEPTION_GROUPING=false
    #ports:
      # - "1777:1777"     # pprof extension
      # - "4317:4317" # OTLP gRPC receiver
      # - "4318:4318" # OTLP HTTP receiver
    labels:
      - "traefik.enable=true"
      # gRPC (OTLP) receiver via Traefik
      - "traefik.http.routers.signoz-grpc.rule=Host(`grpc.signoz.mydomain.com`)"
      - "traefik.http.routers.signoz-grpc.entrypoints=websecure"  
      - "traefik.http.routers.signoz-grpc.tls.certresolver=cloudflare"
      - "traefik.http.routers.signoz-grpc.tls.domains[0].main=signoz.mydomain.com"
      - "traefik.http.routers.signoz-grpc.tls.domains[0].sans=*.signoz.mydomain.com"
      - "traefik.http.routers.signoz-grpc.service=signoz-grpc"
      - "traefik.http.services.signoz-grpc.loadbalancer.server.port=4317"
      - "traefik.http.services.signoz-grpc.loadbalancer.server.scheme=h2c"
      # HTTP (OTLP) receiver via Traefik
      - "traefik.http.routers.signoz-http.rule=Host(`http.signoz.mydomain.com`)"
      - "traefik.http.routers.signoz-http.entrypoints=websecure"
      - "traefik.http.routers.signoz-http.tls.certresolver=cloudflare"
      - "traefik.http.routers.signoz-http.tls.domains[0].main=signoz.mydomain.com"
      - "traefik.http.routers.signoz-http.tls.domains[0].sans=*.signoz.mydomain.com"
      - "traefik.http.routers.signoz-http.service=signoz-http"
      - "traefik.http.services.signoz-http.loadbalancer.server.port=4318"
    depends_on:
      signoz:
        condition: service_healthy
  schema-migrator-sync:
    !!merge <<: *common
    image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-v0.129.8}
    container_name: schema-migrator-sync
    command:
      - sync
      - --dsn=tcp://clickhouse:9000
      - --up=
    depends_on:
      clickhouse:
        condition: service_healthy
    restart: on-failure
  schema-migrator-async:
    !!merge <<: *db-depend
    image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-v0.129.8}
    container_name: schema-migrator-async
    command:
      - async
      - --dsn=tcp://clickhouse:9000
      - --up=
    restart: on-failure

Finally, start the services:

start-signoz-services.sh
docker-compose up

Go to the Signoz web interface (replace with your domain) and create the admin account there.

To setup autostart for the Signoz service, see our post Create a systemd service for your docker-compose project in 10 seconds ; TL;DR:

create-docker-compose-systemd-service.sh
curl -fsSL https://techoverflow.net/scripts/create-docker-compose-service.sh | sudo bash /dev/stdin

For an example of how a nested trace looks like in Signoz, see Logfire example which connects to SigNoz instead of Logfire.


Check out similar posts by category: Monitoring, Docker