germany: server/ конфиги в репе, deploy_lang.sh → rsync + build на ВМ
This commit is contained in:
+21
-11
@@ -1,16 +1,26 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -e
|
set -e
|
||||||
|
VM="root@95.179.252.111"
|
||||||
|
SSH="ssh -i ~/.ssh/vultr_openssh -o StrictHostKeyChecking=no"
|
||||||
|
|
||||||
# Собираем dist/index.html (CSS + JS встроены)
|
echo "=== rsync repo -> VM ==="
|
||||||
~/lang/.venv/bin/python3 ~/lang/build.sh
|
rsync -az -e "$SSH" --exclude='.git' --exclude='.venv' --exclude='__pycache__' ~/lang/ ${VM}:/opt/lyngvo/
|
||||||
|
|
||||||
# Вклеиваем Groq API ключ в dist/index.html
|
echo "=== build + deploy ==="
|
||||||
KEY=$(cat ~/lang/token.txt)
|
$SSH $VM "bash -c '
|
||||||
cp ~/lang/dist/index.html /tmp/lyngvo_index.html
|
cd /opt/lyngvo
|
||||||
sed -i "s|const GROQ_API_KEY = '';|const GROQ_API_KEY = '${KEY}';|" /tmp/lyngvo_index.html
|
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 прокси)
|
echo "=== https://lang.kube5s.ru ==="
|
||||||
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 ==="
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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("/<path:path>", methods=["OPTIONS"])
|
||||||
|
def options(path):
|
||||||
|
return Response(status=204, headers=CORS)
|
||||||
|
|
||||||
|
# Generic proxy for ALL Groq paths
|
||||||
|
@app.route("/<path:subpath>", 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)
|
||||||
Reference in New Issue
Block a user