services:
  #
  # Required services (database and FusionAuth)
  #

  # Postgresql is the default database. You can swap this out for MySQL if you prefer.
  db:
    image: postgres:16.0-bookworm
    environment:
      PGDATA: /var/lib/postgresql/data/pgdata
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    healthcheck:
      test: [ "CMD-SHELL", "pg_isready -U postgres" ]
      interval: 5s
      timeout: 5s
      retries: 5
    restart: unless-stopped
    volumes:
      - db_data:/var/lib/postgresql/data

  # This is the main FusionAuth application.
  fusionauth:
    image: fusionauth/fusionauth-app:latest
    depends_on:
      db:
        condition: service_healthy
      search:
        condition: service_healthy
    environment:
      DATABASE_URL: jdbc:postgresql://db:5432/fusionauth
      DATABASE_ROOT_USERNAME: ${POSTGRES_USER}
      DATABASE_ROOT_PASSWORD: ${POSTGRES_PASSWORD}
      DATABASE_USERNAME: ${DATABASE_USER}
      DATABASE_PASSWORD: ${DATABASE_PASSWORD}
      FUSIONAUTH_APP_KICKSTART_FILE: ${FUSIONAUTH_APP_KICKSTART_FILE}
      FUSIONAUTH_APP_MEMORY: ${FUSIONAUTH_APP_MEMORY}
      FUSIONAUTH_APP_RUNTIME_MODE: ${FUSIONAUTH_APP_RUNTIME_MODE}
      FUSIONAUTH_APP_URL: http://fusionauth:9011
      SEARCH_SERVERS: http://search:9200
      SEARCH_TYPE: ${FUSIONAUTH_SEARCH_TYPE}
      FUSIONAUTH_APP_INSTALLATION_SOURCE: fusionauth-containers
    healthcheck:
      test: curl --silent --fail http://localhost:9011/api/status -o /dev/null -w "%{http_code}"
      interval: 5s
      timeout: 5s
      retries: 5
    restart: unless-stopped
    ports:
      - 9011:9011
    volumes:
      - fusionauth_config:/usr/local/fusionauth/config
      - ${FUSIONAUTH_LOCAL_KICKSTART_DIRECTORY}:/usr/local/fusionauth/kickstart
      - ${FUSIONAUTH_LOCAL_PLUGIN_DIRECTORY}:/usr/local/fusionauth/plugins

  # Open Search isn't technically required, but the `fusionauth` service currently depends on it, so we start it here.
  # You can change the search engine backend to `database` in the `.env` file if you would prefer to use that.
  # Then you can remove the search dependency above and disable this service.
  search:
    image: opensearchproject/opensearch:2.11.0
    environment:
      cluster.name: fusionauth
      discovery.type: single-node
      node.name: search
      plugins.security.disabled: "true"
      bootstrap.memory_lock: "true"
      OPENSEARCH_JAVA_OPTS: ${OPENSEARCH_JAVA_OPTS}
    healthcheck:
      interval: 10s
      retries: 80
      test: curl --write-out 'HTTP %{http_code}' --fail --silent --output /dev/null http://localhost:9200/
    restart: unless-stopped
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536
        hard: 65536
    ports:
      - 9200:9200 # REST API
      - 9600:9600 # Performance Analyzer
    volumes:
      - search_data:/usr/share/opensearch/data

  #
  # Optional services
  #

  # Caddy can be used as a proxy to FusionAuth.
  caddy:
    image: caddy
    profiles:
      - caddy
    depends_on:
      - fusionauth
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config

  # Mailcatcher is a nice SMTP server that can be used for development and testing. You'll need to configure FusionAuth
  # to use Mailcatcher (or use a Kickstart file that points the SMTP configuration to localhost:1025).
  mailcatcher:
    image: sj26/mailcatcher
    profiles:
      - mailcatcher
    ports:
      - "1025:1025"
      - "1080:1080"
    healthcheck:
      interval: 10s
      retries: 80
      test: wget -q -O /dev/null http://mailcatcher:1080/

  # Zookeeper is needed for Kafka
  zookeeper:
    image: confluentinc/cp-zookeeper:latest
    profiles:
      - kafka
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000
    ports:
      - 2181:2181

  # Kafka can be used for Webhooks rather than HTTP. You'll need to configure FusionAuth to use Kafka (or use a
  # Kickstart file that enables Kafka).
  kafka:
    image: confluentinc/cp-kafka:latest
    profiles:
      - kafka
    depends_on:
      - zookeeper
    ports:
      - 9092:9092
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1

  # Cleanspeak provides filtering of usernames and profile data to prevent profanity and other unwanted content. You'll
  # need a Cleanspeak license to enable this service.
  cleanspeak:
    image: cleanspeak/cleanspeak-app:latest
    profiles:
      - cleanspeak
    depends_on:
      db:
        condition: service_healthy
      search:
        condition: service_healthy
    environment:
      DATABASE_URL: jdbc:postgresql://db:5432/cleanspeak
      DATABASE_ROOT_USERNAME: ${POSTGRES_USER}
      DATABASE_ROOT_PASSWORD: ${POSTGRES_PASSWORD}
      DATABASE_USERNAME: ${DATABASE_USER}
      DATABASE_PASSWORD: ${DATABASE_PASSWORD}
      CLEANSPEAK_APP_MEMORY: ${CLEANSPEAK_APP_MEMORY}
      LICENSE_ID: ${CLEANSPEAK_LICENSE_ID}
      SEARCH_SERVERS: http://search:9200
    restart: unless-stopped
    ports:
      - 8001:8001
    volumes:
      - cs_config:/usr/local/cleanspeak/config

  # OpenTelemetry can be used to collect metrics from FusionAuth and push them to Prometheus or other systems. You might need
  # to configure OpenTelemetry by editing the opentelementy-collector-config.yml file.
  opentelemetry:
    image: otel/opentelemetry-collector
    profiles:
      - opentelemetry
    depends_on:
      - fusionauth
    ports:
      - 8889:8889
      - 4318:4318
    volumes:
      - ${OPENTELEMETRY_COLLECTOR_CONFIG_FILE}:/etc/opentelemetry/collector-config.yml
    command: [ "--config=/etc/opentelemetry/collector-config.yml" ]

  # Prometheus can be used to monitor FusionAuth and can be used with OpenTelemetry or directly. Depending on the way you want to
  # use Prometheus, you might need to change the PROMETHEUS_CONFIG_FILE variable to point to a different configuration file or
  # edit the configuration files as needed.
  prometheus:
    image: prom/prometheus
    profiles:
      - prometheus
    depends_on:
      - fusionauth
    ports:
      - 9090:9090
    volumes:
      - ${PROMETHEUS_CONFIG_FILE}:/etc/prometheus/prometheus.yml
      - ${PROMETHEUS_RULES_FILE}:/etc/prometheus/rules.yml
      - prometheus_data:/prometheus

  # Alertmanager can be used in conjunction with Prometheus to handle errors that are collected.
  alertmanager:
    image: prom/alertmanager:v0.28.1
    profiles:
      - alertmanager
    depends_on:
      - prometheus
    ports:
      - 9093:9093
    volumes:
      - ${ALERTMANAGER_CONFIG_FILE}:/etc/alertmanager/alertmanager-config.yml

volumes:
  caddy_config:
  caddy_data:
  cs_config:
  db_data:
  fusionauth_config:
  prometheus_data:
  search_data:
