main
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
# ZBrain Development Docker Compose
|
||||
#
|
||||
# Только Postgres - всё остальное запускается нативно через bun/node.
|
||||
#
|
||||
# Запуск:
|
||||
# docker compose -f deploy/docker/docker-compose.dev.yml up -d
|
||||
#
|
||||
# Подключение:
|
||||
# psql postgresql://zbrain:dev@localhost:5432/brainhub_dev
|
||||
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: pgvector/pgvector:pg16
|
||||
container_name: zbrain-postgres-dev
|
||||
restart: unless-stopped
|
||||
|
||||
environment:
|
||||
POSTGRES_USER: zbrain
|
||||
POSTGRES_PASSWORD: dev
|
||||
POSTGRES_DB: brainhub_dev
|
||||
|
||||
ports:
|
||||
- "127.0.0.1:5432:5432"
|
||||
|
||||
volumes:
|
||||
- postgres-dev-data:/var/lib/postgresql/data
|
||||
- ./init-dev.sql:/docker-entrypoint-initdb.d/init.sql:ro
|
||||
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U zbrain"]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 5
|
||||
|
||||
# Опционально - adminer для просмотра БД через браузер
|
||||
adminer:
|
||||
image: adminer:latest
|
||||
container_name: zbrain-adminer-dev
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "127.0.0.1:8081:8080"
|
||||
environment:
|
||||
ADMINER_DEFAULT_SERVER: postgres
|
||||
ADMINER_DESIGN: pepa-linha-dark
|
||||
|
||||
volumes:
|
||||
postgres-dev-data:
|
||||
driver: local
|
||||
@@ -0,0 +1,78 @@
|
||||
# ZBrain Production Docker Compose
|
||||
#
|
||||
# Запуск:
|
||||
# docker compose -f deploy/docker/docker-compose.yml up -d
|
||||
#
|
||||
# Postgres работает на хосте (не в контейнере) - так проще делать
|
||||
# нативный pg_dump, тюнинг и обновления без даунтайма всех брейнов.
|
||||
# gbrain instances тоже работают через systemd на хосте.
|
||||
# В контейнерах - только brainhub (api + web) и nginx.
|
||||
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
# ============================================================
|
||||
# Brainhub API (Node.js + Express)
|
||||
# ============================================================
|
||||
brainhub-api:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: deploy/docker/api.Dockerfile
|
||||
image: zbrain/brainhub-api:latest
|
||||
container_name: zbrain-api
|
||||
restart: unless-stopped
|
||||
|
||||
# Postgres на хосте, поэтому используем host network для api
|
||||
# ИЛИ - оставляем bridge и в DATABASE_URL пишем host.docker.internal
|
||||
network_mode: host
|
||||
|
||||
env_file:
|
||||
- /etc/zbrain/.env
|
||||
|
||||
environment:
|
||||
NODE_ENV: production
|
||||
LOG_FILE: /var/log/zbrain/brainhub.log
|
||||
|
||||
volumes:
|
||||
- /var/log/zbrain:/var/log/zbrain
|
||||
- /etc/zbrain:/etc/zbrain:ro
|
||||
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3000/health"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "5"
|
||||
|
||||
# ============================================================
|
||||
# Brainhub Web (статика через nginx внутри контейнера)
|
||||
# ============================================================
|
||||
brainhub-web:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: deploy/docker/web.Dockerfile
|
||||
image: zbrain/brainhub-web:latest
|
||||
container_name: zbrain-web
|
||||
restart: unless-stopped
|
||||
|
||||
ports:
|
||||
- "127.0.0.1:8080:80" # только localhost, внешний доступ через системный nginx
|
||||
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "5"
|
||||
|
||||
# ============================================================
|
||||
# Networks
|
||||
# ============================================================
|
||||
# brainhub-api использует host network для прямого доступа к Postgres
|
||||
# и к gbrain instances (localhost:3001-3099).
|
||||
# brainhub-web стоит на bridge с port forward на 127.0.0.1:8080.
|
||||
@@ -0,0 +1,17 @@
|
||||
-- ZBrain Dev Postgres Init
|
||||
-- Создаёт расширения и тестовые БД для локальной разработки
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS vector;
|
||||
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
||||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
|
||||
-- Тестовая БД для gbrain
|
||||
CREATE DATABASE gbrain_dev OWNER zbrain;
|
||||
\c gbrain_dev
|
||||
CREATE EXTENSION IF NOT EXISTS vector;
|
||||
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
||||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||
|
||||
\c brainhub_dev
|
||||
-- В brainhub_dev расширения уже созданы выше, миграции прокатятся через приложение
|
||||
@@ -0,0 +1,189 @@
|
||||
# ZBrain Nginx Configuration
|
||||
# ===========================
|
||||
# Два server-блока:
|
||||
# 1. Внутренний (brain.zetit.local) - полный доступ к UI и API
|
||||
# 2. Публичный (brain.zetit.ru) - только /mcp/* и /oauth/*
|
||||
#
|
||||
# Положить в /etc/nginx/sites-available/zbrain
|
||||
# и сделать symlink в /etc/nginx/sites-enabled/
|
||||
|
||||
# ============================================================
|
||||
# Upstream'ы
|
||||
# ============================================================
|
||||
upstream brainhub_api {
|
||||
server 127.0.0.1:3000;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
upstream brainhub_api_public {
|
||||
server 127.0.0.1:3010;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
upstream brainhub_web {
|
||||
server 127.0.0.1:8080;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
# Rate limiting для публичного MCP
|
||||
limit_req_zone $binary_remote_addr zone=mcp_public:10m rate=30r/s;
|
||||
limit_req_zone $http_authorization zone=mcp_token:10m rate=100r/s;
|
||||
|
||||
# ============================================================
|
||||
# Внутренний контур: brain.zetit.local
|
||||
# ============================================================
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name brain.zetit.local;
|
||||
|
||||
# Внутри сети можно без HTTPS, либо self-signed cert
|
||||
# Если нужен HTTPS - раскомментировать listen 443 ниже и убрать listen 80
|
||||
|
||||
access_log /var/log/nginx/zbrain-internal.access.log;
|
||||
error_log /var/log/nginx/zbrain-internal.error.log;
|
||||
|
||||
client_max_body_size 50M;
|
||||
|
||||
# Web UI (статика)
|
||||
location / {
|
||||
proxy_pass http://brainhub_web;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# API
|
||||
location /api/ {
|
||||
proxy_pass http://brainhub_api;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header Connection "";
|
||||
|
||||
# Таймауты для долгих операций (sync, import)
|
||||
proxy_read_timeout 300s;
|
||||
proxy_send_timeout 300s;
|
||||
}
|
||||
|
||||
# SSE events
|
||||
location /api/events {
|
||||
proxy_pass http://brainhub_api;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection "";
|
||||
proxy_buffering off;
|
||||
proxy_cache off;
|
||||
proxy_read_timeout 24h;
|
||||
|
||||
# SSE headers
|
||||
chunked_transfer_encoding off;
|
||||
}
|
||||
|
||||
# MCP - внутренний доступ (тоже с токенами, но без rate limit)
|
||||
location /mcp/ {
|
||||
proxy_pass http://brainhub_api;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header Authorization $http_authorization;
|
||||
|
||||
proxy_read_timeout 120s;
|
||||
proxy_buffering off;
|
||||
}
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# Публичный контур: brain.zetit.ru
|
||||
# ============================================================
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name brain.zetit.ru;
|
||||
|
||||
# HTTP -> HTTPS redirect (кроме ACME challenge)
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/certbot;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
server_name brain.zetit.ru;
|
||||
|
||||
# TLS
|
||||
ssl_certificate /etc/letsencrypt/live/brain.zetit.ru/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/brain.zetit.ru/privkey.pem;
|
||||
ssl_session_timeout 1d;
|
||||
ssl_session_cache shared:MozSSL:10m;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers off;
|
||||
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
|
||||
|
||||
# HSTS
|
||||
add_header Strict-Transport-Security "max-age=63072000" always;
|
||||
|
||||
# Security headers
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-Frame-Options "DENY" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
|
||||
access_log /var/log/nginx/zbrain-public.access.log;
|
||||
error_log /var/log/nginx/zbrain-public.error.log;
|
||||
|
||||
client_max_body_size 10M;
|
||||
|
||||
# ВАЖНО: на публичном контуре доступны только /mcp/* и /oauth/*
|
||||
# Никакого UI, API админки и т.д.
|
||||
|
||||
# MCP proxy с rate limiting
|
||||
location /mcp/ {
|
||||
# Лимит по IP - защита от подбора токенов
|
||||
limit_req zone=mcp_public burst=60 nodelay;
|
||||
# Лимит по токену - защита от взбесившегося скрипта
|
||||
limit_req zone=mcp_token burst=200 nodelay;
|
||||
limit_req_status 429;
|
||||
|
||||
proxy_pass http://brainhub_api_public;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header Authorization $http_authorization;
|
||||
|
||||
proxy_read_timeout 120s;
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
# OAuth flow для удалённой авторизации
|
||||
location /oauth/ {
|
||||
limit_req zone=mcp_public burst=20 nodelay;
|
||||
|
||||
proxy_pass http://brainhub_api_public;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Health check (без rate limit, для мониторинга)
|
||||
location /health {
|
||||
proxy_pass http://brainhub_api_public/health;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
# Всё остальное - 404, чтобы публично ничего лишнего не светить
|
||||
location / {
|
||||
return 404;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user