feat: CI/CD, per-domain HTTPS, backup, config generator
- sites.yml — единый источник истины для всех сайтов - generate-configs.sh — генератор nginx конфигов, certbot domains.txt, .env - nginx: per-domain HTTPS (вместо all-or-nothing switch-config) - certbot: единый renew-all.sh, динамический init (без 5 дублирующих скриптов) - backup: контейнер с pg_dump + rclone (Яндекс.Диск), ежедневно в 3AM - Gitea + Gitea Runner в docker-compose (self-hosted Git + CI/CD) - .gitea/workflows/deploy.yml — CI/CD pipeline: push → авто-деплой - Makefile: generate-configs, reconfig, deploy, backup, restore, gitea, help
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
name: Deploy
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'main_dc/**'
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Deploy
|
||||
run: |
|
||||
cd /home/gaziz/artefacts/tp/main_dc
|
||||
git pull origin main
|
||||
|
||||
# Если изменился sites.yml — генерируем конфиги
|
||||
if git diff --name-only HEAD~1 HEAD | grep -q 'main_dc/sites.yml'; then
|
||||
echo "→ sites.yml changed, generating configs..."
|
||||
bash generate-configs.sh
|
||||
fi
|
||||
|
||||
# Авто-детект и пересборка изменённых сервисов
|
||||
echo "→ Detecting changed services..."
|
||||
CHANGED=$(git diff --name-only HEAD~1 HEAD | grep -oP 'main_dc/\K[^/]+' | sort -u)
|
||||
for svc in $CHANGED; do
|
||||
svc_name="$svc"
|
||||
# маппинг директорий на имена compose-сервисов
|
||||
case "$svc" in
|
||||
BB) svc_name="api_bb" ;;
|
||||
valitovgaziz) svc_name="valitovgaziz" ;;
|
||||
nginx|certbot|backup|gitea) svc_name="$svc" ;;
|
||||
api_bb|api_yal|analytics|db) svc_name="$svc" ;;
|
||||
yalarba) svc_name="yalarba" ;;
|
||||
*) svc_name="" ;;
|
||||
esac
|
||||
if [ -n "$svc_name" ] && grep -q "^ $svc_name:" docker-compose.yml; then
|
||||
echo " → Rebuilding $svc_name..."
|
||||
make stop_$svc_name build_$svc_name start_$svc_name || \
|
||||
make stop_$svc build_$svc start_$svc 2>/dev/null || \
|
||||
true
|
||||
fi
|
||||
done
|
||||
|
||||
# Nginx всегда перезапускаем если изменились конфиги
|
||||
if echo "$CHANGED" | grep -q 'nginx\|sites.yml'; then
|
||||
echo " → Reloading nginx..."
|
||||
docker compose exec -T nginx nginx -s reload 2>/dev/null || \
|
||||
docker compose restart nginx
|
||||
fi
|
||||
+6
-7
@@ -1,12 +1,11 @@
|
||||
#CERTBOT NGINX VARIABLES
|
||||
|
||||
EMAIL=valitovgaziz@yandex.ru
|
||||
DOMAINS_yalarba=yalarba.ru,www.yalarba.ru
|
||||
DOMAINS_valitovgaziz=valitovgaziz.ru,www.valitovgaziz.ru
|
||||
DOMAINS_easysite102=easysite102.ru,www.easysite102.ru
|
||||
DOMAINS_begushiybashkir=xn--80abahjtcfl5d0a8di.xn--p1ai,www.xn--80abahjtcfl5d0a8di.xn--p1ai
|
||||
DOMAINS_begushiybashkir_latin=begushiybashkir.ru,www.begushiybashkir.ru
|
||||
#CERTBOT NGINX VARIABLES — авто-сгенерировано, не редактировать вручную
|
||||
ALL_DOMAINS=yalarba.ru,www.yalarba.ru,valitovgaziz.ru,www.valitovgaziz.ru,easysite102.ru,www.easysite102.ru,begushiybashkir.ru,www.begushiybashkir.ru,xn--80abahjtcfl5d0a8di.xn--p1ai,www.xn--80abahjtcfl5d0a8di.xn--p1ai
|
||||
DOMAINS_begushiybashkir=begushiybashkir.ru,www.begushiybashkir.ru
|
||||
DOMAINS_begushiybashkir_idn=xn--80abahjtcfl5d0a8di.xn--p1ai,www.xn--80abahjtcfl5d0a8di.xn--p1ai
|
||||
DOMAINS_easysite102=easysite102.ru,www.easysite102.ru
|
||||
DOMAINS_valitovgaziz=valitovgaziz.ru,www.valitovgaziz.ru
|
||||
DOMAINS_yalarba=yalarba.ru,www.yalarba.ru
|
||||
|
||||
# keycloak
|
||||
KEYCLOAK_ADMIN_PASSWORD=your_secure_password
|
||||
|
||||
@@ -238,3 +238,120 @@ start_yalarba:
|
||||
|
||||
# Полный цикл обновления yalarba-nuxt
|
||||
yalarba: stop_yalarba git build_yalarba start_yalarba wn
|
||||
|
||||
# ═══════════════════════════════════════════════
|
||||
# НОВЫЕ ЦЕЛИ: generate-configs, deploy, backup
|
||||
# ═══════════════════════════════════════════════
|
||||
|
||||
# Генерация конфигов из sites.yml
|
||||
generate-configs:
|
||||
bash generate-configs.sh
|
||||
|
||||
# Генерация + рестарт nginx
|
||||
reconfig: generate-configs
|
||||
docker compose restart nginx
|
||||
$(MAKE) wn
|
||||
|
||||
# Авто-детект изменённых сервисов и деплой только их
|
||||
deploy: git
|
||||
@echo "=== Detecting changes ==="
|
||||
@CHANGED=$$(git diff --name-only HEAD~1 HEAD | grep -oP 'main_dc/\K[^/]+' | sort -u); \
|
||||
for svc in $$CHANGED; do \
|
||||
case "$$svc" in \
|
||||
BB) name="api_bb" ;; \
|
||||
certbot) name="certbot" ;; \
|
||||
backup) name="backup" ;; \
|
||||
gitea) name="gitea" ;; \
|
||||
*) name="$$svc" ;; \
|
||||
esac; \
|
||||
if grep -q "^ $$name:" docker-compose.yml 2>/dev/null; then \
|
||||
echo " → Rebuilding $$name..."; \
|
||||
$(MAKE) stop_$$name build_$$name start_$$name 2>/dev/null || \
|
||||
$(MAKE) stop_$$svc build_$$svc start_$$svc 2>/dev/null || true; \
|
||||
fi; \
|
||||
done; \
|
||||
if echo "$$CHANGED" | grep -q 'sites.yml\|nginx'; then \
|
||||
echo " → Regenerating configs..."; \
|
||||
bash generate-configs.sh; \
|
||||
docker compose restart nginx; \
|
||||
fi
|
||||
|
||||
# Ручной запуск бэкапа
|
||||
backup:
|
||||
docker compose exec backup /opt/backup.sh
|
||||
|
||||
# Ручной запуск бэкапа (разовый контейнер)
|
||||
backup-run:
|
||||
docker compose run --rm backup /opt/backup.sh
|
||||
|
||||
# Восстановление из бэкапа: make restore [DATE=2026-06-11]
|
||||
restore:
|
||||
docker compose run --rm backup /opt/restore.sh $(DATE)
|
||||
|
||||
# Gitea — полный цикл обновления
|
||||
gitea: stop_gitea git build_gitea start_gitea wn
|
||||
|
||||
stop_gitea:
|
||||
docker compose down gitea
|
||||
|
||||
build_gitea:
|
||||
docker compose build gitea --no-cache
|
||||
|
||||
start_gitea:
|
||||
docker compose up gitea -d
|
||||
|
||||
# Gitea Runner — полный цикл
|
||||
gitea-runner: stop_gitea-runner git build_gitea-runner start_gitea-runner wn
|
||||
|
||||
stop_gitea-runner:
|
||||
docker compose down gitea-runner
|
||||
|
||||
build_gitea-runner:
|
||||
docker compose build gitea-runner --no-cache
|
||||
|
||||
start_gitea-runner:
|
||||
docker compose up gitea-runner -d
|
||||
|
||||
# Gitea first-time setup helper
|
||||
gitea-setup:
|
||||
@echo "=== Gitea Setup ==="
|
||||
@echo "1. Open http://94.41.23.97:3001 in browser"
|
||||
@echo "2. Complete initial setup (DB: SQLite3 is fine)"
|
||||
@echo "3. Create admin user"
|
||||
@echo "4. Create new repository 'tp' and push:"
|
||||
@echo " git remote add gitea http://94.41.23.97:3001/USER/tp.git"
|
||||
@echo " git push -u gitea main"
|
||||
@echo "5. Register runner:"
|
||||
@echo " Settings → Actions → Runners → Create Token"
|
||||
@echo " Update GITEA_RUNNER_REGISTRATION_TOKEN in docker-compose.yml"
|
||||
@echo " Then: docker compose up -d gitea-runner"
|
||||
@echo "6. Add secrets in repo Settings → Actions → Secrets:"
|
||||
@echo " (none needed — runner runs locally)"
|
||||
|
||||
# Показать все доступные цели
|
||||
help:
|
||||
@echo "=== Make targets ==="
|
||||
@echo ""
|
||||
@echo "Site management:"
|
||||
@echo " generate-configs — generate nginx configs from sites.yml"
|
||||
@echo " reconfig — generate configs + restart nginx"
|
||||
@echo ""
|
||||
@echo "Deploy:"
|
||||
@echo " all — full cycle all services"
|
||||
@echo " deploy — auto-detect changes, rebuild only changed"
|
||||
@echo " <service> — full cycle for one service"
|
||||
@echo ""
|
||||
@echo "Backup:"
|
||||
@echo " backup — run backup via running container"
|
||||
@echo " backup-run — run backup in one-shot container"
|
||||
@echo " restore DATE=... — restore from backup"
|
||||
@echo ""
|
||||
@echo "Gitea:"
|
||||
@echo " gitea — full cycle Gitea"
|
||||
@echo " gitea-runner — full cycle Runner"
|
||||
@echo " gitea-setup — first-time setup instructions"
|
||||
@echo ""
|
||||
@echo "Monitoring:"
|
||||
@echo " wn — watch docker ps"
|
||||
@echo " logs_<service> — logs for a service"
|
||||
@echo " bb_db — psql into bb_db"
|
||||
@@ -0,0 +1,11 @@
|
||||
FROM alpine:3.19
|
||||
|
||||
RUN apk add --no-cache postgresql-client rclone bash curl
|
||||
|
||||
COPY scripts/ /opt/
|
||||
RUN chmod +x /opt/*.sh
|
||||
|
||||
# crontab для расписания бэкапов
|
||||
RUN echo "$BACKUP_TIME /opt/backup.sh > /proc/1/fd/1 2>&1" > /etc/crontabs/root
|
||||
|
||||
CMD ["crond", "-f", "-l", "2"]
|
||||
@@ -0,0 +1,8 @@
|
||||
# Пример конфига rclone для Яндекс.Диска
|
||||
# Скопируй в backup/rclone.conf и заполни токен
|
||||
# Инструкция: https://rclone.org/yandex/
|
||||
[yadisk]
|
||||
type = yandex
|
||||
client_id =
|
||||
client_secret =
|
||||
token = {"access_token":"...","token_type":"...","expiry":"..."}
|
||||
@@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
# backup.sh — ежедневный бэкап: pg_dump + файлы → локально + Яндекс.Диск
|
||||
set -euo pipefail
|
||||
|
||||
BACKUP_DIR="/backups/$(date +%Y-%m-%d)"
|
||||
RETENTION_DAYS="${BACKUP_RETENTION_DAYS:-7}"
|
||||
DB_NAMES="${DB_NAMES:-mydb}"
|
||||
TIMESTAMP=$(date +%H%M%S)
|
||||
|
||||
mkdir -p "$BACKUP_DIR/db" "$BACKUP_DIR/files"
|
||||
|
||||
echo "=== Backup $TIMESTAMP ==="
|
||||
|
||||
# 1. Дампы всех БД
|
||||
IFS=',' read -ra databases <<< "$DB_NAMES"
|
||||
for db in "${databases[@]}"; do
|
||||
db=$(echo "$db" | xargs) # trim
|
||||
echo "→ Dumping database: $db"
|
||||
PGPASSWORD="$DB_PASSWORD" pg_dump -h "$DB_HOST" -p "${DB_PORT:-5432}" \
|
||||
-U "$DB_USER" -d "$db" --format=custom \
|
||||
-f "$BACKUP_DIR/db/${db}-${TIMESTAMP}.dump"
|
||||
done
|
||||
|
||||
# 2. Архив файлов
|
||||
echo "→ Archiving files..."
|
||||
tar -czf "$BACKUP_DIR/files/certbot-${TIMESTAMP}.tar.gz" -C /data/certbot . 2>/dev/null || true
|
||||
tar -czf "$BACKUP_DIR/files/uploads-${TIMESTAMP}.tar.gz" -C /data/uploads . 2>/dev/null || true
|
||||
tar -czf "$BACKUP_DIR/files/analytics-${TIMESTAMP}.tar.gz" -C /data/analytics . 2>/dev/null || true
|
||||
|
||||
# 3. Создаём symlink latest
|
||||
rm -f /backups/latest
|
||||
ln -sf "$BACKUP_DIR" /backups/latest
|
||||
|
||||
# 4. Ротация — удаляем старше RETENTION_DAYS
|
||||
find /backups -maxdepth 1 -type d -name '2*' -mtime "+$RETENTION_DAYS" -exec rm -rf {} \; 2>/dev/null || true
|
||||
|
||||
echo "✓ Local backup saved to $BACKUP_DIR"
|
||||
|
||||
# 5. Синхронизация с Яндекс.Диск
|
||||
if command -v rclone > /dev/null 2>&1 && [ -n "${RCLONE_REMOTE:-}" ]; then
|
||||
echo "→ Syncing to cloud: $RCLONE_REMOTE"
|
||||
rclone sync /backups "$RCLONE_REMOTE" --progress 2>&1 || \
|
||||
echo " ⚠ Cloud sync failed (check rclone config)"
|
||||
echo "✓ Cloud sync complete"
|
||||
fi
|
||||
|
||||
echo "=== Backup finished ==="
|
||||
@@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
# restore.sh — восстановление из бэкапа
|
||||
# Использование: docker compose run --rm backup /opt/restore.sh [дата]
|
||||
set -euo pipefail
|
||||
|
||||
BACKUP_DATE="${1:-latest}"
|
||||
BACKUP_DIR="/backups/$BACKUP_DATE"
|
||||
|
||||
if [ ! -d "$BACKUP_DIR" ]; then
|
||||
echo "Ошибка: бэкап $BACKUP_DIR не найден"
|
||||
echo "Доступные бэкапы:"
|
||||
ls -d /backups/2* 2>/dev/null || echo " (нет бэкапов)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== Restore from $BACKUP_DIR ==="
|
||||
|
||||
# Восстановить БД
|
||||
if [ -d "$BACKUP_DIR/db" ]; then
|
||||
for dump in "$BACKUP_DIR/db"/*.dump; do
|
||||
[ -f "$dump" ] || continue
|
||||
db=$(basename "$dump" | sed 's/-.*//')
|
||||
echo "→ Restoring database: $db"
|
||||
PGPASSWORD="$DB_PASSWORD" pg_restore -h "$DB_HOST" -p "${DB_PORT:-5432}" \
|
||||
-U "$DB_USER" -d "$db" --clean --if-exists "$dump" || \
|
||||
echo " ⚠ Restore of $db had warnings (non-fatal)"
|
||||
done
|
||||
fi
|
||||
|
||||
# Распаковать файлы
|
||||
if [ -d "$BACKUP_DIR/files" ]; then
|
||||
for archive in "$BACKUP_DIR/files"/*.tar.gz; do
|
||||
[ -f "$archive" ] || continue
|
||||
name=$(basename "$archive" | sed 's/-.*//')
|
||||
target="/data/$name"
|
||||
echo "→ Extracting $name to $target"
|
||||
mkdir -p "$target"
|
||||
tar -xzf "$archive" -C "$target" || true
|
||||
done
|
||||
fi
|
||||
|
||||
echo "=== Restore completed ==="
|
||||
echo "При необходимости перезапусти сервисы: docker compose restart"
|
||||
@@ -1,20 +1,10 @@
|
||||
FROM certbot/certbot
|
||||
|
||||
# Проверяем наличие crond (используем command -v вместо which)
|
||||
RUN if ! command -v crond > /dev/null 2>&1; then \
|
||||
echo "Cron not found. Installing cronie..."; \
|
||||
apk add --no-cache cronie; \
|
||||
else \
|
||||
echo "Cron is already installed."; \
|
||||
fi
|
||||
RUN apk add --no-cache cronie docker-cli
|
||||
|
||||
# Создаем директории для конфигов
|
||||
RUN mkdir -p /etc/letsencrypt/config
|
||||
|
||||
# Копируем конфигурационные файлы
|
||||
COPY scripts/ /opt/
|
||||
|
||||
# Устанавливаем права
|
||||
RUN chmod +x /opt/*
|
||||
RUN chmod +x /opt/*.sh
|
||||
|
||||
ENTRYPOINT ["/opt/init-certbot.sh"]
|
||||
@@ -0,0 +1,10 @@
|
||||
yalarba.ru
|
||||
www.yalarba.ru
|
||||
valitovgaziz.ru
|
||||
www.valitovgaziz.ru
|
||||
easysite102.ru
|
||||
www.easysite102.ru
|
||||
begushiybashkir.ru
|
||||
www.begushiybashkir.ru
|
||||
xn--80abahjtcfl5d0a8di.xn--p1ai
|
||||
www.xn--80abahjtcfl5d0a8di.xn--p1ai
|
||||
@@ -1 +1 @@
|
||||
0 0 * * * root /opt/checkRenewCerts.sh > /proc/1/fd/1 2>&1
|
||||
0 0 * * * /opt/renew-all.sh > /proc/1/fd/1 2>&1
|
||||
|
||||
@@ -1,69 +1,32 @@
|
||||
#!/bin/sh
|
||||
# init-certbot.sh — точка входа certbot контейнера
|
||||
set -e
|
||||
|
||||
# Проверяем наличие сертификатов для yalarba.ru
|
||||
if [ ! -d "/etc/letsencrypt/live/yalarba.ru" ]; then
|
||||
echo "Получаем новые сертификаты yalarba.ru ..."
|
||||
echo "=== Certbot init ==="
|
||||
|
||||
# Получаем сертификаты для всех доменов из DOMAINS_* env
|
||||
env | grep '^DOMAINS_' | grep -v '^ALL_DOMAINS' | sort | while IFS='=' read -r var_name domains; do
|
||||
primary_domain=$(echo "$domains" | cut -d, -f1)
|
||||
|
||||
if [ ! -d "/etc/letsencrypt/live/$primary_domain" ]; then
|
||||
echo "→ Получаем сертификат для $primary_domain"
|
||||
certbot certonly --webroot \
|
||||
--config /etc/letsencrypt/config/certbot.ini \
|
||||
-w /var/www/certbot \
|
||||
-d ${DOMAINS_yalarba}
|
||||
fi
|
||||
-d "$domains"
|
||||
echo "✓ Сертификат для $primary_domain получен"
|
||||
else
|
||||
echo "✓ Сертификат для $primary_domain уже существует"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "сertificates for ${DOMAINS_yalarba} is ready"
|
||||
|
||||
# Проверяем наличие сертификатов для valitovgaziz.ru
|
||||
if [ ! -d "/etc/letsencrypt/live/valitovgaziz.ru" ]; then
|
||||
echo "Получаем новые сертификаты valitovgaziz ..."
|
||||
certbot certonly --webroot \
|
||||
--config /etc/letsencrypt/config/certbot.ini \
|
||||
-w /var/www/certbot \
|
||||
-d ${DOMAINS_valitovgaziz}
|
||||
fi
|
||||
|
||||
echo "сertificates for ${DOMAINS_valitovgaziz} is ready"
|
||||
|
||||
# Проверяем наличие сертификатов для easysite102.ru
|
||||
if [ ! -d "/etc/letsencrypt/live/easysite102.ru" ]; then
|
||||
echo "Получаем новые сертификаты easysite102.ru ..."
|
||||
certbot certonly --webroot \
|
||||
--config /etc/letsencrypt/config/certbot.ini \
|
||||
-w /var/www/certbot \
|
||||
-d ${DOMAINS_easysite102}
|
||||
fi
|
||||
|
||||
echo "сertificates for ${DOMAINS_easysite102} is ready"
|
||||
|
||||
# Проверяем наличие сертификатов для бегущийбашкир.рф
|
||||
if [ ! -d "/etc/letsencrypt/live/xn--80abahjtcfl5d0a8di.xn--p1ai" ]; then
|
||||
echo "Получаем новые сертификаты xn--80abahjtcfl5d0a8di.xn--p1ai(бегущийбашкир.рф) ..."
|
||||
certbot certonly --webroot \
|
||||
--config /etc/letsencrypt/config/certbot.ini \
|
||||
-w /var/www/certbot \
|
||||
-d ${DOMAINS_begushiybashkir}
|
||||
fi
|
||||
|
||||
echo "сertificates for ${DOMAINS_begushiybashkir} is ready"
|
||||
|
||||
# Проверяем наличие сертификатов для begushiybashkir.ru
|
||||
if [ ! -d "/etc/letsencrypt/live/begushiybashkir.ru" ]; then
|
||||
echo "Получаем новые сертификаты begushiybashkir.ru ..."
|
||||
certbot certonly --webroot \
|
||||
--config /etc/letsencrypt/config/certbot.ini \
|
||||
-w /var/www/certbot \
|
||||
-d ${DOMAINS_begushiybashkir_latin}
|
||||
fi
|
||||
|
||||
echo "сertificates for ${DOMAINS_begushiybashkir_latin} is ready"
|
||||
|
||||
set -e # Завершаем работу, если любая команда вернёт ошибку
|
||||
|
||||
# Активируем сервис cron
|
||||
/usr/sbin/crond -f &
|
||||
crond -f &
|
||||
|
||||
# Копируем нашу собственную crontab таблицу
|
||||
# Настраиваем cron для ежедневного обновления
|
||||
cp /opt/crontab.txt /etc/crontabs/root
|
||||
|
||||
# Оставляем контейнер открытым
|
||||
tail -f /dev/null
|
||||
# Запускаем crond в фоне
|
||||
crond -b
|
||||
|
||||
echo "=== Init завершён, контейнер работает ==="
|
||||
|
||||
# Держим контейнер живым
|
||||
tail -f /dev/null
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#!/bin/sh
|
||||
# renew-all.sh — единый скрипт обновления всех сертификатов
|
||||
set -e
|
||||
|
||||
echo "=== Certbot renewal ==="
|
||||
|
||||
# Обновляем все сертификаты
|
||||
certbot renew --webroot -w /var/www/certbot
|
||||
|
||||
# Перезагружаем nginx чтобы он подхватил новые сертификаты
|
||||
if command -v docker > /dev/null 2>&1; then
|
||||
echo "→ Перезагружаем nginx..."
|
||||
docker exec nginx nginx -s reload 2>/dev/null || \
|
||||
echo " (nginx reload не удался, возможно контейнер не запущен)"
|
||||
fi
|
||||
|
||||
echo "=== Renewal завершён ==="
|
||||
@@ -10,19 +10,15 @@ services:
|
||||
- ./certbot/config:/etc/letsencrypt/config
|
||||
- certbot_data:/etc/letsencrypt
|
||||
- certbot_www:/var/www/certbot
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- EMAIL=${EMAIL}
|
||||
- DOMAINS=${ALL_DOMAINS}
|
||||
- STAGING=0
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD-SHELL",
|
||||
"test -f /etc/letsencrypt/live/$$(echo $${DOMAINS} | cut -d',' -f1)/fullchain.pem || exit 1",
|
||||
]
|
||||
test: ["CMD-SHELL", "ls /etc/letsencrypt/live/*/fullchain.pem 2>/dev/null | head -1 | xargs test -f || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
@@ -45,6 +41,7 @@ services:
|
||||
- ./stubSite:/usr/share/nginx/stub/html
|
||||
- ./BB/bbvue/dist:/usr/share/nginx/begushiybashkir/html
|
||||
- analytics_logs:/var/log/analytics:ro
|
||||
- ./nginx/conf.available:/etc/nginx/conf.available:ro
|
||||
networks:
|
||||
- web-network
|
||||
- internal
|
||||
@@ -52,8 +49,6 @@ services:
|
||||
depends_on:
|
||||
easysite:
|
||||
condition: service_healthy
|
||||
certbot:
|
||||
condition: service_healthy
|
||||
api_bb:
|
||||
condition: service_healthy
|
||||
analytics:
|
||||
@@ -254,6 +249,81 @@ services:
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# Gitea — self-hosted Git сервер + CI/CD
|
||||
# ──────────────────────────────────────────────
|
||||
gitea:
|
||||
image: gitea/gitea:latest
|
||||
container_name: gitea
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3001:3000"
|
||||
- "2222:22"
|
||||
volumes:
|
||||
- gitea_data:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
environment:
|
||||
- USER_UID=1000
|
||||
- USER_GID=1000
|
||||
- GITEA__server__DOMAIN=git.yalarba.ru
|
||||
- GITEA__server__SSH_DOMAIN=94.41.23.97
|
||||
- GITEA__server__ROOT_URL=https://git.yalarba.ru
|
||||
networks:
|
||||
- web-network
|
||||
- internal
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--spider", "http://localhost:3000"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
gitea-runner:
|
||||
image: gitea/act_runner:latest
|
||||
container_name: gitea-runner
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- /home/gaziz/artefacts/tp:/home/gaziz/artefacts/tp
|
||||
- gitea_runner:/data
|
||||
environment:
|
||||
- GITEA_INSTANCE_URL=http://gitea:3000
|
||||
- GITEA_RUNNER_REGISTRATION_TOKEN=
|
||||
depends_on:
|
||||
gitea:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- internal
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# Backup — ежедневные бэкапы БД + файлов → локально + Яндекс.Диск
|
||||
# ──────────────────────────────────────────────
|
||||
backup:
|
||||
build:
|
||||
context: ./backup
|
||||
dockerfile: Dockerfile
|
||||
container_name: backup
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- /var/backups/tp:/backups
|
||||
- certbot_data:/data/certbot:ro
|
||||
- api_bb_uploads:/data/uploads:ro
|
||||
- analytics_data:/data/analytics:ro
|
||||
environment:
|
||||
DB_HOST: db
|
||||
DB_PORT: 5432
|
||||
DB_USER: postgres
|
||||
DB_PASSWORD: postgres
|
||||
DB_NAMES: mydb,bb_db
|
||||
RCLONE_REMOTE: "yadisk:tp-backups"
|
||||
BACKUP_RETENTION_DAYS: 7
|
||||
BACKUP_TIME: "0 3 * * *"
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- internal
|
||||
|
||||
volumes:
|
||||
certbot_data: # volume для данных Certbot
|
||||
certbot_www: # volume для данных Certbot
|
||||
@@ -261,6 +331,8 @@ volumes:
|
||||
api_bb_uploads: # Volume для загружаемых файлов бегущий башкир
|
||||
analytics_logs: # Volume для логов аналитики
|
||||
analytics_data: # Volume для данных аналитики
|
||||
gitea_data: # Volume для Gitea
|
||||
gitea_runner: # Volume для Gitea Runner
|
||||
|
||||
networks:
|
||||
web-network:
|
||||
|
||||
Executable
+474
@@ -0,0 +1,474 @@
|
||||
#!/bin/bash
|
||||
# generate-configs.sh — генератор конфигов из sites.yml
|
||||
# Генерирует: nginx-http.conf, nginx-ssl.conf, certbot/domains.txt, обновляет .env
|
||||
set -euo pipefail
|
||||
|
||||
DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
cd "$DIR"
|
||||
|
||||
SITES_YML="$DIR/sites.yml"
|
||||
NGINX_DIR="$DIR/nginx"
|
||||
ENV_FILE="$DIR/.env"
|
||||
|
||||
if [ ! -f "$SITES_YML" ]; then
|
||||
echo "Ошибка: $SITES_YML не найден"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== Генерация конфигов из sites.yml ==="
|
||||
|
||||
# Используем python3 с quoted heredoc — предотвращает интерпретацию $ переменных bash
|
||||
python3 - "$DIR" "$NGINX_DIR" "$ENV_FILE" << 'PYEOF'
|
||||
import yaml, os, sys
|
||||
|
||||
BASE_DIR = sys.argv[1]
|
||||
NGINX_DIR = sys.argv[2]
|
||||
ENV_FILE = sys.argv[3]
|
||||
SITES_YML = os.path.join(BASE_DIR, "sites.yml")
|
||||
|
||||
with open(SITES_YML) as f:
|
||||
data = yaml.safe_load(f)
|
||||
|
||||
sites = data.get("sites", {})
|
||||
if not sites:
|
||||
print("Ошибка: в sites.yml нет сайтов")
|
||||
sys.exit(1)
|
||||
|
||||
# собираем данные
|
||||
all_domains = []
|
||||
env_domains = {}
|
||||
site_list = []
|
||||
|
||||
for name, cfg in sites.items():
|
||||
domain = cfg["domain"]
|
||||
aliases = cfg.get("aliases", [])
|
||||
|
||||
all_domains.append(domain)
|
||||
all_domains.extend(aliases)
|
||||
|
||||
env_key = f"DOMAINS_{name}"
|
||||
env_val = ",".join([domain] + aliases)
|
||||
env_domains[env_key] = env_val
|
||||
|
||||
site_list.append({
|
||||
"name": name,
|
||||
"domain": domain,
|
||||
"aliases": aliases,
|
||||
"type": cfg.get("type", "upstream"),
|
||||
"upstream": cfg.get("upstream", ""),
|
||||
"root": cfg.get("root", ""),
|
||||
"api": cfg.get("api", {}),
|
||||
})
|
||||
|
||||
env_domains["ALL_DOMAINS"] = ",".join(all_domains)
|
||||
|
||||
def all_server_names():
|
||||
"""Возвращает строку со всеми доменами и алиасами через пробел"""
|
||||
parts = []
|
||||
for s in site_list:
|
||||
parts.append(s["domain"])
|
||||
parts.extend(s["aliases"])
|
||||
return " ".join(parts)
|
||||
|
||||
def all_server_names_multiline():
|
||||
"""Возвращает строку с переносами для nginx server_name"""
|
||||
lines = []
|
||||
for s in site_list:
|
||||
lines.append(s["domain"])
|
||||
for a in s["aliases"]:
|
||||
lines.append(a)
|
||||
return " \\\n ".join(lines)
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# 2. Генерация nginx-http.conf
|
||||
# ──────────────────────────────────────────────
|
||||
http_conf = f"""# Автоматически сгенерировано generate-configs.sh — не редактировать вручную
|
||||
# HTTP-only конфигурация (работает когда нет сертификатов)
|
||||
|
||||
server {{
|
||||
listen 80;
|
||||
server_name {all_server_names_multiline()};
|
||||
|
||||
location / {{
|
||||
root /usr/share/nginx/stub/html;
|
||||
index index.html;
|
||||
}}
|
||||
|
||||
location /.well-known/acme-challenge/ {{
|
||||
root /var/www/certbot;
|
||||
}}
|
||||
}}
|
||||
|
||||
# Блок для HTTPS → HTTP редиректа (порт 443)
|
||||
server {{
|
||||
listen 443 ssl;
|
||||
server_name {all_server_names_multiline()};
|
||||
|
||||
ssl_certificate /etc/nginx/ssl/dummy.crt;
|
||||
ssl_certificate_key /etc/nginx/ssl/dummy.key;
|
||||
|
||||
return 301 http://$host$request_uri;
|
||||
}}
|
||||
"""
|
||||
|
||||
http_conf_path = os.path.join(NGINX_DIR, "nginx-http.conf")
|
||||
with open(http_conf_path, "w") as f:
|
||||
f.write(http_conf.lstrip())
|
||||
print(f" ✓ {http_conf_path}")
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# 3. Генерация nginx-ssl.conf
|
||||
# ──────────────────────────────────────────────
|
||||
ssl_server_blocks = []
|
||||
|
||||
for s in site_list:
|
||||
server_names = " ".join([s["domain"]] + s["aliases"])
|
||||
|
||||
block = f"""
|
||||
server {{
|
||||
listen 443 ssl;
|
||||
server_name {server_names};
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/{s["domain"]}/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/{s["domain"]}/privkey.pem;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
|
||||
"""
|
||||
if s["type"] == "upstream":
|
||||
block += f"""
|
||||
location / {{
|
||||
proxy_pass {s["upstream"]};
|
||||
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 X-Forwarded-Port $server_port;
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
}}
|
||||
"""
|
||||
elif s["type"] == "static":
|
||||
block += f"""
|
||||
location / {{
|
||||
root {s["root"]};
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}}
|
||||
"""
|
||||
# API routes
|
||||
for path, target in s["api"].items():
|
||||
cors_block = ""
|
||||
if "/api/" in path:
|
||||
cors_block = """
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header 'Access-Control-Allow-Origin' "$http_origin";
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
|
||||
add_header 'Access-Control-Max-Age' 1728000;
|
||||
add_header 'Content-Length' 0;
|
||||
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||
return 204;
|
||||
}
|
||||
"""
|
||||
block += f"""
|
||||
location {path} {{
|
||||
proxy_pass {target};
|
||||
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 X-Forwarded-Port $server_port;
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
{cors_block}
|
||||
}}
|
||||
"""
|
||||
if s["type"] == "static":
|
||||
block += f"""
|
||||
location /uploads/ {{
|
||||
alias /uploads/;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}}
|
||||
"""
|
||||
block += "}"
|
||||
ssl_server_blocks.append(block)
|
||||
|
||||
ssl_conf = f"""# Автоматически сгенерировано generate-configs.sh — не редактировать вручную
|
||||
# Полная HTTPS конфигурация
|
||||
|
||||
# --- HTTP → HTTPS редирект ---
|
||||
server {{
|
||||
listen 80;
|
||||
|
||||
server_name {all_server_names()};
|
||||
|
||||
location /.well-known/acme-challenge/ {{
|
||||
root /var/www/certbot;
|
||||
}}
|
||||
|
||||
location /uploads/ {{
|
||||
alias /uploads/;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}}
|
||||
|
||||
location / {{
|
||||
return 301 https://$host$request_uri;
|
||||
}}
|
||||
}}
|
||||
|
||||
# --- HTTPS серверные блоки ---
|
||||
{''.join(ssl_server_blocks)}
|
||||
"""
|
||||
|
||||
ssl_conf_path = os.path.join(NGINX_DIR, "nginx-ssl.conf")
|
||||
with open(ssl_conf_path, "w") as f:
|
||||
f.write(ssl_conf.lstrip())
|
||||
print(f" ✓ {ssl_conf_path}")
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# 4. Генерация per-domain конфигов (conf.available/)
|
||||
# ──────────────────────────────────────────────
|
||||
CONF_AVAILABLE = os.path.join(NGINX_DIR, "conf.available")
|
||||
os.makedirs(CONF_AVAILABLE, exist_ok=True)
|
||||
|
||||
# 00-http.conf — базовый HTTP catch-all (всегда активен)
|
||||
base_http = f"""# Автоматически сгенерировано generate-configs.sh
|
||||
server {{
|
||||
listen 80 default_server;
|
||||
server_name _;
|
||||
|
||||
location / {{
|
||||
root /usr/share/nginx/stub/html;
|
||||
index index.html;
|
||||
}}
|
||||
|
||||
location /.well-known/acme-challenge/ {{
|
||||
root /var/www/certbot;
|
||||
}}
|
||||
}}
|
||||
"""
|
||||
path = os.path.join(CONF_AVAILABLE, "00-http.conf")
|
||||
with open(path, "w") as f:
|
||||
f.write(base_http.lstrip())
|
||||
print(f" ✓ conf.available/00-http.conf")
|
||||
|
||||
# per-domain: SSL + HTTP fallback
|
||||
ORDER = ["10", "20", "30", "40", "50", "60", "70", "80", "90"]
|
||||
for idx, s in enumerate(site_list):
|
||||
prefix = ORDER[idx] if idx < len(ORDER) else f"{90 + idx}"
|
||||
safe_name = s["name"]
|
||||
server_names = " ".join([s["domain"]] + s["aliases"])
|
||||
|
||||
# --- SSL variant ---
|
||||
ssl_block = f"""# CERT_DOMAIN={s["domain"]}
|
||||
# Автоматически сгенерировано generate-configs.sh
|
||||
server {{
|
||||
listen 443 ssl;
|
||||
server_name {server_names};
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/{s["domain"]}/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/{s["domain"]}/privkey.pem;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
|
||||
"""
|
||||
if s["type"] == "upstream":
|
||||
ssl_block += f"""
|
||||
location / {{
|
||||
proxy_pass {s["upstream"]};
|
||||
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 X-Forwarded-Port $server_port;
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
}}
|
||||
"""
|
||||
elif s["type"] == "static":
|
||||
ssl_block += f"""
|
||||
location / {{
|
||||
root {s["root"]};
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}}
|
||||
"""
|
||||
for path, target in s["api"].items():
|
||||
cors = ""
|
||||
if "/api/" in path:
|
||||
cors = """
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header 'Access-Control-Allow-Origin' "$http_origin";
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
|
||||
add_header 'Access-Control-Max-Age' 1728000;
|
||||
add_header 'Content-Length' 0;
|
||||
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||
return 204;
|
||||
}
|
||||
"""
|
||||
ssl_block += f"""
|
||||
location {path} {{
|
||||
proxy_pass {target};
|
||||
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 X-Forwarded-Port $server_port;
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
{cors}
|
||||
}}
|
||||
"""
|
||||
if s["type"] == "static":
|
||||
ssl_block += f"""
|
||||
location /uploads/ {{
|
||||
alias /uploads/;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}}
|
||||
"""
|
||||
ssl_block += "}"
|
||||
|
||||
ssl_path = os.path.join(CONF_AVAILABLE, f"{prefix}-{safe_name}.ssl.conf")
|
||||
with open(ssl_path, "w") as f:
|
||||
f.write(ssl_block.lstrip())
|
||||
|
||||
# --- HTTP fallback variant ---
|
||||
http_block = f"""# HTTP fallback for {s["domain"]} (no SSL cert)
|
||||
server {{
|
||||
listen 80;
|
||||
server_name {server_names};
|
||||
"""
|
||||
if s["type"] == "upstream":
|
||||
http_block += f"""
|
||||
location / {{
|
||||
proxy_pass {s["upstream"]};
|
||||
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_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
}}
|
||||
"""
|
||||
elif s["type"] == "static":
|
||||
http_block += f"""
|
||||
location / {{
|
||||
root {s["root"]};
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}}
|
||||
"""
|
||||
for path, target in s["api"].items():
|
||||
cors = ""
|
||||
if "/api/" in path:
|
||||
cors = """
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header 'Access-Control-Allow-Origin' "$http_origin";
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
|
||||
add_header 'Access-Control-Max-Age' 1728000;
|
||||
add_header 'Content-Length' 0;
|
||||
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||
return 204;
|
||||
}
|
||||
"""
|
||||
http_block += f"""
|
||||
location {path} {{
|
||||
proxy_pass {target};
|
||||
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_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
{cors}
|
||||
}}
|
||||
"""
|
||||
if s["type"] == "static":
|
||||
http_block += f"""
|
||||
location /uploads/ {{
|
||||
alias /uploads/;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}}
|
||||
"""
|
||||
http_block += "}"
|
||||
|
||||
http_path = os.path.join(CONF_AVAILABLE, f"{prefix}-{safe_name}.http.conf")
|
||||
with open(http_path, "w") as f:
|
||||
f.write(http_block.lstrip())
|
||||
|
||||
print(f" ✓ conf.available/{prefix}-{safe_name}.ssl.conf + .http.conf")
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# 5. Генерация certbot/domains.txt
|
||||
# ──────────────────────────────────────────────
|
||||
domains_txt_path = os.path.join(BASE_DIR, "certbot", "domains.txt")
|
||||
with open(domains_txt_path, "w") as f:
|
||||
for d in all_domains:
|
||||
f.write(d + "\n")
|
||||
print(f" ✓ {domains_txt_path}")
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# 6. Обновление .env
|
||||
# ──────────────────────────────────────────────
|
||||
if os.path.exists(ENV_FILE):
|
||||
with open(ENV_FILE) as f:
|
||||
env_lines = f.readlines()
|
||||
else:
|
||||
env_lines = []
|
||||
|
||||
new_env = []
|
||||
for line in env_lines:
|
||||
stripped = line.strip()
|
||||
if stripped.startswith("DOMAINS_") or stripped.startswith("ALL_DOMAINS") or "CERTBOT NGINX VARIABLES" in stripped:
|
||||
continue
|
||||
new_env.append(line)
|
||||
|
||||
# удаляем пустые строки в начале
|
||||
while new_env and not new_env[0].strip():
|
||||
new_env.pop(0)
|
||||
|
||||
domain_keys = {k: v for k, v in env_domains.items()}
|
||||
|
||||
insert_idx = None
|
||||
for i, line in enumerate(new_env):
|
||||
if line.strip().startswith("EMAIL="):
|
||||
insert_idx = i + 1
|
||||
break
|
||||
|
||||
env_header = "#CERTBOT NGINX VARIABLES — авто-сгенерировано, не редактировать вручную\n"
|
||||
domain_lines = [f"{k}={v}\n" for k, v in sorted(domain_keys.items())]
|
||||
|
||||
if insert_idx is not None:
|
||||
new_env.insert(insert_idx, env_header)
|
||||
for dl in reversed(domain_lines):
|
||||
new_env.insert(insert_idx + 1, dl)
|
||||
else:
|
||||
new_env = [env_header] + domain_lines + new_env
|
||||
|
||||
with open(ENV_FILE, "w") as f:
|
||||
f.writelines(new_env)
|
||||
print(f" ✓ {ENV_FILE} (обновлён)")
|
||||
|
||||
print()
|
||||
print("=== Генерация завершена ===")
|
||||
print(f"Сгенерировано {len(site_list)} сайтов:")
|
||||
for s in site_list:
|
||||
print(f" • {s['domain']} ({s['type']})")
|
||||
print()
|
||||
print("Не забудь перезапустить nginx: docker compose restart nginx")
|
||||
PYEOF
|
||||
@@ -1,28 +1,17 @@
|
||||
FROM nginx:alpine
|
||||
|
||||
# Установка зависимостей
|
||||
RUN apk add --no-cache bash openssl
|
||||
|
||||
# Создание директории для сертификатов
|
||||
RUN mkdir -p /etc/nginx/ssl
|
||||
|
||||
# Генерация самоподписанных сертификатов (действительны 365 дней)
|
||||
RUN openssl req -x509 -nodes -days 365 \
|
||||
# dummy сертификаты для nginx (нужны чтобы nginx стартовал с любым конфигом)
|
||||
RUN mkdir -p /etc/nginx/ssl && \
|
||||
openssl req -x509 -nodes -days 365 \
|
||||
-newkey rsa:2048 \
|
||||
-keyout /etc/nginx/ssl/dummy.key \
|
||||
-out /etc/nginx/ssl/dummy.crt \
|
||||
-subj "/C=US/ST=State/L=City/O=Organization/CN=localhost"
|
||||
|
||||
# Копируем обе конфигурации
|
||||
COPY nginx-http.conf /etc/nginx/nginx-http.conf
|
||||
COPY nginx-ssl.conf /etc/nginx/nginx-ssl.conf
|
||||
RUN mkdir -p /var/www/certbot /etc/nginx/conf.d /etc/nginx/conf.available
|
||||
|
||||
# Создаем симлинк по умолчанию на HTTP конфиг
|
||||
RUN ln -sf /etc/nginx/nginx-http.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# Скрипт для проверки сертификатов и переключения конфига
|
||||
COPY switch-config.sh /docker-entrypoint.d/switch-config.sh
|
||||
# per-domain entrypoint для проверки сертификатов
|
||||
COPY entrypoint.sh /docker-entrypoint.d/switch-config.sh
|
||||
RUN chmod +x /docker-entrypoint.d/switch-config.sh
|
||||
|
||||
# Создаем необходимые директории
|
||||
RUN mkdir -p /var/www/certbot
|
||||
@@ -0,0 +1,14 @@
|
||||
# Автоматически сгенерировано generate-configs.sh
|
||||
server {
|
||||
listen 80 default_server;
|
||||
server_name _;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/stub/html;
|
||||
index index.html;
|
||||
}
|
||||
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/certbot;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
# HTTP fallback for yalarba.ru (no SSL cert)
|
||||
server {
|
||||
listen 80;
|
||||
server_name yalarba.ru www.yalarba.ru;
|
||||
|
||||
location / {
|
||||
proxy_pass http://yalarba:3000;
|
||||
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_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
}
|
||||
|
||||
location /api/v1/ {
|
||||
proxy_pass http://api_yal:8787;
|
||||
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_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header 'Access-Control-Allow-Origin' "$http_origin";
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
|
||||
add_header 'Access-Control-Max-Age' 1728000;
|
||||
add_header 'Content-Length' 0;
|
||||
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||
return 204;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
# CERT_DOMAIN=yalarba.ru
|
||||
# Автоматически сгенерировано generate-configs.sh
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name yalarba.ru www.yalarba.ru;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/yalarba.ru/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/yalarba.ru/privkey.pem;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
|
||||
|
||||
location / {
|
||||
proxy_pass http://yalarba:3000;
|
||||
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 X-Forwarded-Port $server_port;
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
}
|
||||
|
||||
location /api/v1/ {
|
||||
proxy_pass http://api_yal:8787;
|
||||
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 X-Forwarded-Port $server_port;
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header 'Access-Control-Allow-Origin' "$http_origin";
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
|
||||
add_header 'Access-Control-Max-Age' 1728000;
|
||||
add_header 'Content-Length' 0;
|
||||
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||
return 204;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
# HTTP fallback for valitovgaziz.ru (no SSL cert)
|
||||
server {
|
||||
listen 80;
|
||||
server_name valitovgaziz.ru www.valitovgaziz.ru;
|
||||
|
||||
location / {
|
||||
proxy_pass http://valitovgaziz/;
|
||||
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_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://analytics:3000/;
|
||||
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_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header 'Access-Control-Allow-Origin' "$http_origin";
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
|
||||
add_header 'Access-Control-Max-Age' 1728000;
|
||||
add_header 'Content-Length' 0;
|
||||
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||
return 204;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
# CERT_DOMAIN=valitovgaziz.ru
|
||||
# Автоматически сгенерировано generate-configs.sh
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name valitovgaziz.ru www.valitovgaziz.ru;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/valitovgaziz.ru/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/valitovgaziz.ru/privkey.pem;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
|
||||
|
||||
location / {
|
||||
proxy_pass http://valitovgaziz/;
|
||||
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 X-Forwarded-Port $server_port;
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://analytics:3000/;
|
||||
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 X-Forwarded-Port $server_port;
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header 'Access-Control-Allow-Origin' "$http_origin";
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
|
||||
add_header 'Access-Control-Max-Age' 1728000;
|
||||
add_header 'Content-Length' 0;
|
||||
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||
return 204;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
# HTTP fallback for easysite102.ru (no SSL cert)
|
||||
server {
|
||||
listen 80;
|
||||
server_name easysite102.ru www.easysite102.ru;
|
||||
|
||||
location / {
|
||||
proxy_pass http://easysite:3000;
|
||||
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_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
}
|
||||
|
||||
location /api/v1/ {
|
||||
proxy_pass http://api_yal:8787;
|
||||
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_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header 'Access-Control-Allow-Origin' "$http_origin";
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
|
||||
add_header 'Access-Control-Max-Age' 1728000;
|
||||
add_header 'Content-Length' 0;
|
||||
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||
return 204;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
# CERT_DOMAIN=easysite102.ru
|
||||
# Автоматически сгенерировано generate-configs.sh
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name easysite102.ru www.easysite102.ru;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/easysite102.ru/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/easysite102.ru/privkey.pem;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
|
||||
|
||||
location / {
|
||||
proxy_pass http://easysite:3000;
|
||||
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 X-Forwarded-Port $server_port;
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
}
|
||||
|
||||
location /api/v1/ {
|
||||
proxy_pass http://api_yal:8787;
|
||||
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 X-Forwarded-Port $server_port;
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header 'Access-Control-Allow-Origin' "$http_origin";
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
|
||||
add_header 'Access-Control-Max-Age' 1728000;
|
||||
add_header 'Content-Length' 0;
|
||||
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||
return 204;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
# HTTP fallback for begushiybashkir.ru (no SSL cert)
|
||||
server {
|
||||
listen 80;
|
||||
server_name begushiybashkir.ru www.begushiybashkir.ru;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/begushiybashkir/html;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://api_bb:8080/;
|
||||
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_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header 'Access-Control-Allow-Origin' "$http_origin";
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
|
||||
add_header 'Access-Control-Max-Age' 1728000;
|
||||
add_header 'Content-Length' 0;
|
||||
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||
return 204;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
location /uploads/ {
|
||||
alias /uploads/;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
# CERT_DOMAIN=begushiybashkir.ru
|
||||
# Автоматически сгенерировано generate-configs.sh
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name begushiybashkir.ru www.begushiybashkir.ru;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/begushiybashkir.ru/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/begushiybashkir.ru/privkey.pem;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/begushiybashkir/html;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://api_bb:8080/;
|
||||
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 X-Forwarded-Port $server_port;
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header 'Access-Control-Allow-Origin' "$http_origin";
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
|
||||
add_header 'Access-Control-Max-Age' 1728000;
|
||||
add_header 'Content-Length' 0;
|
||||
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||
return 204;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
location /uploads/ {
|
||||
alias /uploads/;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
# HTTP fallback for xn--80abahjtcfl5d0a8di.xn--p1ai (no SSL cert)
|
||||
server {
|
||||
listen 80;
|
||||
server_name xn--80abahjtcfl5d0a8di.xn--p1ai www.xn--80abahjtcfl5d0a8di.xn--p1ai;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/begushiybashkir/html;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://api_bb:8080/;
|
||||
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_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header 'Access-Control-Allow-Origin' "$http_origin";
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
|
||||
add_header 'Access-Control-Max-Age' 1728000;
|
||||
add_header 'Content-Length' 0;
|
||||
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||
return 204;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
location /uploads/ {
|
||||
alias /uploads/;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
# CERT_DOMAIN=xn--80abahjtcfl5d0a8di.xn--p1ai
|
||||
# Автоматически сгенерировано generate-configs.sh
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name xn--80abahjtcfl5d0a8di.xn--p1ai www.xn--80abahjtcfl5d0a8di.xn--p1ai;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/xn--80abahjtcfl5d0a8di.xn--p1ai/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/xn--80abahjtcfl5d0a8di.xn--p1ai/privkey.pem;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/begushiybashkir/html;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://api_bb:8080/;
|
||||
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 X-Forwarded-Port $server_port;
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header 'Access-Control-Allow-Origin' "$http_origin";
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
|
||||
add_header 'Access-Control-Max-Age' 1728000;
|
||||
add_header 'Content-Length' 0;
|
||||
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||
return 204;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
location /uploads/ {
|
||||
alias /uploads/;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
# entrypoint.sh — per-domain HTTPS переключение
|
||||
# Для каждого домена проверяет сертификат и активирует SSL или HTTP конфиг
|
||||
set -euo pipefail
|
||||
|
||||
CONF_AVAILABLE="/etc/nginx/conf.available"
|
||||
CONF_D="/etc/nginx/conf.d"
|
||||
CERT_DIR="/etc/letsencrypt/live"
|
||||
|
||||
rm -f "$CONF_D"/*.conf
|
||||
|
||||
# базовый HTTP (ACME challenge, catch-all redirect)
|
||||
if [ -f "$CONF_AVAILABLE/00-http.conf" ]; then
|
||||
ln -sf "$CONF_AVAILABLE/00-http.conf" "$CONF_D/00-http.conf"
|
||||
fi
|
||||
|
||||
# per-domain конфиги
|
||||
shopt -s nullglob
|
||||
for ssl_conf in "$CONF_AVAILABLE"/*.ssl.conf; do
|
||||
base="$(basename "$ssl_conf" .ssl.conf)"
|
||||
http_conf="$CONF_AVAILABLE/$base.http.conf"
|
||||
|
||||
# CERT_DOMAIN в первой строке: # CERT_DOMAIN=example.ru
|
||||
cert_domain="$(head -1 "$ssl_conf" | grep -oP '(?<=# CERT_DOMAIN=).+')" || true
|
||||
|
||||
if [ -n "$cert_domain" ] && [ -f "$CERT_DIR/$cert_domain/fullchain.pem" ]; then
|
||||
ln -sf "$ssl_conf" "$CONF_D/$base.ssl.conf"
|
||||
echo " ✓ $base → HTTPS ($cert_domain)"
|
||||
elif [ -f "$http_conf" ]; then
|
||||
ln -sf "$http_conf" "$CONF_D/$base.http.conf"
|
||||
echo " ✓ $base → HTTP (no cert for $cert_domain)"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "---"
|
||||
ls -la "$CONF_D/" | grep -v '^total'
|
||||
nginx -t
|
||||
@@ -1,16 +1,18 @@
|
||||
# Автоматически сгенерировано generate-configs.sh — не редактировать вручную
|
||||
# HTTP-only конфигурация (работает когда нет сертификатов)
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name yalarba.ru \
|
||||
www.yalarba.ru \
|
||||
easysite102.ru \
|
||||
www.easysite102.ru \
|
||||
valitovgaziz.ru \
|
||||
www.valitovgaziz.ru \
|
||||
xn--80abahjtcfl5d0a8di.xn--p1ai \
|
||||
www.xn--80abahjtcfl5d0a8di.xn--p1ai \
|
||||
easysite102.ru \
|
||||
www.easysite102.ru \
|
||||
begushiybashkir.ru \
|
||||
www.begushiybashkir.ru \
|
||||
auth.yalarba.ru;
|
||||
xn--80abahjtcfl5d0a8di.xn--p1ai \
|
||||
www.xn--80abahjtcfl5d0a8di.xn--p1ai;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/stub/html;
|
||||
@@ -25,12 +27,19 @@ server {
|
||||
# Блок для HTTPS → HTTP редиректа (порт 443)
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name yalarba.ru www.yalarba.ru easysite102.ru www.easysite102.ru valitovgaziz.ru www.valitovgaziz.ru xn--80abahjtcfl5d0a8di.xn--p1ai www.xn--80abahjtcfl5d0a8di.xn--p1ai begushiybashkir.ru www.begushiybashkir.ru;
|
||||
server_name yalarba.ru \
|
||||
www.yalarba.ru \
|
||||
valitovgaziz.ru \
|
||||
www.valitovgaziz.ru \
|
||||
easysite102.ru \
|
||||
www.easysite102.ru \
|
||||
begushiybashkir.ru \
|
||||
www.begushiybashkir.ru \
|
||||
xn--80abahjtcfl5d0a8di.xn--p1ai \
|
||||
www.xn--80abahjtcfl5d0a8di.xn--p1ai;
|
||||
|
||||
# Указание пустых сертификатов (обязательно для запуска Nginx)
|
||||
ssl_certificate /etc/nginx/ssl/dummy.crt;
|
||||
ssl_certificate_key /etc/nginx/ssl/dummy.key;
|
||||
|
||||
# Редирект всех HTTPS-запросов на HTTP
|
||||
return 301 http://$host$request_uri;
|
||||
}
|
||||
+80
-221
@@ -1,130 +1,52 @@
|
||||
# ================================================
|
||||
# КОНФИГУРАЦИЯ NGINX С ПОДДЕРЖКОЙ SSL
|
||||
# Основные задачи:
|
||||
# 1. Перенаправление HTTP → HTTPS
|
||||
# 2. Обслуживание статических файлов
|
||||
# 3. Проксирование к backend сервисам
|
||||
# 4. Поддержка нескольких доменов
|
||||
# ================================================
|
||||
# Автоматически сгенерировано generate-configs.sh — не редактировать вручную
|
||||
# Полная HTTPS конфигурация
|
||||
|
||||
# ================================================
|
||||
# БЛОК 1: HTTP СЕРВЕР (ПОРТ 80)
|
||||
# ================================================
|
||||
# --- HTTP → HTTPS редирект ---
|
||||
server {
|
||||
# Прослушивание порта 80 для всех входящих HTTP соединений
|
||||
listen 80;
|
||||
|
||||
# Список доменов, которые обслуживает этот сервер
|
||||
# Все запросы к этим доменам по HTTP будут обработаны здесь
|
||||
server_name yalarba.ru www.yalarba.ru
|
||||
valitovgaziz.ru www.valitovgaziz.ru
|
||||
easysite102.ru www.easysite102.ru
|
||||
begushiybashkir.ru
|
||||
xn--80abahjtcfl5d0a8di.xn--p1ai; # Punycode для IDN домена
|
||||
server_name yalarba.ru www.yalarba.ru valitovgaziz.ru www.valitovgaziz.ru easysite102.ru www.easysite102.ru begushiybashkir.ru www.begushiybashkir.ru xn--80abahjtcfl5d0a8di.xn--p1ai www.xn--80abahjtcfl5d0a8di.xn--p1ai;
|
||||
|
||||
# ============================================
|
||||
# ЛОКАЦИЯ: Проверочные файлы для Certbot
|
||||
# ============================================
|
||||
# Этот блок КРИТИЧЕСКИ ВАЖЕН для получения SSL сертификатов
|
||||
# Certbot (Let's Encrypt) размещает здесь временные файлы
|
||||
# для подтверждения владения доменом
|
||||
location /.well-known/acme-challenge/ {
|
||||
# Директория, где Certbot хранит проверочные файлы
|
||||
root /var/www/certbot;
|
||||
|
||||
# Дополнительные настройки не нужны - nginx просто отдает файлы
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# ЛОКАЦИЯ: Основное перенаправление
|
||||
# ============================================
|
||||
# Все HTTP запросы перенаправляются на HTTPS
|
||||
# Это обеспечивает безопасность и правильную SEO-практику
|
||||
location / {
|
||||
# 301 - постоянный редирект (лучше для SEO, кэшируется браузерами)
|
||||
# https://$host$request_uri - сохраняет домен и полный путь запроса
|
||||
return 301 https://$host$request_uri;
|
||||
|
||||
# Пример:
|
||||
# HTTP: http://example.com/page?param=1
|
||||
# ↓ перенаправление ↓
|
||||
# HTTPS: https://example.com/page?param=1
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# ЛОКАЦИЯ: Загруженные файлы
|
||||
# ============================================
|
||||
# Обслуживание статических файлов (загрузок) по HTTP
|
||||
# Может быть полезно для прямых ссылок или кэширования
|
||||
location /uploads/ {
|
||||
# Псевдоним пути - запросы к /uploads/ обслуживаются из /uploads/ на диске
|
||||
alias /uploads/;
|
||||
|
||||
# Кэширование в браузере на 1 год
|
||||
expires 1y;
|
||||
|
||||
# Заголовки кэширования:
|
||||
# "public" - может кэшироваться прокси-серверами
|
||||
# "immutable" - файлы никогда не меняются, браузер не проверяет обновления
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# Если файл не найден - вернуть 404 ошибку
|
||||
try_files $uri =404;
|
||||
location / {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
# ================================================
|
||||
# БЛОК 2: HTTPS СЕРВЕР ДЛЯ YALARBA.RU
|
||||
# ================================================
|
||||
server {
|
||||
# Прослушивание порта 443 с SSL/TLS шифрованием
|
||||
listen 443 ssl;
|
||||
# --- HTTPS серверные блоки ---
|
||||
|
||||
# Домены для этого сервера
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name yalarba.ru www.yalarba.ru;
|
||||
|
||||
# ============================================
|
||||
# НАСТРОЙКИ SSL СЕРТИФИКАТОВ
|
||||
# ============================================
|
||||
# Пути к SSL сертификатам, сгенерированным Certbot
|
||||
ssl_certificate /etc/letsencrypt/live/yalarba.ru/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/yalarba.ru/privkey.pem;
|
||||
|
||||
# ============================================
|
||||
# НАСТРОЙКИ БЕЗОПАСНОСТИ SSL
|
||||
# ============================================
|
||||
# Разрешенные протоколы - только современные безопасные версии
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
|
||||
# Сервер выбирает шифры (не клиент)
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
# Список безопасных шифров
|
||||
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
|
||||
|
||||
# ============================================
|
||||
# ЛОКАЦИЯ: Nuxt 4 SSR приложение
|
||||
# ============================================
|
||||
location / {
|
||||
# Проксирование к Nuxt.js SSR серверу
|
||||
proxy_pass http://yalarba:3000;
|
||||
|
||||
# Полный набор заголовков для корректной работы приложения
|
||||
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 X-Forwarded-Port $server_port;
|
||||
|
||||
# Длинные таймауты
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# ЛОКАЦИЯ: REST API (api_yal)
|
||||
# ============================================
|
||||
location /api/v1/ {
|
||||
proxy_pass http://api_yal:8787;
|
||||
proxy_set_header Host $host;
|
||||
@@ -135,28 +57,30 @@ server {
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header 'Access-Control-Allow-Origin' "$http_origin";
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
|
||||
add_header 'Access-Control-Max-Age' 1728000;
|
||||
add_header 'Content-Length' 0;
|
||||
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||
return 204;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
# ================================================
|
||||
# БЛОК 3: HTTPS СЕРВЕР ДЛЯ VALITOVGAZIZ.RU
|
||||
# ================================================
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name valitovgaziz.ru www.valitovgaziz.ru;
|
||||
|
||||
# Свой SSL сертификат для этого домена
|
||||
ssl_certificate /etc/letsencrypt/live/valitovgaziz.ru/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/valitovgaziz.ru/privkey.pem;
|
||||
|
||||
# Те же настройки безопасности SSL
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
|
||||
|
||||
# ============================================
|
||||
# ЛОКАЦИЯ: Проксирование к Vue SPA контейнеру
|
||||
# ============================================
|
||||
location / {
|
||||
proxy_pass http://valitovgaziz/;
|
||||
proxy_set_header Host $host;
|
||||
@@ -169,79 +93,59 @@ server {
|
||||
proxy_read_timeout 600;
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# ЛОКАЦИЯ: API для аналитики
|
||||
# ============================================
|
||||
location /api/ {
|
||||
proxy_pass http://analytics:3000/;
|
||||
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;
|
||||
|
||||
add_header Access-Control-Allow-Origin "*" always;
|
||||
add_header Access-Control-Allow-Methods "POST, GET, OPTIONS" always;
|
||||
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
|
||||
add_header Access-Control-Allow-Credentials "true" always;
|
||||
proxy_set_header X-Forwarded-Port $server_port;
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header 'Access-Control-Allow-Origin' "$http_origin";
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
|
||||
add_header 'Access-Control-Max-Age' 1728000;
|
||||
add_header 'Content-Length' 0;
|
||||
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||
return 204;
|
||||
}
|
||||
|
||||
proxy_connect_timeout 30s;
|
||||
proxy_send_timeout 30s;
|
||||
proxy_read_timeout 30s;
|
||||
}
|
||||
}
|
||||
|
||||
# ================================================
|
||||
# БЛОК 4: HTTPS СЕРВЕР ДЛЯ EASYSITE102.RU
|
||||
# ================================================
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name easysite102.ru www.easysite102.ru;
|
||||
|
||||
# Свой SSL сертификат
|
||||
ssl_certificate /etc/letsencrypt/live/easysite102.ru/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/easysite102.ru/privkey.pem;
|
||||
|
||||
# Безопасные настройки SSL
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
|
||||
|
||||
# ============================================
|
||||
# ЛОКАЦИЯ: Проксирование к Nuxt.js приложению
|
||||
# ============================================
|
||||
location / {
|
||||
# ВСЕ запросы проксируются к Nuxt.js серверу
|
||||
proxy_pass http://easysite:3000;
|
||||
|
||||
# Полный набор заголовков для корректной работы приложения
|
||||
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 X-Forwarded-Port $server_port;
|
||||
|
||||
# Длинные таймауты для работы приложения
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# ЛОКАЦИЯ: API Backend для Easysite (api_yal)
|
||||
# ============================================
|
||||
location /api/v1/ {
|
||||
proxy_pass http://api_yal:8787;
|
||||
|
||||
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 X-Forwarded-Port $server_port;
|
||||
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
@@ -255,111 +159,26 @@ server {
|
||||
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||
return 204;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
# ================================================
|
||||
# БЛОК 5: HTTPS СЕРВЕР ДЛЯ IDN ДОМЕНА
|
||||
# (Punycode для "бегущийбашкир.рф")
|
||||
# ================================================
|
||||
server {
|
||||
listen 443 ssl;
|
||||
|
||||
# Punycode представление кириллического домена
|
||||
server_name xn--80abahjtcfl5d0a8di.xn--p1ai
|
||||
www.xn--80abahjtcfl5d0a8di.xn--p1ai;
|
||||
|
||||
# Отдельный сертификат для IDN домена
|
||||
ssl_certificate /etc/letsencrypt/live/xn--80abahjtcfl5d0a8di.xn--p1ai/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/xn--80abahjtcfl5d0a8di.xn--p1ai/privkey.pem;
|
||||
|
||||
# Стандартные SSL настройки
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
|
||||
|
||||
# ============================================
|
||||
# ЛОКАЦИЯ: SPA приложение (такое же как begushiybashkir.ru)
|
||||
# ============================================
|
||||
location / {
|
||||
root /usr/share/nginx/begushiybashkir/html;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# ЛОКАЦИЯ: API для "Бегущий Башкир"
|
||||
# ============================================
|
||||
location /api/ {
|
||||
proxy_pass http://api_bb:8080/;
|
||||
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 X-Forwarded-Port $server_port;
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
|
||||
# Те же CORS настройки что и у Easysite
|
||||
if ($request_method = OPTIONS ) {
|
||||
add_header 'Access-Control-Allow-Origin' "$http_origin";
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
|
||||
add_header 'Access-Control-Max-Age' 1728000;
|
||||
add_header 'Content-Length' 0;
|
||||
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||
return 204;
|
||||
}
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# ЛОКАЦИЯ: Загруженные файлы (статическое обслуживание)
|
||||
# ============================================
|
||||
location /uploads/ {
|
||||
# Обслуживание файлов загрузок напрямую из файловой системы
|
||||
alias /uploads/;
|
||||
|
||||
# Долгое кэширование - файлы загрузок редко меняются
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
|
||||
# try_files не нужен - nginx сам проверит существование файла
|
||||
}
|
||||
}
|
||||
|
||||
# ================================================
|
||||
# БЛОК 6: HTTPS СЕРВЕР ДЛЯ BEGUSHIYBASHKIR.RU
|
||||
# (ДУБЛИРУЕТ БЛОК 5 С ДРУГИМ ДОМЕНОМ)
|
||||
# ================================================
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name begushiybashkir.ru www.begushiybashkir.ru;
|
||||
|
||||
# Свой SSL сертификат для этого домена
|
||||
ssl_certificate /etc/letsencrypt/live/begushiybashkir.ru/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/begushiybashkir.ru/privkey.pem;
|
||||
|
||||
# Стандартные SSL настройки
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
|
||||
|
||||
# ВНИМАНИЕ: Весь контент ниже ДОСЛОВНО ДУБЛИРУЕТ
|
||||
# предыдущий серверный блок для IDN домена
|
||||
|
||||
# ============================================
|
||||
# ЛОКАЦИЯ: SPA приложение
|
||||
# ============================================
|
||||
location / {
|
||||
root /usr/share/nginx/begushiybashkir/html;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# ЛОКАЦИЯ: API для "Бегущий Башкир"
|
||||
# ============================================
|
||||
location /api/ {
|
||||
proxy_pass http://api_bb:8080/;
|
||||
proxy_set_header Host $host;
|
||||
@@ -371,8 +190,7 @@ server {
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
|
||||
# Копия CORS настроек
|
||||
if ($request_method = OPTIONS ) {
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header 'Access-Control-Allow-Origin' "$http_origin";
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
|
||||
@@ -381,17 +199,58 @@ server {
|
||||
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||
return 204;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
location /uploads/ {
|
||||
alias /uploads/;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name xn--80abahjtcfl5d0a8di.xn--p1ai www.xn--80abahjtcfl5d0a8di.xn--p1ai;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/xn--80abahjtcfl5d0a8di.xn--p1ai/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/xn--80abahjtcfl5d0a8di.xn--p1ai/privkey.pem;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/begushiybashkir/html;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://api_bb:8080/;
|
||||
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 X-Forwarded-Port $server_port;
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
|
||||
if ($request_method = OPTIONS) {
|
||||
add_header 'Access-Control-Allow-Origin' "$http_origin";
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
|
||||
add_header 'Access-Control-Max-Age' 1728000;
|
||||
add_header 'Content-Length' 0;
|
||||
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||
return 204;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# ЛОКАЦИЯ: Загруженные файлы
|
||||
# ============================================
|
||||
location /uploads/ {
|
||||
alias /uploads/;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
# ================================================
|
||||
# КОНЕЦ КОНФИГУРАЦИИ
|
||||
# ================================================
|
||||
@@ -0,0 +1,49 @@
|
||||
# Единый источник истины для всех сайтов проекта
|
||||
# Добавление нового сайта = одна секция в этом файле
|
||||
# После изменений запусти: bash generate-configs.sh
|
||||
|
||||
sites:
|
||||
yalarba:
|
||||
domain: yalarba.ru
|
||||
aliases:
|
||||
- www.yalarba.ru
|
||||
type: upstream
|
||||
upstream: http://yalarba:3000
|
||||
api:
|
||||
/api/v1/: http://api_yal:8787
|
||||
|
||||
valitovgaziz:
|
||||
domain: valitovgaziz.ru
|
||||
aliases:
|
||||
- www.valitovgaziz.ru
|
||||
type: upstream
|
||||
upstream: http://valitovgaziz/
|
||||
api:
|
||||
/api/: http://analytics:3000/
|
||||
|
||||
easysite102:
|
||||
domain: easysite102.ru
|
||||
aliases:
|
||||
- www.easysite102.ru
|
||||
type: upstream
|
||||
upstream: http://easysite:3000
|
||||
api:
|
||||
/api/v1/: http://api_yal:8787
|
||||
|
||||
begushiybashkir:
|
||||
domain: begushiybashkir.ru
|
||||
aliases:
|
||||
- www.begushiybashkir.ru
|
||||
type: static
|
||||
root: /usr/share/nginx/begushiybashkir/html
|
||||
api:
|
||||
/api/: http://api_bb:8080/
|
||||
|
||||
begushiybashkir_idn:
|
||||
domain: xn--80abahjtcfl5d0a8di.xn--p1ai
|
||||
aliases:
|
||||
- www.xn--80abahjtcfl5d0a8di.xn--p1ai
|
||||
type: static
|
||||
root: /usr/share/nginx/begushiybashkir/html
|
||||
api:
|
||||
/api/: http://api_bb:8080/
|
||||
Reference in New Issue
Block a user