diff --git a/deploy_lang.sh b/deploy_lang.sh index 9e32280..781824f 100755 --- a/deploy_lang.sh +++ b/deploy_lang.sh @@ -1,16 +1,26 @@ #!/bin/bash set -e +VM="root@95.179.252.111" +SSH="ssh -i ~/.ssh/vultr_openssh -o StrictHostKeyChecking=no" -# Собираем dist/index.html (CSS + JS встроены) -~/lang/.venv/bin/python3 ~/lang/build.sh +echo "=== rsync repo -> VM ===" +rsync -az -e "$SSH" --exclude='.git' --exclude='.venv' --exclude='__pycache__' ~/lang/ ${VM}:/opt/lyngvo/ -# Вклеиваем Groq API ключ в dist/index.html -KEY=$(cat ~/lang/token.txt) -cp ~/lang/dist/index.html /tmp/lyngvo_index.html -sed -i "s|const GROQ_API_KEY = '';|const GROQ_API_KEY = '${KEY}';|" /tmp/lyngvo_index.html +echo "=== build + deploy ===" +$SSH $VM "bash -c ' + cd /opt/lyngvo + python3 build.sh + KEY=\$(cat token.txt) + sed -i \"s|const GROQ_API_KEY = .*;|const GROQ_API_KEY = '\\\''\$KEY'\\\'';|\" dist/index.html + cp dist/index.html /var/www/lyngvo/index.html + if [ -f server/lang.kube5s.ru.conf ]; then + cp server/lang.kube5s.ru.conf /etc/nginx/conf.d/ + nginx -t && systemctl reload nginx + fi + if [ -f server/proxy.py ]; then + cp server/proxy.py /opt/groq-proxy/proxy.py + systemctl reload groq-proxy 2>/dev/null || true + fi +'" -# Деплой на германскую ВМ (nginx + Groq прокси) -scp -i ~/.ssh/vultr_openssh -o StrictHostKeyChecking=no /tmp/lyngvo_index.html root@95.179.252.111:/var/www/lyngvo/index.html - -rm -f /tmp/lyngvo_index.html -echo "\n=== Деплой завершён. Проверяй https://lang.kube5s.ru ===" +echo "=== https://lang.kube5s.ru ===" diff --git a/server/lang.kube5s.ru.conf b/server/lang.kube5s.ru.conf new file mode 100644 index 0000000..fd7e60f --- /dev/null +++ b/server/lang.kube5s.ru.conf @@ -0,0 +1,40 @@ +# Lyngvo — тренажёр произношения +server { + listen 80; + server_name lang.kube5s.ru; + location /.well-known/acme-challenge/ { root /var/www/certbot; } + location / { return 301 https://$host$request_uri; } +} +server { + listen 443 ssl; + http2 on; + server_name lang.kube5s.ru; + + ssl_certificate /etc/letsencrypt/live/lang.kube5s.ru/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/lang.kube5s.ru/privkey.pem; + + root /var/www/lyngvo; + index index.html; + + location / { + try_files $uri $uri/ /index.html; + } + + # Groq API proxy + location /openai/ { + proxy_pass http://127.0.0.1:8765; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_read_timeout 120s; + proxy_send_timeout 120s; + proxy_request_buffering off; + } + + # Будущий бэкенд (Python/Go) + location /api/ { + proxy_pass http://127.0.0.1:8080; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_read_timeout 120s; + } +} diff --git a/server/proxy.py b/server/proxy.py new file mode 100644 index 0000000..f2e9ba8 --- /dev/null +++ b/server/proxy.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 +from flask import Flask, request, Response +import requests + +app = Flask(__name__) +GROQ_BASE = "https://api.groq.com" + +CORS = { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "GET, POST, OPTIONS", + "Access-Control-Allow-Headers": "Authorization, Content-Type", +} + +@app.route("/", methods=["OPTIONS"]) +def options(path): + return Response(status=204, headers=CORS) + +# Generic proxy for ALL Groq paths +@app.route("/", methods=["GET", "POST", "PUT", "DELETE", "PATCH"]) +def proxy(subpath): + url = f"{GROQ_BASE}/{subpath}" + hdrs = {} + if request.headers.get("Authorization"): + hdrs["Authorization"] = request.headers["Authorization"] + if request.headers.get("Content-Type"): + hdrs["Content-Type"] = request.headers["Content-Type"] + r = requests.request(request.method, url, headers=hdrs, + data=request.get_data(), timeout=60, stream=True) + out = dict(CORS) + out["Content-Type"] = r.headers.get("Content-Type", "application/json") + return Response(r.iter_content(8192), status=r.status_code, headers=out) + +if __name__ == "__main__": + app.run(host="127.0.0.1", port=8765)