docker-compose.yml 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. services:
  2. qdrant:
  3. image: qdrant/qdrant:latest
  4. container_name: modulos-qdrant
  5. ports:
  6. - "6333:6333"
  7. - "6334:6334"
  8. volumes:
  9. - ./qdrant_storage:/qdrant/storage
  10. restart: unless-stopped
  11. healthcheck:
  12. test:
  13. [
  14. "CMD-SHELL",
  15. "if command -v curl >/dev/null 2>&1; then curl -fsS http://localhost:6333/readyz >/dev/null; \
  16. elif command -v wget >/dev/null 2>&1; then wget -qO- http://localhost:6333/readyz >/dev/null; \
  17. else bash -lc \"exec 3<>/dev/tcp/127.0.0.1/6333; printf 'GET /readyz HTTP/1.0\\r\\n\\r\\n' >&3; head -n1 <&3 | grep -q '200'\"; fi"
  18. ]
  19. interval: 20s
  20. timeout: 5s
  21. retries: 5
  22. backend:
  23. build: ./backend
  24. container_name: modulos-backend
  25. ports:
  26. - "2281:8000"
  27. command: >
  28. bash -lc '
  29. set -euo pipefail;
  30. exec uvicorn app:app --host 0.0.0.0 --port 8000
  31. '
  32. user: "10001:10001" # run as appuser at runtime
  33. environment:
  34. # point to your Windows Ollama box
  35. - OLLAMA_URL=http://192.168.8.73:11434
  36. # talk to qdrant inside this compose
  37. - QDRANT_URL=http://qdrant:6333
  38. # defaults for collection/models (override if you like)
  39. - QDRANT_COLLECTION=planning_docs
  40. - EMBED_MODEL=nomic-embed-text
  41. - CHAT_MODEL=llama3.1:8b-instruct-q5_K_M
  42. #- CHAT_MODEL=llama3.1:8b
  43. # optional CORS, comma-separated list
  44. - CORS_ORIGINS=http://localhost:3000,http://192.168.8.69:2380,https://llm.modulos.com.au,https://api.modulos.com.au,https://tasplanning.report
  45. # Optional demo gate:
  46. - DEMO_REQUIRE_TOKEN=0
  47. - DEMO_TOKEN=DHv2xUx7vWzGg3O8UihDbUVQ7Svrub1FJXHv2Y3jyOTRrOTO19cLytm3b8Y8A6eC
  48. - TPR_DB=/data/telemetry.db
  49. - TPR_IP_SECRET=${TPR_IP_SECRET:-mmOwQgqljUs1CPiKW3O9vvL4XGalAHojOEmB7SJLBxXBPXHbBoDCMyS8fPc62aDk}
  50. depends_on:
  51. qdrant:
  52. condition: service_healthy
  53. volumes:
  54. - ./backend:/app
  55. - /home/modulos_llm/telemetry_data:/data
  56. restart: unless-stopped
  57. healthcheck:
  58. test: ["CMD", "curl", "-f", "http://localhost:8000/readyz"]
  59. interval: 20s
  60. timeout: 3s
  61. retries: 5
  62. web:
  63. build:
  64. context: .
  65. dockerfile: ./web/Dockerfile
  66. container_name: modulos-web
  67. ports:
  68. - "2380:80"
  69. volumes:
  70. - ./public:/var/www/html
  71. - cache:/var/www/html/cache
  72. - /home/modulos_llm/telemetry_data:/data
  73. environment:
  74. - TPR_DB=/data/telemetry.db
  75. - DEBIAN_FRONTEND=noninteractive
  76. - GOOGLE_APPLICATION_CREDENTIALS=/var/www/secure/service-account.json
  77. - GDOC_PARENT_ID=1Zkv6eThu-3szvRpug3fXiAuTDWLsWxxl
  78. - GDOC_SHARE_EMAIL=modulos.aust@gmail.com
  79. - GMAPS_API_KEY=${GMAPS_API_KEY}
  80. - SMTP_HOST=mail.modulos.com.au
  81. - SMTP_PORT=465
  82. - SMTP_USER=no-reply@modulos.com.au
  83. - SMTP_PASS=${SMTP_PASS}
  84. - SMTP_FROM=no-reply@modulos.com.au
  85. - SMTP_FROM_NAME=Tas Planning Assistant
  86. - NOTIFY_EMAIL=ben@modulos.com.au
  87. - APP_API_BASE=https://api.modulos.com.au/ask
  88. - CORS_ORIGINS=${CORS_ORIGINS:-https://tasplanning.report,https://modulosdesign.com.au,https://llm.modulos.com.au}
  89. - APP_ENV=${APP_ENV:-production}
  90. depends_on:
  91. - backend
  92. restart: unless-stopped
  93. command: >
  94. bash -lc '
  95. set -euo pipefail;
  96. apt-get update -y;
  97. apt-get install -y --no-install-recommends git unzip libzip-dev netcat-openbsd;
  98. rm -rf /var/lib/apt/lists/*;
  99. a2enmod rewrite headers >/dev/null || true;
  100. # Only build zip if not loaded
  101. php -m | grep -qi "^zip$" || docker-php-ext-install zip;
  102. # Write clean confs (printf avoids YAML here-doc pitfalls)
  103. printf "%s\n" "<Directory \"/var/www/html\">" \
  104. " AllowOverride All" \
  105. " Require all granted" \
  106. "</Directory>" \
  107. > /etc/apache2/conf-enabled/allowoverride.conf
  108. printf "%s\n" "SetEnvIfNoCase X-Forwarded-Proto ^https$ HTTPS=on" \
  109. > /etc/apache2/conf-enabled/proxy-https.conf
  110. # Extra: set HTTPS via mod_rewrite for libs reading env later
  111. printf "%s\n" "RewriteEngine On" \
  112. "RewriteCond %{HTTP:X-Forwarded-Proto} =https" \
  113. "RewriteRule .* - [E=HTTPS:on]" \
  114. > /etc/apache2/conf-enabled/rewrite-https.conf
  115. printf "ServerName localhost\n" > /etc/apache2/conf-enabled/servername.conf
  116. printf "PassEnv GMAPS_API_KEY\nPassEnv CORS_ORIGINS\nPassEnv APP_ENV\n" > /etc/apache2/conf-enabled/passenv.conf;
  117. chown -R www-data:www-data /var/www/html/cache || true;
  118. apachectl -t;
  119. exec apache2-foreground
  120. '
  121. sqliteweb:
  122. image: coleifer/sqlite-web:latest
  123. container_name: modulos-sqliteweb
  124. depends_on:
  125. - backend
  126. user: "10001:10001"
  127. volumes:
  128. - /home/modulos_llm/telemetry_data:/data # same volume the backend uses
  129. # external: true
  130. environment:
  131. - SQLITE_DATABASE=telemetry.db # looks for /data/telemetry.db
  132. # optional: protect with a password
  133. # - SQLITE_WEB_PASSWORD=${SQLITE_WEB_PASSWORD:-}
  134. ports:
  135. - "8091:8080"
  136. restart: unless-stopped
  137. composer:
  138. build:
  139. context: .
  140. dockerfile: ./web/Dockerfile
  141. working_dir: /app
  142. volumes:
  143. - ./public:/app
  144. # external: true
  145. command: ["composer", "install", "--no-interaction", "--no-progress", "--prefer-dist"]
  146. restart: unless-stopped
  147. depends_on:
  148. - web
  149. volumes:
  150. cache:
  151. external: true
  152. name: modulos_llm_cache
  153. telemetry_data: {}