File size: 5,041 Bytes
5d3c01b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# =============================================================================
# World Monitor β€” Docker / Podman Compose
# =============================================================================
# Self-contained stack: app + Redis + AIS relay.
#
# Quick start:
#   cp .env.example .env        # add your API keys
#   docker compose up -d --build
#
# The app will be available at http://localhost:3000
# =============================================================================

services:

  worldmonitor:
    build:
      context: .
      dockerfile: Dockerfile
    image: worldmonitor:latest
    container_name: worldmonitor
    ports:
      - "${WM_PORT:-3000}:8080"
    environment:
      UPSTASH_REDIS_REST_URL: "http://redis-rest:80"
      UPSTASH_REDIS_REST_TOKEN: "${REDIS_TOKEN:?REDIS_TOKEN required β€” generate with: openssl rand -hex 32}"
      LOCAL_API_PORT: "46123"
      LOCAL_API_MODE: "docker"
      LOCAL_API_CLOUD_FALLBACK: "false"
      WS_RELAY_URL: "http://ais-relay:3004"
      # LLM provider (any OpenAI-compatible endpoint)
      LLM_API_URL: "${LLM_API_URL:-}"
      LLM_API_KEY: "${LLM_API_KEY:-}"
      LLM_MODEL: "${LLM_MODEL:-}"
      GROQ_API_KEY: "${GROQ_API_KEY:-}"
      OPENROUTER_API_KEY: "${OPENROUTER_API_KEY:-}"
      # Data source API keys (optional β€” features degrade gracefully)
      AISSTREAM_API_KEY: "${AISSTREAM_API_KEY:-}"
      FINNHUB_API_KEY: "${FINNHUB_API_KEY:-}"
      EIA_API_KEY: "${EIA_API_KEY:-}"
      FRED_API_KEY: "${FRED_API_KEY:-}"
      ACLED_EMAIL: "${ACLED_EMAIL:-}"
      ACLED_PASSWORD: "${ACLED_PASSWORD:-}"
      ACLED_ACCESS_TOKEN: "${ACLED_ACCESS_TOKEN:-}"
      NASA_FIRMS_API_KEY: "${NASA_FIRMS_API_KEY:-}"
      CLOUDFLARE_API_TOKEN: "${CLOUDFLARE_API_TOKEN:-}"
      AVIATIONSTACK_API: "${AVIATIONSTACK_API:-}"
      TRAVELPAYOUTS_API_TOKEN: "${TRAVELPAYOUTS_API_TOKEN:-}"
    # Docker secrets (recommended for API keys β€” keeps them out of docker inspect).
    # Create secrets/ dir with one file per key, then uncomment below.
    # See SELF_HOSTING.md or docker-compose.override.yml for details.
    # secrets:
    #   - GROQ_API_KEY
    #   - AISSTREAM_API_KEY
    #   - FINNHUB_API_KEY
    #   - FRED_API_KEY
    #   - NASA_FIRMS_API_KEY
    #   - LLM_API_KEY
    depends_on:
      redis-rest:
        condition: service_started
      ais-relay:
        condition: service_started
    restart: unless-stopped

  ais-relay:
    build:
      context: .
      dockerfile: Dockerfile.relay
    image: worldmonitor-ais-relay:latest
    container_name: worldmonitor-ais-relay
    environment:
      AISSTREAM_API_KEY: "${AISSTREAM_API_KEY:-}"
      FINNHUB_API_KEY: "${FINNHUB_API_KEY:-}"
      MARKET_YAHOO_REFRESH_INTERVAL_MS: "${MARKET_YAHOO_REFRESH_INTERVAL_MS:-900000}"
      UPSTASH_REDIS_REST_URL: "http://redis-rest:80"
      UPSTASH_REDIS_REST_TOKEN: "${REDIS_TOKEN:?REDIS_TOKEN required β€” generate with: openssl rand -hex 32}"
      UPSTASH_ALLOW_INSECURE_HTTP: "true"
      UCDP_ACCESS_TOKEN: "${UCDP_ACCESS_TOKEN:-}"
      PORT: "3004"
    depends_on:
      redis-rest:
        condition: service_started
    restart: unless-stopped

  redis:
    image: docker.io/redis:7-alpine
    container_name: worldmonitor-redis
    # --requirepass closes off the network so any future sidecar / compromised
    # dependency added to the worldmonitor network can't read or write cache
    # entries without the password. Defense-in-depth alongside the REST token.
    command: >
      redis-server
      --requirepass "${REDIS_PASSWORD:?REDIS_PASSWORD required β€” generate with: openssl rand -hex 32}"
      --maxmemory 256mb
      --maxmemory-policy allkeys-lru
    volumes:
      - redis-data:/data
    restart: unless-stopped

  redis-rest:
    build:
      context: docker
      dockerfile: Dockerfile.redis-rest
    image: worldmonitor-redis-rest:latest
    container_name: worldmonitor-redis-rest
    ports:
      - "127.0.0.1:8079:80"
    environment:
      SRH_TOKEN: "${REDIS_TOKEN:?REDIS_TOKEN required β€” generate with: openssl rand -hex 32}"
      # Defense-in-depth: the redis service's --requirepass already fails
      # compose validation if REDIS_PASSWORD is unset, but the explicit
      # :? here protects against a future PR removing --requirepass or
      # copying this connection string into a new service.
      SRH_CONNECTION_STRING: "redis://:${REDIS_PASSWORD:?REDIS_PASSWORD required β€” generate with: openssl rand -hex 32}@redis:6379"
    depends_on:
      - redis
    restart: unless-stopped

# Docker secrets β€” uncomment and point to your secret files.
# Example: echo "gsk_abc123" > secrets/groq_api_key.txt
# secrets:
#   GROQ_API_KEY:
#     file: ./secrets/groq_api_key.txt
#   AISSTREAM_API_KEY:
#     file: ./secrets/aisstream_api_key.txt
#   FINNHUB_API_KEY:
#     file: ./secrets/finnhub_api_key.txt
#   FRED_API_KEY:
#     file: ./secrets/fred_api_key.txt
#   NASA_FIRMS_API_KEY:
#     file: ./secrets/nasa_firms_api_key.txt
#   LLM_API_KEY:
#     file: ./secrets/llm_api_key.txt

volumes:
  redis-data: