feat: новая функция

This commit is contained in:
2025-11-13 11:30:55 +03:00
parent d48afcfd6a
commit 4ab155c406
5 changed files with 57 additions and 14 deletions

View File

@@ -8,13 +8,19 @@ echo "🔧 Настройка nginx с параметрами:"
echo " DOMAIN: $DOMAIN" echo " DOMAIN: $DOMAIN"
echo " BACKEND_CONTAINER: $BACKEND_CONTAINER" echo " BACKEND_CONTAINER: $BACKEND_CONTAINER"
# Выбор конфигурации в зависимости от домена # Выбор конфигурации
SSL_CERT_PATH="/etc/letsencrypt/live/${DOMAIN}/fullchain.pem"
SSL_KEY_PATH="/etc/letsencrypt/live/${DOMAIN}/privkey.pem"
if echo "$DOMAIN" | grep -qE '^localhost(:[0-9]+)?$|^production\.local$'; then if echo "$DOMAIN" | grep -qE '^localhost(:[0-9]+)?$|^production\.local$'; then
echo " Режим: ЛОКАЛЬНАЯ РАЗРАБОТКА (без SSL)" echo " Режим: ЛОКАЛЬНАЯ РАЗРАБОТКА (без SSL)"
TEMPLATE_FILE="/etc/nginx/nginx-local.conf.template" TEMPLATE_FILE="/etc/nginx/nginx-local.conf.template"
else elif [ -f "$SSL_CERT_PATH" ] && [ -f "$SSL_KEY_PATH" ]; then
echo " Режим: ПРОДАКШН (с SSL)" echo " Режим: ПРОДАКШН (SSL сертификаты найдены)"
TEMPLATE_FILE="/etc/nginx/nginx-ssl.conf.template" TEMPLATE_FILE="/etc/nginx/nginx-ssl.conf.template"
else
echo " Режим: ПРОДАКШН (ожидаем выпуск SSL, работаем по HTTP)"
TEMPLATE_FILE="/etc/nginx/nginx-local.conf.template"
fi fi
# Обработка переменных окружения для nginx конфигурации # Обработка переменных окружения для nginx конфигурации

View File

@@ -38,6 +38,12 @@ http {
add_header X-XSS-Protection "1; mode=block" always; add_header X-XSS-Protection "1; mode=block" always;
} }
# Certbot webroot для автоматического получения SSL сертификатов
location /.well-known/acme-challenge/ {
root /var/www/certbot;
try_files $uri $uri/ =404;
}
# Статические файлы # Статические файлы
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y; expires 1y;

View File

@@ -53,3 +53,4 @@ export default {
} }
}; };

View File

@@ -216,21 +216,21 @@ app.post('/vds/transfer-encryption-key', logRequest, async (req, res) => {
sshConnectPassword sshConnectPassword
}; };
// 1. Проверяем, что директория для ключа существует на VDS // 1. Убеждаемся, что директория для ключа существует на VDS
log.info('🔍 Проверка директории для ключа шифрования...'); log.info('🔍 Подготовка директории для ключа шифрования на VDS...');
const dirCheckResult = await execSshCommand(`ls -la /home/${dockerUser}/dapp/ssl/keys/`, options); const ensureDirResult = await execSshCommand(`mkdir -p /home/${dockerUser}/dapp/ssl/keys`, options);
if (ensureDirResult.code !== 0) {
if (dirCheckResult.code !== 0) { log.error('❌ Не удалось подготовить директорию для ключа шифрования на VDS');
log.error('❌ Директория для ключа шифрования не найдена на VDS');
return res.status(500).json({ return res.status(500).json({
success: false, success: false,
message: 'Директория для ключа шифрования не найдена на VDS. Сначала выполните настройку VDS.' message: 'Не удалось подготовить директорию для ключа шифрования на VDS'
}); });
} }
// 2. Читаем ключ шифрования с локальной машины // 2. Читаем ключ шифрования с локальной машины
log.info('📖 Чтение ключа шифрования с локальной машины...'); log.info('📖 Чтение ключа шифрования с локальной машины...');
const encryptionKeyPath = '/home/alex/Digital_Legal_Entity(DLE)/ssl/keys/full_db_encryption.key'; const encryptionKeyPath = process.env.ENCRYPTION_KEY_PATH
|| path.resolve(__dirname, '..', 'ssl', 'keys', 'full_db_encryption.key');
try { try {
const encryptionKeyContent = await fs.readFile(encryptionKeyPath, 'utf8'); const encryptionKeyContent = await fs.readFile(encryptionKeyPath, 'utf8');
@@ -442,12 +442,10 @@ findtime = 3600
log.info('Nginx конфигурация встроена в Docker образ frontend-nginx'); log.info('Nginx конфигурация встроена в Docker образ frontend-nginx');
log.info('Конфигурация будет применена автоматически при запуске контейнера'); log.info('Конфигурация будет применена автоматически при запуске контейнера');
// Проверяем наличие необходимых переменных окружения для nginx
if (!domain || !email) { if (!domain || !email) {
log.error('Критическая ошибка: отсутствуют обязательные переменные DOMAIN или EMAIL для nginx'); log.error('Критическая ошибка: отсутствуют обязательные переменные DOMAIN или EMAIL для nginx');
throw new Error('Необходимы переменные DOMAIN и EMAIL для настройки nginx'); throw new Error('Необходимы переменные DOMAIN и EMAIL для настройки nginx');
} }
log.success(`Nginx будет настроен для домена: ${domain} с email: ${email}`); log.success(`Nginx будет настроен для домена: ${domain} с email: ${email}`);
// 14. 🆕 Создание полного .env файла со всеми переменными окружения // 14. 🆕 Создание полного .env файла со всеми переменными окружения
@@ -502,6 +500,32 @@ WS_BACKEND_CONTAINER=dapp-backend`;
// 16.0. 🆕 Получение реального SSL сертификата через Let's Encrypt (опционально) // 16.0. 🆕 Получение реального SSL сертификата через Let's Encrypt (опционально)
log.info('Получение реального SSL сертификата через Let\'s Encrypt...'); log.info('Получение реального SSL сертификата через Let\'s Encrypt...');
// Убеждаемся, что challenge доступен по HTTP
log.info('Проверяем доступность HTTP challenge для Let\'s Encrypt...');
await execSshCommand('mkdir -p /var/www/certbot/.well-known/acme-challenge', options);
const challengeToken = `agent-challenge-${Date.now()}`;
await execSshCommand(`echo 'challenge-ok' > /var/www/certbot/.well-known/acme-challenge/${challengeToken}`, options);
let tempHttpContainerStarted = false;
let challengeCheck = await execSshCommand(`curl -fsS http://${domain}/.well-known/acme-challenge/${challengeToken}`, options);
if (challengeCheck.code !== 0) {
log.warn('HTTP challenge недоступен. Запускаю временный nginx на 80 порту...');
await execSshCommand(`cd /home/${dockerUser}/dapp && docker compose -f docker-compose.prod.yml stop frontend-nginx || true`, options);
await execSshCommand('docker rm -f dle-certbot-http 2>/dev/null || true', options);
const tempNginxStart = await execSshCommand('docker run -d --name dle-certbot-http -p 80:80 -v /var/www/certbot:/usr/share/nginx/html:ro nginx:alpine', options);
if (tempNginxStart.code === 0) {
tempHttpContainerStarted = true;
await execSshCommand('sleep 3', options);
challengeCheck = await execSshCommand(`curl -fsS http://${domain}/.well-known/acme-challenge/${challengeToken}`, options);
} else {
log.warn('Не удалось запустить временный nginx для challenge: ' + tempNginxStart.stderr);
}
} else {
log.success('HTTP challenge доступен через frontend-nginx');
}
await execSshCommand(`rm -f /var/www/certbot/.well-known/acme-challenge/${challengeToken}`, options);
// Получаем SSL сертификат через certbot // Получаем SSL сертификат через certbot
const certbotResult = await execSshCommand(`cd /home/${dockerUser}/dapp && docker compose -f docker-compose.prod.yml run --rm certbot`, options); const certbotResult = await execSshCommand(`cd /home/${dockerUser}/dapp && docker compose -f docker-compose.prod.yml run --rm certbot`, options);
@@ -512,6 +536,12 @@ WS_BACKEND_CONTAINER=dapp-backend`;
log.info('Будет использоваться временный самоподписанный сертификат'); log.info('Будет использоваться временный самоподписанный сертификат');
} }
if (tempHttpContainerStarted) {
log.info('Останавливаю временный HTTP контейнер для challenge');
await execSshCommand('docker rm -f dle-certbot-http || true', options);
await execSshCommand(`cd /home/${dockerUser}/dapp && docker compose -f docker-compose.prod.yml up -d frontend-nginx`, options);
}
// Настройка автоматического обновления SSL сертификатов // Настройка автоматического обновления SSL сертификатов
log.info('Настройка автоматического обновления SSL сертификатов...'); log.info('Настройка автоматического обновления SSL сертификатов...');
const renewScript = `#!/bin/bash const renewScript = `#!/bin/bash

View File

@@ -224,7 +224,7 @@ services:
- WS_BACKEND_CONTAINER=dapp-backend - WS_BACKEND_CONTAINER=dapp-backend
volumes: volumes:
# SSL сертификаты Let's Encrypt (автоматически обновляются) # SSL сертификаты Let's Encrypt (автоматически обновляются)
- /etc/letsencrypt:/etc/ssl/certs:ro - /etc/letsencrypt:/etc/letsencrypt:ro
# Webroot для certbot # Webroot для certbot
- /var/www/certbot:/var/www/certbot - /var/www/certbot:/var/www/certbot
depends_on: depends_on: