name: community-mesh-isp

services:
  controller:
    image: ghcr.io/openmeshnet/controller:2.8.4
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_started
    ports:
      - "8080:8080"
    environment:
      NODE_ENV: production
      PUBLIC_BASE_URL: https://portal.mesh.example.org
      DATABASE_URL: postgres://mesh:${POSTGRES_PASSWORD}@postgres:5432/meshisp
      REDIS_URL: redis://redis:6379/0
      RADIUS_HOST: radius
      RADIUS_SECRET: ${RADIUS_SECRET}
      MQTT_URL: mqtt://broker:1883
      DEFAULT_NETWORK_ASN: "4242423910"
      DEFAULT_IPV6_PREFIX: "fd42:3910::/48"
      MAP_TILE_URL: https://tiles.mesh.example.org/{z}/{x}/{y}.png
    volumes:
      - controller-state:/var/lib/mesh-controller
    networks:
      - control
      - telemetry

  radius:
    image: freeradius/freeradius-server:3.2.5
    restart: unless-stopped
    ports:
      - "1812:1812/udp"
      - "1813:1813/udp"
    environment:
      RADIUS_CLIENT_NET: 10.44.0.0/16
      RADIUS_SECRET: ${RADIUS_SECRET}
    volumes:
      - ./radius/clients.conf:/etc/freeradius/clients.conf:ro
      - ./radius/sites-enabled:/etc/freeradius/sites-enabled:ro
    networks:
      - control

  broker:
    image: eclipse-mosquitto:2.0
    restart: unless-stopped
    ports:
      - "1883:1883"
    volumes:
      - ./mosquitto/mosquitto.conf:/mosquitto/config/mosquitto.conf:ro
      - mqtt-data:/mosquitto/data
    networks:
      - telemetry

  prometheus:
    image: prom/prometheus:v2.54.1
    restart: unless-stopped
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus-data:/prometheus
    command:
      - --config.file=/etc/prometheus/prometheus.yml
      - --storage.tsdb.retention.time=30d
    networks:
      - telemetry

  grafana:
    image: grafana/grafana:11.1.4
    restart: unless-stopped
    depends_on:
      - prometheus
    ports:
      - "3000:3000"
    environment:
      GF_SERVER_ROOT_URL: https://status.mesh.example.org
      GF_SECURITY_ADMIN_USER: admin
      GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD}
      GF_AUTH_ANONYMOUS_ENABLED: "false"
    volumes:
      - grafana-data:/var/lib/grafana
      - ./grafana/provisioning:/etc/grafana/provisioning:ro
    networks:
      - telemetry

  postgres:
    image: postgis/postgis:16-3.4
    restart: unless-stopped
    environment:
      POSTGRES_DB: meshisp
      POSTGRES_USER: mesh
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - postgres-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U mesh -d meshisp"]
      interval: 10s
      timeout: 5s
      retries: 6
    networks:
      - control

  redis:
    image: redis:7.4-alpine
    restart: unless-stopped
    command: ["redis-server", "--appendonly", "yes"]
    volumes:
      - redis-data:/data
    networks:
      - control

networks:
  control:
    ipam:
      config:
        - subnet: 172.30.10.0/24
  telemetry:
    ipam:
      config:
        - subnet: 172.30.20.0/24

volumes:
  controller-state:
  postgres-data:
  redis-data:
  mqtt-data:
  prometheus-data:
  grafana-data: