diff --git a/infra/deploy/deploy.sh b/infra/deploy/deploy.sh new file mode 100755 index 0000000..f190cbf --- /dev/null +++ b/infra/deploy/deploy.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# Deploy origin/dev to the shared server (ssh alias `vobot`, dir /srv/ptsr). Run from a clean checkout: +# infra/deploy/deploy.sh [git-ref] default: origin/dev +# Keeps /srv/ptsr/.env (secrets live only on the server) and the Postgres volume. +set -euo pipefail +REF=${1:-origin/dev} +HOST=${DEPLOY_HOST:-vobot} +DIR=/srv/ptsr +git fetch -q origin +SHA=$(git rev-parse --short "$REF") +echo "deploy $REF ($SHA) -> $HOST:$DIR" +git archive --format=tar "$REF" | ssh "$HOST" "rm -rf $DIR/app.new && mkdir -p $DIR/app.new && tar -x -C $DIR/app.new" +ssh "$HOST" bash -s < REVISION +docker run --rm -v "\$PWD/web:/w" -w /w node:20-alpine sh -c "npm ci --no-audit --no-fund >/dev/null && npm run build >/dev/null" +docker compose -p ptsr -f docker-compose.yml -f infra/deploy/docker-compose.server.yml up -d --build /dev/null && break; sleep 3; done +curl -sf 127.0.0.1:8010/health && echo " api ok" +SH diff --git a/infra/deploy/docker-compose.server.yml b/infra/deploy/docker-compose.server.yml new file mode 100644 index 0000000..d195ed9 --- /dev/null +++ b/infra/deploy/docker-compose.server.yml @@ -0,0 +1,30 @@ +# Server override (shared host with vobot): loopback-only ports behind host nginx, restart policy, memory caps. +# docker compose -p ptsr -f docker-compose.yml -f infra/deploy/docker-compose.server.yml up -d --build +services: + postgres: + ports: !reset [] + restart: unless-stopped + mem_limit: 512m + + app: + ports: !override + - "127.0.0.1:8010:8000" + restart: unless-stopped + mem_limit: 768m + + dashboard: + command: + - streamlit + - run + - dashboard/app.py + - --server.port=8501 + - --server.address=0.0.0.0 + - --server.baseUrlPath=doctor + - --browser.gatherUsageStats=false + environment: + API_BASE_URL: http://app:8000 + DASHBOARD_PUBLIC_URL: ${PUBLIC_URL:-http://localhost}/doctor + ports: !override + - "127.0.0.1:8511:8501" + restart: unless-stopped + mem_limit: 768m diff --git a/infra/deploy/nginx-meditron.conf b/infra/deploy/nginx-meditron.conf new file mode 100644 index 0000000..ffcfd14 --- /dev/null +++ b/infra/deploy/nginx-meditron.conf @@ -0,0 +1,52 @@ +# meditron.tenvex.ru — PTSRaiAgent prototype (synthetic data only). +# / patient web app (static, web/dist) +# /api/ FastAPI (127.0.0.1:8010) +# /doctor/ Streamlit doctor dashboard + demo console (127.0.0.1:8511, baseUrlPath=doctor) +# TLS: after the DNS A-record exists — certbot --nginx -d meditron.tenvex.ru + +map $http_upgrade $ptsr_connection_upgrade { + default upgrade; + '' close; +} + +server { + listen 80; + listen [::]:80; + server_name meditron.tenvex.ru; + + access_log /var/log/nginx/ptsr-access.log; + client_max_body_size 5m; + + root /srv/ptsr/app/web/dist; + index index.html; + + location / { + try_files $uri $uri/ /index.html; + } + + location /api/ { + proxy_pass http://127.0.0.1:8010; + 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_read_timeout 120s; # chat agent + scheduler replay on clock advance + } + + location ~ ^/(docs|openapi.json|health)$ { + proxy_pass http://127.0.0.1:8010; + proxy_set_header Host $host; + } + + location /doctor/ { + proxy_pass http://127.0.0.1:8511; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $ptsr_connection_upgrade; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 86400s; + proxy_buffering off; + } +}