331 lines
10 KiB
Bash
331 lines
10 KiB
Bash
#!/bin/bash
|
||
|
||
# MY Network Nginx + SSL Setup
|
||
# Настройка nginx с SSL сертификатами через certbot
|
||
|
||
set -e
|
||
|
||
DOMAIN="my-public-node-3.projscale.dev"
|
||
EMAIL="admin@projscale.dev"
|
||
SERVICE_PORT="15100"
|
||
|
||
echo "🔒 MY Network Nginx + SSL Setup"
|
||
echo "==============================="
|
||
echo "Домен: $DOMAIN"
|
||
echo "Email: $EMAIL"
|
||
echo "Сервис порт: $SERVICE_PORT"
|
||
echo ""
|
||
|
||
# Проверка root прав
|
||
if [[ $EUID -ne 0 ]]; then
|
||
echo "❌ Запустите от root: sudo bash setup_nginx_ssl.sh"
|
||
exit 1
|
||
fi
|
||
|
||
# Обновление системы
|
||
echo "🔄 Обновление системы..."
|
||
apt update
|
||
|
||
# Установка необходимых пакетов
|
||
echo "📦 Установка nginx, certbot, ufw..."
|
||
apt install -y nginx certbot python3-certbot-nginx ufw curl
|
||
|
||
# Остановка nginx для получения сертификата
|
||
echo "🛑 Остановка nginx..."
|
||
systemctl stop nginx || true
|
||
|
||
# Настройка firewall
|
||
echo "🔥 Настройка firewall..."
|
||
ufw --force reset
|
||
ufw default deny incoming
|
||
ufw default allow outgoing
|
||
|
||
# SSH
|
||
ufw allow 22/tcp comment 'SSH'
|
||
|
||
# HTTP/HTTPS
|
||
ufw allow 80/tcp comment 'HTTP'
|
||
ufw allow 443/tcp comment 'HTTPS'
|
||
|
||
# Внутренний порт сервиса (только локально)
|
||
ufw allow from 127.0.0.1 to any port $SERVICE_PORT comment 'MY Network Local'
|
||
|
||
ufw --force enable
|
||
|
||
# Получение SSL сертификата
|
||
echo "🔐 Получение SSL сертификата..."
|
||
certbot certonly \
|
||
--standalone \
|
||
--non-interactive \
|
||
--agree-tos \
|
||
--email $EMAIL \
|
||
-d $DOMAIN
|
||
|
||
# Проверка что сертификат получен
|
||
if [[ ! -f "/etc/letsencrypt/live/$DOMAIN/fullchain.pem" ]]; then
|
||
echo "❌ Не удалось получить SSL сертификат!"
|
||
exit 1
|
||
fi
|
||
|
||
echo "✅ SSL сертификат получен"
|
||
|
||
# Создание конфигурации nginx
|
||
echo "🌐 Настройка nginx..."
|
||
|
||
# Удаление дефолтного сайта
|
||
rm -f /etc/nginx/sites-enabled/default
|
||
|
||
# Создание конфигурации MY Network
|
||
cat > /etc/nginx/sites-available/my-network << EOF
|
||
# MY Network Bootstrap Node - Nginx Configuration
|
||
# HTTP -> HTTPS redirect
|
||
server {
|
||
listen 80;
|
||
server_name $DOMAIN;
|
||
|
||
# Certbot renewal
|
||
location /.well-known/acme-challenge/ {
|
||
root /var/www/html;
|
||
}
|
||
|
||
# Redirect all HTTP to HTTPS
|
||
location / {
|
||
return 301 https://\$server_name\$request_uri;
|
||
}
|
||
}
|
||
|
||
# HTTPS server
|
||
server {
|
||
listen 443 ssl http2;
|
||
server_name $DOMAIN;
|
||
|
||
# SSL Configuration
|
||
ssl_certificate /etc/letsencrypt/live/$DOMAIN/fullchain.pem;
|
||
ssl_certificate_key /etc/letsencrypt/live/$DOMAIN/privkey.pem;
|
||
|
||
# SSL Security
|
||
ssl_protocols TLSv1.2 TLSv1.3;
|
||
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384;
|
||
ssl_prefer_server_ciphers on;
|
||
ssl_session_cache shared:SSL:10m;
|
||
ssl_session_timeout 10m;
|
||
|
||
# Security headers
|
||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||
add_header X-Frame-Options DENY always;
|
||
add_header X-Content-Type-Options nosniff always;
|
||
add_header X-XSS-Protection "1; mode=block" always;
|
||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||
add_header X-MY-Network-Version "2.0" always;
|
||
add_header X-MY-Network-Node "bootstrap" always;
|
||
|
||
# Hide nginx version
|
||
server_tokens off;
|
||
|
||
# Gzip compression
|
||
gzip on;
|
||
gzip_vary on;
|
||
gzip_min_length 1024;
|
||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||
|
||
# Rate limiting
|
||
limit_req_zone \$binary_remote_addr zone=api:10m rate=10r/s;
|
||
limit_req_zone \$binary_remote_addr zone=monitor:10m rate=1r/s;
|
||
|
||
# Main application proxy
|
||
location / {
|
||
# Rate limiting
|
||
limit_req zone=api burst=20 nodelay;
|
||
|
||
proxy_pass http://127.0.0.1:$SERVICE_PORT;
|
||
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-Host \$host;
|
||
proxy_set_header X-Forwarded-Port \$server_port;
|
||
|
||
# Timeouts
|
||
proxy_connect_timeout 5s;
|
||
proxy_send_timeout 10s;
|
||
proxy_read_timeout 10s;
|
||
|
||
# Buffering
|
||
proxy_buffering on;
|
||
proxy_buffer_size 4k;
|
||
proxy_buffers 8 4k;
|
||
|
||
# CORS headers
|
||
add_header Access-Control-Allow-Origin "*" always;
|
||
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
|
||
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
|
||
|
||
# Handle preflight requests
|
||
if (\$request_method = 'OPTIONS') {
|
||
add_header Access-Control-Allow-Origin "*";
|
||
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
|
||
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
|
||
add_header Access-Control-Max-Age 86400;
|
||
add_header Content-Length 0;
|
||
add_header Content-Type text/plain;
|
||
return 204;
|
||
}
|
||
}
|
||
|
||
# Monitor endpoint with stricter rate limiting
|
||
location /api/my/monitor/ {
|
||
limit_req zone=monitor burst=5 nodelay;
|
||
|
||
proxy_pass http://127.0.0.1:$SERVICE_PORT;
|
||
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;
|
||
|
||
# Cache static content
|
||
expires 30s;
|
||
add_header Cache-Control "public, no-transform";
|
||
}
|
||
|
||
# Health check endpoint
|
||
location /api/my/health {
|
||
proxy_pass http://127.0.0.1:$SERVICE_PORT;
|
||
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;
|
||
|
||
# No caching for health checks
|
||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||
add_header Pragma "no-cache";
|
||
add_header Expires "0";
|
||
}
|
||
|
||
# Block access to sensitive files
|
||
location ~ /\. {
|
||
deny all;
|
||
access_log off;
|
||
log_not_found off;
|
||
}
|
||
|
||
# Custom error pages
|
||
error_page 404 /404.html;
|
||
error_page 500 502 503 504 /50x.html;
|
||
|
||
location = /404.html {
|
||
return 404 '{"error": "Not Found", "message": "MY Network endpoint not found"}';
|
||
add_header Content-Type application/json;
|
||
}
|
||
|
||
location = /50x.html {
|
||
return 500 '{"error": "Server Error", "message": "MY Network temporarily unavailable"}';
|
||
add_header Content-Type application/json;
|
||
}
|
||
}
|
||
EOF
|
||
|
||
# Активация сайта
|
||
ln -sf /etc/nginx/sites-available/my-network /etc/nginx/sites-enabled/
|
||
|
||
# Проверка конфигурации nginx
|
||
echo "🔍 Проверка конфигурации nginx..."
|
||
nginx -t
|
||
|
||
if [[ $? -ne 0 ]]; then
|
||
echo "❌ Ошибка в конфигурации nginx!"
|
||
exit 1
|
||
fi
|
||
|
||
# Настройка автообновления сертификатов
|
||
echo "🔄 Настройка автообновления сертификатов..."
|
||
cat > /etc/cron.d/certbot-renew << EOF
|
||
# Автообновление SSL сертификатов MY Network
|
||
0 12 * * * root certbot renew --quiet --post-hook "systemctl reload nginx"
|
||
EOF
|
||
|
||
# Запуск nginx
|
||
echo "🚀 Запуск nginx..."
|
||
systemctl enable nginx
|
||
systemctl start nginx
|
||
|
||
# Проверка статуса
|
||
sleep 2
|
||
if systemctl is-active --quiet nginx; then
|
||
echo "✅ Nginx запущен успешно"
|
||
else
|
||
echo "❌ Ошибка запуска nginx"
|
||
systemctl status nginx
|
||
exit 1
|
||
fi
|
||
|
||
# Проверка MY Network сервиса
|
||
echo "🔍 Проверка MY Network сервиса..."
|
||
if pgrep -f "python3 app/main.py" > /dev/null; then
|
||
echo "✅ MY Network сервис работает"
|
||
else
|
||
echo "⚠️ MY Network сервис не запущен, запускаем..."
|
||
cd /home/service/my-uploader-bot
|
||
sudo -u service ./run_my_network.sh
|
||
sleep 3
|
||
fi
|
||
|
||
# Финальная проверка
|
||
echo "🎯 Финальная проверка..."
|
||
echo ""
|
||
|
||
# Проверка HTTP -> HTTPS redirect
|
||
echo "📡 Проверка HTTP redirect..."
|
||
HTTP_RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" http://$DOMAIN/ || echo "000")
|
||
if [[ "$HTTP_RESPONSE" == "301" ]]; then
|
||
echo "✅ HTTP -> HTTPS redirect работает"
|
||
else
|
||
echo "⚠️ HTTP redirect: $HTTP_RESPONSE"
|
||
fi
|
||
|
||
# Проверка HTTPS
|
||
echo "🔒 Проверка HTTPS..."
|
||
HTTPS_RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" https://$DOMAIN/api/my/health || echo "000")
|
||
if [[ "$HTTPS_RESPONSE" == "200" ]]; then
|
||
echo "✅ HTTPS работает"
|
||
else
|
||
echo "❌ HTTPS не работает: $HTTPS_RESPONSE"
|
||
fi
|
||
|
||
# Проверка SSL сертификата
|
||
echo "🔐 Проверка SSL сертификата..."
|
||
SSL_INFO=$(echo | openssl s_client -servername $DOMAIN -connect $DOMAIN:443 2>/dev/null | openssl x509 -noout -dates 2>/dev/null || echo "SSL check failed")
|
||
if [[ "$SSL_INFO" != "SSL check failed" ]]; then
|
||
echo "✅ SSL сертификат валиден"
|
||
echo "$SSL_INFO"
|
||
else
|
||
echo "⚠️ Не удалось проверить SSL сертификат"
|
||
fi
|
||
|
||
echo ""
|
||
echo "🎉 MY Network Bootstrap Node с SSL настроен!"
|
||
echo "============================================"
|
||
echo ""
|
||
echo "🌐 Доступ:"
|
||
echo " https://$DOMAIN"
|
||
echo " https://$DOMAIN/api/my/health"
|
||
echo " https://$DOMAIN/api/my/bootstrap/config"
|
||
echo " https://$DOMAIN/api/my/monitor/"
|
||
echo ""
|
||
echo "🔒 Безопасность:"
|
||
echo " ✅ SSL/TLS сертификат от Let's Encrypt"
|
||
echo " ✅ HTTP -> HTTPS redirect"
|
||
echo " ✅ Security headers"
|
||
echo " ✅ Rate limiting"
|
||
echo " ✅ Firewall (UFW)"
|
||
echo ""
|
||
echo "🔄 Автообновление:"
|
||
echo " ✅ SSL сертификаты (cron)"
|
||
echo " ✅ MY Network сервис (cron)"
|
||
echo ""
|
||
echo "📊 Мониторинг:"
|
||
echo " systemctl status nginx"
|
||
echo " systemctl status my-network"
|
||
echo " tail -f /var/log/nginx/access.log"
|
||
echo " tail -f /var/log/nginx/error.log"
|
||
echo ""
|
||
echo "🎯 MY Network Bootstrap Node полностью готов!" |