version: "3.8"

services:
  # Dependencies
  postgres:
    image: postgres:15.2
    volumes:
      - postgres-data:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: firezone_dev
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
      start_period: 20s
      interval: 30s
      retries: 5
      timeout: 5s
    ports:
      - 5432:5432/tcp
    networks:
      - app

  vault:
    image: vault:1.13.3
    environment:
      VAULT_ADDR: "http://127.0.0.1:8200"
      VAULT_DEV_ROOT_TOKEN_ID: "firezone"
      VAULT_LOG_LEVEL: "debug"
    ports:
      - 8200:8200/tcp
    cap_add:
      - IPC_LOCK
    networks:
      - app
    healthcheck:
      test:
        [
          "CMD",
          "wget",
          "--spider",
          "--proxy",
          "off",
          "http://127.0.0.1:8200/v1/sys/health?standbyok=true",
        ]
      interval: 10s
      timeout: 3s
      retries: 10
      start_period: 5s

  # Firezone Components
  web:
    build:
      context: elixir
      cache_from:
        - type=registry,ref=us-east1-docker.pkg.dev/firezone-staging/cache/web:main
      args:
        APPLICATION_NAME: web
    image: us-east1-docker.pkg.dev/firezone-staging/firezone/web:${VERSION:-main}
    hostname: web.cluster.local
    ports:
      - 8080:8080/tcp
    environment:
      # Web Server
      EXTERNAL_URL: http://localhost:8080/
      PHOENIX_HTTP_WEB_PORT: "8080"
      PHOENIX_SECURE_COOKIES: false
      # Erlang
      ERLANG_DISTRIBUTION_PORT: 9000
      ERLANG_CLUSTER_ADAPTER: "Elixir.Cluster.Strategy.Epmd"
      ERLANG_CLUSTER_ADAPTER_CONFIG: '{"hosts":["api@api.cluster.local","web@web.cluster.local"]}'
      RELEASE_COOKIE: "NksuBhJFBhjHD1uUa9mDOHV"
      RELEASE_HOSTNAME: "web.cluster.local"
      RELEASE_NAME: "web"
      # Database
      DATABASE_HOST: postgres
      DATABASE_PORT: 5432
      DATABASE_NAME: firezone_dev
      DATABASE_USER: postgres
      DATABASE_PASSWORD: postgres
      # Auth
      AUTH_PROVIDER_ADAPTERS: "email,openid_connect,userpass,token,google_workspace"
      # Secrets
      TOKENS_KEY_BASE: "5OVYJ83AcoQcPmdKNksuBhJFBhjHD1uUa9mDOHV/6EIdBQ6pXksIhkVeWIzFk5S2"
      TOKENS_SALT: "t01wa0K4lUd7mKa0HAtZdE+jFOPDDej2"
      RELAYS_AUTH_TOKEN_KEY_BASE: "5OVYJ83AcoQcPmdKNksuBhJFBhjHD1uUa9mDOHV/6EIdBQ6pXksIhkVeWIzFk5S2"
      RELAYS_AUTH_TOKEN_SALT: "t01wa0K4lUd7mKa0HAtZdE+jFOPDDej2"
      GATEWAYS_AUTH_TOKEN_KEY_BASE: "5OVYJ83AcoQcPmdKNksuBhJFBhjHD1uUa9mDOHV/6EIdBQ6pXksIhkVeWIzFk5S2"
      GATEWAYS_AUTH_TOKEN_SALT: "t01wa0K4lUd7mKa0HAtZdE+jFOPDDej2"
      SECRET_KEY_BASE: "5OVYJ83AcoQcPmdKNksuBhJFBhjHD1uUa9mDOHV/6EIdBQ6pXksIhkVeWIzFk5S2"
      LIVE_VIEW_SIGNING_SALT: "t01wa0K4lUd7mKa0HAtZdE+jFOPDDej2"
      COOKIE_SIGNING_SALT: "t01wa0K4lUd7mKa0HAtZdE+jFOPDDej2"
      COOKIE_ENCRYPTION_SALT: "t01wa0K4lUd7mKa0HAtZdE+jFOPDDej2"
      # Telemetry
      TELEMETRY_ENABLED: "false"
      # Debugging
      LOG_LEVEL: "debug"
      # Emails
      OUTBOUND_EMAIL_FROM: "public-noreply@firez.one"
      OUTBOUND_EMAIL_ADAPTER: "Elixir.Swoosh.Adapters.Postmark"
      ## Warning: The token is for the blackhole Postmark server created in a separate isolated account,
      ## that WILL NOT send any actual emails, but you can see and debug them in the Postmark dashboard.
      OUTBOUND_EMAIL_ADAPTER_OPTS: '{"api_key":"7da7d1cd-111c-44a7-b5ac-4027b9d230e5"}'
      # Seeds
      STATIC_SEEDS: "true"
    depends_on:
      vault:
        condition: "service_healthy"
      postgres:
        condition: "service_healthy"
    networks:
      - app

  client:
    environment:
      FIREZONE_TOKEN: "n.SFMyNTY.g2gDaANtAAAAJGM4OWJjYzhjLTkzOTItNGRhZS1hNDBkLTg4OGFlZjZkMjhlMG0AAAAkN2RhN2QxY2QtMTExYy00NGE3LWI1YWMtNDAyN2I5ZDIzMGU1bQAAACtBaUl5XzZwQmstV0xlUkFQenprQ0ZYTnFJWktXQnMyRGR3XzJ2Z0lRdkZnbgYAGUmu74wBYgABUYA.UN3vSLLcAMkHeEh5VHumPOutkuue8JA6wlxM9JxJEPE"
      RUST_LOG: firezone_linux_client=trace,wire=trace,connlib_client_shared=trace,firezone_tunnel=trace,connlib_shared=trace,warn
      FIREZONE_API_URL: ws://api:8081
      FIREZONE_ID: D0455FDE-8F65-4960-A778-B934E4E85A5F
      MAX_PARTITION_TIME: 5s
    build:
      target: debug
      context: rust
      dockerfile: Dockerfile
      cache_from:
        - type=registry,ref=us-east1-docker.pkg.dev/firezone-staging/cache/client:main
      args:
        PACKAGE: firezone-linux-client
    image: us-east1-docker.pkg.dev/firezone-staging/firezone/client:${VERSION:-main}
    dns:
      - 100.100.111.1
    cap_add:
      - NET_ADMIN
    sysctls:
      - net.ipv6.conf.all.disable_ipv6=0
    devices:
      - "/dev/net/tun:/dev/net/tun"
    depends_on:
      gateway:
        condition: "service_healthy"
      httpbin:
        condition: "service_healthy"
      api:
        condition: "service_healthy"
    networks:
      app:
        ipv4_address: 172.28.0.100

  gateway:
    healthcheck:
      test: ["CMD-SHELL", "ip link | grep tun-firezone"]
    environment:
      FIREZONE_TOKEN: "SFMyNTY.g2gDaAJtAAAAJDNjZWYwNTY2LWFkZmQtNDhmZS1hMGYxLTU4MDY3OTYwOGY2Zm0AAABAamp0enhSRkpQWkdCYy1vQ1o5RHkyRndqd2FIWE1BVWRwenVScjJzUnJvcHg3NS16bmhfeHBfNWJUNU9uby1yYm4GAEC0b0KJAWIAAVGA.9Oirn9t8rvQpfOhW7hwGBFVzeMm9di0xYGTlwf9cFFk"
      RUST_LOG: firezone_gateway=trace,wire=trace,connlib_gateway_shared=trace,firezone_tunnel=trace,connlib_shared=trace,warn
      FIREZONE_ENABLE_MASQUERADE: 1
      FIREZONE_API_URL: ws://api:8081
      FIREZONE_ID: 4694E56C-7643-4A15-9DF3-638E5B05F570
    build:
      target: debug
      context: rust
      dockerfile: Dockerfile
      cache_from:
        - type=registry,ref=us-east1-docker.pkg.dev/firezone-staging/cache/gateway:main
      args:
        PACKAGE: firezone-gateway
    image: us-east1-docker.pkg.dev/firezone-staging/firezone/gateway:${VERSION:-main}
    cap_add:
      - NET_ADMIN
    sysctls:
      - net.ipv4.ip_forward=1
      - net.ipv4.conf.all.src_valid_mark=1
      - net.ipv6.conf.all.disable_ipv6=0
      - net.ipv6.conf.all.forwarding=1
      - net.ipv6.conf.default.forwarding=1
    devices:
      - "/dev/net/tun:/dev/net/tun"
    depends_on:
      api:
        condition: "service_healthy"
    networks:
      app:
        ipv4_address: 172.28.0.105
      resources:

  httpbin:
    image: kennethreitz/httpbin
    healthcheck:
      test: ["CMD-SHELL", "ps -C gunicorn"]
    networks:
      resources:
        ipv4_address: 172.20.0.100

  iperf3:
    image: networkstatic/iperf3
    healthcheck:
      test: ["CMD-SHELL", "iperf3 -k 1 -c 127.0.0.1 || exit 1"]
    command: -s
    networks:
      resources:
        ipv4_address: 172.20.0.110

  relay:
    environment:
      PUBLIC_IP4_ADDR: 172.28.0.101
      PUBLIC_IP6_ADDR: fcff:3990:3990::101
      LOWEST_PORT: 55555
      HIGHEST_PORT: 55666
      # Token for self-hosted Relay
      #FIREZONE_TOKEN: "SFMyNTY.g2gDaAJtAAAAJDcyODZiNTNkLTA3M2UtNGM0MS05ZmYxLWNjODQ1MWRhZDI5OW0AAABARVg3N0dhMEhLSlVWTGdjcE1yTjZIYXRkR25mdkFEWVFyUmpVV1d5VHFxdDdCYVVkRVUzbzktRmJCbFJkSU5JS24GAFSzb0KJAWIAAVGA.waeGE26tbgkgIcMrWyck0ysv9SHIoHr0zqoM3wao84M"
      # Token for global Relay
      FIREZONE_TOKEN: "SFMyNTY.g2gDaAJtAAAAJGMxMDM4ZTIyLTAyMTUtNDk3Ny05ZjZjLWY2NTYyMWUwMDA4Zm0AAABWT2JubmIzN2RCdE5RY2NDVS1mQll1MWg4TmFmQXAwS3lvT3dsbzJUVEl5NjBvZm9rSWxWNjBzcGExMkc1cElHLVJWS2o1cXdIVkVoMWs5bjh4QmNmOUFuBgAqiFHuiwFiAAFRgA.VyV9cW06PCZyxTefBwIlSCFTDBFEOSRQ2gfJXtMplVE"
      RUST_LOG: "debug"
      RUST_BACKTRACE: 1
      FIREZONE_API_URL: ws://api:8081
    build:
      target: debug
      context: rust
      dockerfile: Dockerfile
      cache_from:
        - type=registry,ref=us-east1-docker.pkg.dev/firezone-staging/cache/relay:main
      args:
        PACKAGE: firezone-relay
    image: us-east1-docker.pkg.dev/firezone-staging/firezone/relay:${VERSION:-main}
    healthcheck:
      test: ["CMD-SHELL", "lsof -i UDP | grep firezone-relay"]
      start_period: 3s
      interval: 30s
      retries: 5
      timeout: 5s
    depends_on:
      api:
        condition: "service_healthy"
    ports:
      # XXX: Only 111 ports are used for local dev / testing because Docker Desktop
      # allocates a userland proxy process for each forwarded port X_X.
      #
      # Large ranges here will bring your machine to its knees.
      - "55555-55666:55555-55666/udp"
      - 3478:3478/udp
    networks:
      app:
        ipv4_address: 172.28.0.101

  api:
    build:
      context: elixir
      cache_from:
        - type=registry,ref=us-east1-docker.pkg.dev/firezone-staging/cache/api:main
      args:
        APPLICATION_NAME: api
    image: us-east1-docker.pkg.dev/firezone-staging/firezone/api:${VERSION:-main}
    hostname: api.cluster.local
    ports:
      - 8081:8081/tcp
    environment:
      # Web Server
      EXTERNAL_URL: http://localhost:8081/
      PHOENIX_HTTP_API_PORT: "8081"
      PHOENIX_SECURE_COOKIES: false
      # Erlang
      ERLANG_DISTRIBUTION_PORT: 9000
      ERLANG_CLUSTER_ADAPTER: "Elixir.Cluster.Strategy.Epmd"
      ERLANG_CLUSTER_ADAPTER_CONFIG: '{"hosts":["api@api.cluster.local","web@web.cluster.local"]}'
      RELEASE_COOKIE: "NksuBhJFBhjHD1uUa9mDOHV"
      RELEASE_HOSTNAME: "api.cluster.local"
      RELEASE_NAME: "api"
      # Database
      DATABASE_HOST: postgres
      DATABASE_PORT: 5432
      DATABASE_NAME: firezone_dev
      DATABASE_USER: postgres
      DATABASE_PASSWORD: postgres
      # Auth
      AUTH_PROVIDER_ADAPTERS: "email,openid_connect,userpass,token,google_workspace"
      # Secrets
      TOKENS_KEY_BASE: "5OVYJ83AcoQcPmdKNksuBhJFBhjHD1uUa9mDOHV/6EIdBQ6pXksIhkVeWIzFk5S2"
      TOKENS_SALT: "t01wa0K4lUd7mKa0HAtZdE+jFOPDDej2"
      RELAYS_AUTH_TOKEN_KEY_BASE: "5OVYJ83AcoQcPmdKNksuBhJFBhjHD1uUa9mDOHV/6EIdBQ6pXksIhkVeWIzFk5S2"
      RELAYS_AUTH_TOKEN_SALT: "t01wa0K4lUd7mKa0HAtZdE+jFOPDDej2"
      GATEWAYS_AUTH_TOKEN_KEY_BASE: "5OVYJ83AcoQcPmdKNksuBhJFBhjHD1uUa9mDOHV/6EIdBQ6pXksIhkVeWIzFk5S2"
      GATEWAYS_AUTH_TOKEN_SALT: "t01wa0K4lUd7mKa0HAtZdE+jFOPDDej2"
      SECRET_KEY_BASE: "5OVYJ83AcoQcPmdKNksuBhJFBhjHD1uUa9mDOHV/6EIdBQ6pXksIhkVeWIzFk5S2"
      LIVE_VIEW_SIGNING_SALT: "t01wa0K4lUd7mKa0HAtZdE+jFOPDDej2"
      COOKIE_SIGNING_SALT: "t01wa0K4lUd7mKa0HAtZdE+jFOPDDej2"
      COOKIE_ENCRYPTION_SALT: "t01wa0K4lUd7mKa0HAtZdE+jFOPDDej2"
      # Telemetry
      TELEMETRY_ENABLED: "false"
      # Debugging
      LOG_LEVEL: "debug"
      # Emails
      OUTBOUND_EMAIL_FROM: "public-noreply@firez.one"
      OUTBOUND_EMAIL_ADAPTER: "Elixir.Swoosh.Adapters.Postmark"
      ## Warning: The token is for the blackhole Postmark server created in a separate isolated account,
      ## that WILL NOT send any actual emails, but you can see and debug them in the Postmark dashboard.
      OUTBOUND_EMAIL_ADAPTER_OPTS: '{"api_key":"7da7d1cd-111c-44a7-b5ac-4027b9d230e5"}'
      # Seeds
      STATIC_SEEDS: "true"
    depends_on:
      vault:
        condition: "service_healthy"
      postgres:
        condition: "service_healthy"
    healthcheck:
      test: ["CMD-SHELL", "curl -f localhost:8081/healthz"]
      start_period: 10s
      interval: 30s
      retries: 5
      timeout: 5s
    networks:
      - app

  # This is a service container which allows to run mix tasks for local development
  # without having to install Elixir and Erlang on the host machine.
  elixir:
    build:
      context: elixir
      target: compiler
      cache_from:
        - type=registry,ref=us-east1-docker.pkg.dev/firezone-staging/cache/elixir:main
      args:
        APPLICATION_NAME: api
    image: us-east1-docker.pkg.dev/firezone-staging/firezone/elixir:${VERSION:-main}
    hostname: elixir
    environment:
      # Web Server
      EXTERNAL_URL: http://localhost:8081/
      # Erlang
      ERLANG_DISTRIBUTION_PORT: 9000
      RELEASE_COOKIE: "NksuBhJFBhjHD1uUa9mDOHV"
      RELEASE_HOSTNAME: "mix.cluster.local"
      RELEASE_NAME: "mix"
      # Database
      DATABASE_HOST: postgres
      DATABASE_PORT: 5432
      DATABASE_NAME: firezone_dev
      DATABASE_USER: postgres
      DATABASE_PASSWORD: postgres
      # Auth
      AUTH_PROVIDER_ADAPTERS: "email,openid_connect,userpass,token,google_workspace"
      # Secrets
      TOKENS_KEY_BASE: "5OVYJ83AcoQcPmdKNksuBhJFBhjHD1uUa9mDOHV/6EIdBQ6pXksIhkVeWIzFk5S2"
      TOKENS_SALT: "t01wa0K4lUd7mKa0HAtZdE+jFOPDDej2"
      RELAYS_AUTH_TOKEN_KEY_BASE: "5OVYJ83AcoQcPmdKNksuBhJFBhjHD1uUa9mDOHV/6EIdBQ6pXksIhkVeWIzFk5S2"
      RELAYS_AUTH_TOKEN_SALT: "t01wa0K4lUd7mKa0HAtZdE+jFOPDDej2"
      GATEWAYS_AUTH_TOKEN_KEY_BASE: "5OVYJ83AcoQcPmdKNksuBhJFBhjHD1uUa9mDOHV/6EIdBQ6pXksIhkVeWIzFk5S2"
      GATEWAYS_AUTH_TOKEN_SALT: "t01wa0K4lUd7mKa0HAtZdE+jFOPDDej2"
      SECRET_KEY_BASE: "5OVYJ83AcoQcPmdKNksuBhJFBhjHD1uUa9mDOHV/6EIdBQ6pXksIhkVeWIzFk5S2"
      LIVE_VIEW_SIGNING_SALT: "t01wa0K4lUd7mKa0HAtZdE+jFOPDDej2"
      COOKIE_SIGNING_SALT: "t01wa0K4lUd7mKa0HAtZdE+jFOPDDej2"
      COOKIE_ENCRYPTION_SALT: "t01wa0K4lUd7mKa0HAtZdE+jFOPDDej2"
      # Telemetry
      TELEMETRY_ENABLED: "false"
      # Higher log level not to make seeds output too verbose
      LOG_LEVEL: "info"
      # Emails
      OUTBOUND_EMAIL_FROM: "public-noreply@firez.one"
      OUTBOUND_EMAIL_ADAPTER: "Elixir.Swoosh.Adapters.Postmark"
      ## Warning: The token is for the blackhole Postmark server created in a separate isolated account,
      ## that WILL NOT send any actual emails, but you can see and debug them in the Postmark dashboard.
      OUTBOUND_EMAIL_ADAPTER_OPTS: '{"api_key":"7da7d1cd-111c-44a7-b5ac-4027b9d230e5"}'
      # Mix env should be set to prod to use secrets declared above,
      # otherwise seeds will generate invalid tokens
      MIX_ENV: "prod"
      # Seeds
      STATIC_SEEDS: "true"
    depends_on:
      postgres:
        condition: "service_healthy"
    networks:
      - app

networks:
  resources:
    enable_ipv6: true
    ipam:
      config:
        - subnet: 172.20.0.0/16
        - subnet: 2001:db8:1::/64
  app:
    enable_ipv6: true
    ipam:
      config:
        - subnet: 172.28.0.0/16
        - subnet: 2001:db8:2::/64

volumes:
  postgres-data:
  elixir-build-cache:
  assets-build-cache:
