- Главная: тихая кнопка «Помахать» (web/js/wave.js), общий счётчик для всех посетителей - server/server.mjs: мини-API (/api/waves, /api/wave), счётчик хранится вне репозитория (/var/lib/vizitka-site/waves.json), лимит раз в секунду с IP, проверка Origin - deploy: systemd-сервис vizitka-api, проксирование /api в nginx, setup-server.sh ставит nodejs - CI: после git pull перезапускает API - Домен https://me.ibrash.duckdns.org вместо заглушки, исправлен пробел в шапке - README и заметки обновлены Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,14 @@ server {
|
||||
root /opt/vizitka-site/web;
|
||||
index index.html;
|
||||
|
||||
# реальный IP посетителя из X-Forwarded-For, если запрос пришёл от прокси из локальной сети (для лимита в API)
|
||||
set_real_ip_from 10.0.0.0/8;
|
||||
set_real_ip_from 172.16.0.0/12;
|
||||
set_real_ip_from 192.168.0.0/16;
|
||||
set_real_ip_from 127.0.0.0/8;
|
||||
real_ip_header X-Forwarded-For;
|
||||
real_ip_recursive on;
|
||||
|
||||
# сжатие
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
@@ -20,6 +28,16 @@ server {
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always;
|
||||
|
||||
# API кнопки «Помахать» (Node, systemd-сервис vizitka-api), счётчик хранится вне репозитория
|
||||
location /api/ {
|
||||
proxy_pass http://127.0.0.1:8787;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Client-IP $remote_addr;
|
||||
proxy_read_timeout 10s;
|
||||
client_max_body_size 1k;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
+24
-6
@@ -1,19 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
# Разовая подготовка сервера: nginx, git, клон репозитория в /opt/vizitka-site. Безопасно запускать повторно.
|
||||
# Использование: ./deploy/setup-server.sh root@192.168.10.112
|
||||
# Разовая подготовка сервера: nginx, git, nodejs, клон репозитория в /opt/vizitka-site, сервис API счётчика.
|
||||
# Безопасно запускать повторно. Использование: ./deploy/setup-server.sh root@192.168.10.112
|
||||
# Обновления потом приходят через `git pull` (его делает CI, см. .gitea/workflows/deploy.yml).
|
||||
set -euo pipefail
|
||||
TARGET="${1:?укажите сервер: ./deploy/setup-server.sh root@192.168.10.112}"
|
||||
REPO_URL="${REPO_URL:-https://git.ibrash.duckdns.org/aibrash/vizitka-site.git}" # репозиторий публичный: ключи не нужны
|
||||
# откуда разрешены POST к API (домен сайта и адрес в локальной сети)
|
||||
ORIGINS="${ORIGINS:-https://me.ibrash.duckdns.org,http://me.ibrash.duckdns.org,http://192.168.10.112}"
|
||||
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
scp -q "$HERE/nginx-site.conf" "$TARGET:/tmp/vizitka-nginx.conf"
|
||||
ssh "$TARGET" "REPO_URL='$REPO_URL' bash -s" <<'REMOTE'
|
||||
scp -q "$HERE/vizitka-api.service" "$TARGET:/tmp/vizitka-api.service"
|
||||
ssh "$TARGET" "REPO_URL='$REPO_URL' ORIGINS='$ORIGINS' bash -s" <<'REMOTE'
|
||||
set -euo pipefail
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
if ! command -v nginx >/dev/null || ! command -v git >/dev/null; then
|
||||
if ! command -v nginx >/dev/null || ! command -v git >/dev/null || ! command -v node >/dev/null; then
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq nginx git >/dev/null
|
||||
apt-get install -y -qq nginx git nodejs >/dev/null
|
||||
fi
|
||||
|
||||
DIR=/opt/vizitka-site
|
||||
@@ -24,11 +27,26 @@ else
|
||||
git clone "$REPO_URL" "$DIR"
|
||||
fi
|
||||
|
||||
# сервис API: настройки лежат вне репозитория; существующий файл не перезаписываем
|
||||
if [ ! -f /etc/vizitka-api.env ]; then
|
||||
cat > /etc/vizitka-api.env <<ENV
|
||||
PORT=8787
|
||||
HOST=127.0.0.1
|
||||
DATA_FILE=/var/lib/vizitka-site/waves.json
|
||||
ALLOWED_ORIGINS=$ORIGINS
|
||||
TRUST_PROXY=1
|
||||
ENV
|
||||
fi
|
||||
install -m 644 /tmp/vizitka-api.service /etc/systemd/system/vizitka-api.service
|
||||
systemctl daemon-reload
|
||||
systemctl enable vizitka-api >/dev/null 2>&1
|
||||
systemctl restart vizitka-api
|
||||
|
||||
install -m 644 /tmp/vizitka-nginx.conf /etc/nginx/sites-available/vizitka-site
|
||||
ln -sf /etc/nginx/sites-available/vizitka-site /etc/nginx/sites-enabled/vizitka-site
|
||||
rm -f /etc/nginx/sites-enabled/default
|
||||
nginx -t
|
||||
systemctl enable --now nginx >/dev/null 2>&1
|
||||
systemctl reload nginx
|
||||
echo "готово: nginx $(nginx -v 2>&1 | cut -d/ -f2), сайт: $DIR/web (коммит $(git -C "$DIR" rev-parse --short HEAD))"
|
||||
echo "готово: nginx $(nginx -v 2>&1 | cut -d/ -f2), node $(node --version), сайт $DIR/web (коммит $(git -C "$DIR" rev-parse --short HEAD)), API: $(systemctl is-active vizitka-api)"
|
||||
REMOTE
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
[Unit]
|
||||
Description=vizitka-site API (счётчик «Помахать»)
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
# отдельный временный пользователь без прав; каталог /var/lib/vizitka-site создаётся сам и переживает пуши и перезапуски
|
||||
DynamicUser=yes
|
||||
StateDirectory=vizitka-site
|
||||
EnvironmentFile=/etc/vizitka-api.env
|
||||
ExecStart=/usr/bin/node /opt/vizitka-site/server/server.mjs
|
||||
Restart=on-failure
|
||||
RestartSec=3
|
||||
|
||||
# песочница
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
PrivateDevices=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
ProtectKernelTunables=true
|
||||
ProtectKernelModules=true
|
||||
ProtectControlGroups=true
|
||||
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
|
||||
RestrictNamespaces=true
|
||||
LockPersonality=true
|
||||
MemoryMax=96M
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in New Issue
Block a user