Ctrl K
ComunidadGuías…

docker-compose.yaml

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
name: hook0

volumes:
  postgres-data:
  mailpit-data:

services:
  postgres:
    image: postgres:18
    volumes:
      - postgres-data:/var/lib/postgresql
    environment:
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_DB=hook0
    ports:
      - "5432:5432"
    networks:
      - hook0
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres -d $${POSTGRES_DB}"]
      timeout: 1s
      interval: 5s

  mailpit:
    image: axllent/mailpit:v1.28
    volumes:
      - mailpit-data:/data
    environment:
      - MP_DATABASE=/data/mailpit.db
      - POSTGRES_DB=hook0
    ports:
      - "8025:8025"
      - "1025:1025"
    networks:
      - hook0
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider --user-agent 'docker-compose-healthcheck' http://localhost:8025/api/v1/info || exit 1"]
      timeout: 1s
      interval: 5s

  api:
    build:
      context: .
      dockerfile: api/Dockerfile
      args:
        FEATURES: "application-secret-compatibility"
    environment:
      - IP=0.0.0.0
      - PORT=8081
      - CORS_ALLOWED_ORIGINS=http://localhost:8001
      - DATABASE_URL=postgres://postgres:postgres@postgres:5432/hook0
      - SMTP_CONNECTION_URL=smtp://mailpit:1025
      - EMAIL_SENDER_ADDRESS=sender@hook0.local
      - APP_URL=http://localhost:8001
      - BISCUIT_PRIVATE_KEY=bbea79cd66926b219b3219a3186decb36136d774dd7c35a8239e512090fa8854  # DO NOT USE THIS KEY IN PRODUCTION
      # Development stack only: the default burst of 5 is what bounds
      # address-enumeration sweeps on the endpoints that send mail. The suite
      # gives its direct API calls a source address of their own, so only the
      # browser-driven ones draw on this quota — signing up included, now that
      # registration mails an address the caller names and is held to the same
      # allowance as the rest of that family. Raised rather than disabled, and
      # not raised out of sight, so a loop that hammers the endpoint still meets
      # a 429 here instead of meeting one for the first time in production.
      - API_RATE_LIMITING_EMAIL_BURST_SIZE=50
      # Development stack only, and the phrase is read rather than only meant:
      # a setting whose comment carries it is one `self-hosting` is held not to
      # declare, and one the compose file has to be free to shape for this stack
      # without shaping a cluster.
      #
      # One address: this stack's own bridge gateway, which is what a caller on
      # this host arrives as. It makes the API trust the client address
      # announced in a proxy header when the peer is that gateway, and trust
      # nobody else — a peer inside the trusted range can claim any address it
      # likes and walk past every per-IP limiter, so the range is the whole of
      # the setting's blast radius and it is held to one address.
      #
      # Not 127.0.0.0/8, and not the bridge pool either. Measured on the three
      # ways in, against a container on a network this file shaped:
      #
      #   from this host, through the published port -> the gateway, 172.16.0.1
      #   from another container on this network     -> its own address, .0.2 up
      #   from off the host, at its LAN address      -> the caller's own address
      #
      # so loopback is never what arrives, and Docker's pool would have covered
      # the second line: every sibling on this network, `frontend` and
      # `output-worker` included, plus whatever an operator adds to it. The
      # gateway is the one address on the network no container can be given.
      #
      # It is a fixed address rather than a guessed one because the network
      # below fixes it. Left to itself Docker draws a /16 from its pool in the
      # order they are free, so the gateway is 172.18.0.1 on one machine and
      # 172.21.0.1 on the next, and a range wide enough to cover them all is
      # the range this is not.
      - REVERSE_PROXY_IPS=172.16.0.1/32
    ports:
      - "8081:8081"
    networks:
      - hook0
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "curl --fail --user-agent 'docker-compose-healthcheck' http://localhost:$${PORT}/api/v1/swagger.json || exit 1"]
      timeout: 1s
      interval: 5s
    depends_on:
      postgres:
        condition: service_healthy
      mailpit:
        condition: service_healthy

  frontend:
    build:
      context: .
      dockerfile: frontend/Dockerfile
    environment:
      - API_ENDPOINT=http://localhost:8081/api/v1
    ports:
      - "8001:80"
    networks:
      - hook0
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "curl --fail --user-agent 'docker-compose-healthcheck' http://localhost || exit 1"]
      timeout: 1s
      interval: 5s
    depends_on:
      api:
        condition: service_healthy

  output-worker:
    build:
      context: .
      dockerfile: output-worker/Dockerfile
    environment:
      - DATABASE_URL=postgres://postgres:postgres@postgres:5432/hook0
      - WORKER_NAME=default
      - DISABLE_TARGET_IP_CHECK=true
    networks:
      - hook0
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
      api:
        condition: service_healthy

networks:
  hook0:
    driver: bridge
    # Fixed rather than drawn from Docker's pool, so that the gateway the API is
    # told to trust is an address this file knows rather than one that differs
    # per machine. 172.16 is inside the pool's range and outside what it hands
    # out: a daemon left to itself starts at 172.18 and walks up, so this is the
    # one /16 in there it will not give to something else. Should an operator
    # have taken it anyway, `docker compose up` refuses naming the overlap,
    # which is the way to find out.
    ipam:
      config:
        - subnet: 172.16.0.0/24
          gateway: 172.16.0.1