Documentation

Add StyloBot to an existing Docker Compose app

Step-by-step guide Updated 24 August 2026

Use this when you already have an application in Docker Compose and want StyloBot to sit in front of it. Your application stays on the internal Compose network; StyloBot becomes the one public HTTP port.

This takes about ten minutes. Start in observe-only mode, confirm traffic is flowing, then choose an enforcement policy.

Before you start

You need:

  • an existing compose.yml with an application service;
  • the port your application listens on inside its container; and
  • Docker Compose v2 (docker compose, not the old standalone command).

The examples use an app service named app listening on port 3000. Replace those two values with yours.

1. Stop publishing your app directly

If your app has a ports: entry such as "3000:3000", remove it. Keep expose: instead. expose keeps the port reachable by other Compose services without making it public from the host.

services:
  app:
    image: my-company/my-app:latest
    expose:
      - "3000"

If another internal service needs to call the app, keep using http://app:3000.

2. Add the FOSS gateway

Add this service alongside your app. The gateway calls the upstream by its Compose service name, so do not use localhost for DEFAULT_UPSTREAM.

services:
  stylobot:
    image: scottgal/stylobot-gateway:latest
    ports:
      - "8080:8080"
    environment:
      ASPNETCORE_URLS: http://+:8080
      DEFAULT_UPSTREAM: http://app:3000
    depends_on:
      - app

  app:
    image: my-company/my-app:latest
    expose:
      - "3000"

For a custom domain, point your existing reverse proxy, load balancer, or DNS target at the host port 8080. Do not publish both app and stylobot: that would let callers bypass detection.

3. Start in observe-only mode

Bring up the changed services:

docker compose up -d app stylobot
docker compose logs -f stylobot

Open http://localhost:8080/ (or your normal public URL) and confirm the app still responds through StyloBot. The live dashboard is available at:

http://localhost:8080/_stylobot/

Keep your normal application smoke tests. They now exercise the real public path: client → StyloBot → app.

4. Verify detection without blocking anyone

Run these from a second terminal:

curl -is -A "Mozilla/5.0 (Macintosh) Safari/605.1.15" http://localhost:8080/
curl -is -A "curl/8.4.0" http://localhost:8080/
curl -is -A "Python/3.13 aiohttp/3.11" http://localhost:8080/.env

You should see X-Bot-* response headers and the requests in the dashboard. At this point StyloBot is observing and classifying your traffic; your app behaviour should be unchanged.

5. Choose an enforcement policy

Once the dashboard looks right, add your policy to the gateway command or configuration. For example, this starts the gateway in production mode and slows likely automated traffic instead of blocking it outright:

  stylobot:
    image: scottgal/stylobot-gateway:latest
    command: ["5080", "http://app:3000", "--mode", "production", "--policy", "throttle-stealth"]
    ports:
      - "8080:5080"

Use allow while tuning, throttle-stealth for a cautious first enforcement policy, or route-specific policies when you are ready to protect sensitive endpoints. See Configuration for the complete policy model.

Add the commercial layer

The FOSS gateway above is complete on its own. Commercial adds durable PostgreSQL-backed state, live editing, dashboard packs, and licensed capabilities. It uses the same topology: StyloBot remains the only public service in front of app.

  1. Keep the app and stylobot service names from the FOSS setup.
  2. Add a PostgreSQL service (or use your existing managed PostgreSQL instance).
  3. Replace the FOSS image with the commercial gateway image supplied through your customer registry.
  4. Put the license token and connection string in .env; never commit either value.
services:
  stylobot:
    image: ${STYLOBOT_GATEWAY_IMAGE}
    ports:
      - "8080:8080"
    environment:
      ASPNETCORE_URLS: http://+:8080
      DEFAULT_UPSTREAM: http://app:3000
      BotDetection__Commercial__LicenseToken: ${STYLOBOT_COMMERCIAL_LICENSE_TOKEN}
      BotDetection__Commercial__Postgres__ConnectionString: Host=stylobot-db;Database=stylobot;Username=stylobot;Password=${STYLOBOT_DB_PASSWORD}
    depends_on:
      stylobot-db:
        condition: service_healthy
      app:
        condition: service_started

  stylobot-db:
    image: pgvector/pgvector:pg16
    environment:
      POSTGRES_DB: stylobot
      POSTGRES_USER: stylobot
      POSTGRES_PASSWORD: ${STYLOBOT_DB_PASSWORD}
    volumes:
      - stylobot-db:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U stylobot -d stylobot"]
      interval: 5s
      timeout: 5s
      retries: 10

volumes:
  stylobot-db:

Create a local .env next to your Compose file:

STYLOBOT_GATEWAY_IMAGE=your-customer-registry/stylobot-gateway-enterprise:8.5.3
STYLOBOT_COMMERCIAL_LICENSE_TOKEN=replace-with-your-license-token
STYLOBOT_DB_PASSWORD=use-a-long-random-password

Add .env to .gitignore. For production, use your Compose secret mechanism or an external secret manager instead of a checked-in environment file.

Then start it and verify the same public path:

docker compose up -d
docker compose ps
docker compose logs -f stylobot

Troubleshooting

Symptom Check
502 from StyloBot The upstream must be http://app:<container-port>, not localhost. Confirm the app is healthy with docker compose exec stylobot wget -qO- http://app:3000/.
App is still reachable without StyloBot Remove the app's ports: mapping; use expose: only.
No dashboard data Browse through the StyloBot port, then check docker compose logs stylobot.
Commercial gateway will not start Confirm the PostgreSQL healthcheck is passing and the license token/connection string are supplied as environment variables.

Next: How StyloBot works, Configuration, or choose a plan.