Настройка Nginx для ботов

В этой статье мы рассмотрим настройку Nginx как reverse proxy для ботов, включая SSL сертификаты, балансировку нагрузки, кэширование и безопасность.

Содержание

Установка и базовая настройка

Установка Nginx

#!/bin/bash
# install-nginx.sh

# Обновление системы
apt update && apt upgrade -y

# Установка Nginx
apt install -y nginx

# Запуск и включение автозапуска
systemctl start nginx
systemctl enable nginx

# Проверка статуса
systemctl status nginx

# Проверка конфигурации
nginx -t

echo "Nginx установлен и запущен!"

Базовая конфигурация

# /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;

events {
    worker_connections 1024;
    use epoll;
    multi_accept on;
}

http {
    # Основные настройки
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    server_tokens off;

    # MIME типы
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    # Логирование
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    access_log /var/log/nginx/access.log main;
    error_log /var/log/nginx/error.log;

    # Gzip сжатие
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/json
        application/javascript
        application/xml+rss
        application/atom+xml
        image/svg+xml;

    # Безопасность
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "no-referrer-when-downgrade" always;
    add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;

    # Включение конфигураций сайтов
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

Reverse Proxy для ботов

Конфигурация для Telegram бота

# /etc/nginx/sites-available/telegram-bot
server {
    listen 80;
    server_name bot.yourdomain.com;

    # Логирование
    access_log /var/log/nginx/telegram-bot.access.log;
    error_log /var/log/nginx/telegram-bot.error.log;

    # Основной прокси
    location / {
        proxy_pass http://127.0.0.1:8000;
        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 30s;
        proxy_send_timeout 30s;
        proxy_read_timeout 30s;
        
        # Буферизация
        proxy_buffering on;
        proxy_buffer_size 4k;
        proxy_buffers 8 4k;
    }

    # Webhook для Telegram
    location /webhook {
        proxy_pass http://127.0.0.1:8000/webhook;
        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;
        
        # Специальные настройки для webhook
        proxy_read_timeout 60s;
        proxy_send_timeout 60s;
    }

    # Статические файлы
    location /static/ {
        alias /home/botuser/telegram-bot/static/;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # Медиа файлы
    location /media/ {
        alias /home/botuser/telegram-bot/media/;
        expires 1M;
        add_header Cache-Control "public";
    }

    # Health check
    location /health {
        access_log off;
        return 200 "healthy\n";
        add_header Content-Type text/plain;
    }
}

Конфигурация для Discord бота

# /etc/nginx/sites-available/discord-bot
server {
    listen 80;
    server_name discord-bot.yourdomain.com;

    # Логирование
    access_log /var/log/nginx/discord-bot.access.log;
    error_log /var/log/nginx/discord-bot.error.log;

    # Основной прокси
    location / {
        proxy_pass http://127.0.0.1:8001;
        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;
        
        # WebSocket поддержка
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    # API endpoints
    location /api/ {
        proxy_pass http://127.0.0.1:8001/api/;
        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;
        
        # Ограничение размера запроса
        client_max_body_size 10M;
    }

    # Dashboard
    location /dashboard {
        proxy_pass http://127.0.0.1:8001/dashboard;
        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;
        
        # Аутентификация
        auth_basic "Discord Bot Dashboard";
        auth_basic_user_file /etc/nginx/.htpasswd;
    }
}

Конфигурация для VK бота

# /etc/nginx/sites-available/vk-bot
server {
    listen 80;
    server_name vk-bot.yourdomain.com;

    # Логирование
    access_log /var/log/nginx/vk-bot.access.log;
    error_log /var/log/nginx/vk-bot.error.log;

    # Callback API для VK
    location /callback {
        proxy_pass http://127.0.0.1:8002/callback;
        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;
        
        # Специальные настройки для VK Callback
        proxy_read_timeout 30s;
        proxy_send_timeout 30s;
        
        # Ограничение размера запроса
        client_max_body_size 1M;
    }

    # Основной прокси
    location / {
        proxy_pass http://127.0.0.1:8002;
        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;
    }

    # Статические файлы
    location /static/ {
        alias /home/botuser/vk-bot/static/;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

SSL сертификаты

Let's Encrypt с Certbot

#!/bin/bash
# setup-ssl.sh

# Установка Certbot
apt install -y certbot python3-certbot-nginx

# Получение SSL сертификата
certbot --nginx -d bot.yourdomain.com -d discord-bot.yourdomain.com -d vk-bot.yourdomain.com

# Автоматическое обновление
echo "0 12   * /usr/bin/certbot renew --quiet" | crontab -

# Проверка обновления
certbot renew --dry-run

echo "SSL сертификаты настроены!"

Конфигурация с SSL

# /etc/nginx/sites-available/telegram-bot-ssl
server {
    listen 80;
    server_name bot.yourdomain.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name bot.yourdomain.com;

    # SSL сертификаты
    ssl_certificate /etc/letsencrypt/live/bot.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/bot.yourdomain.com/privkey.pem;

    # SSL настройки
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    # HSTS
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # Основной прокси
    location / {
        proxy_pass http://127.0.0.1:8000;
        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;
    }

    # Webhook для Telegram
    location /webhook {
        proxy_pass http://127.0.0.1:8000/webhook;
        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;
    }
}

Балансировка нагрузки

Load Balancer конфигурация

# /etc/nginx/conf.d/load-balancer.conf
upstream telegram_bot_backend {
    least_conn;
    server 127.0.0.1:8000 weight=3 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:8001 weight=2 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:8002 weight=1 max_fails=3 fail_timeout=30s;
    
    # Health check
    keepalive 32;
}

upstream discord_bot_backend {
    ip_hash;
    server 127.0.0.1:9000 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:9001 max_fails=3 fail_timeout=30s;
    
    keepalive 32;
}

upstream vk_bot_backend {
    round_robin;
    server 127.0.0.1:7000 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:7001 max_fails=3 fail_timeout=30s;
    
    keepalive 32;
}

Конфигурация с балансировкой

# /etc/nginx/sites-available/load-balanced-bots
server {
    listen 443 ssl http2;
    server_name bots.yourdomain.com;

    # SSL настройки
    ssl_certificate /etc/letsencrypt/live/bots.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/bots.yourdomain.com/privkey.pem;

    # Telegram бот
    location /telegram/ {
        proxy_pass http://telegram_bot_backend/;
        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;
        
        # Health check
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
    }

    # Discord бот
    location /discord/ {
        proxy_pass http://discord_bot_backend/;
        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;
        
        # WebSocket поддержка
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    # VK бот
    location /vk/ {
        proxy_pass http://vk_bot_backend/;
        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;
    }

    # Статус балансировщика
    location /nginx_status {
        stub_status on;
        access_log off;
        allow 127.0.0.1;
        deny all;
    }
}

Кэширование

Кэширование статических файлов

# /etc/nginx/conf.d/caching.conf
# Кэширование статических файлов
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
    add_header Vary Accept-Encoding;
    
    # Gzip сжатие
    gzip_static on;
}

# Кэширование API ответов
location /api/ {
    proxy_pass http://backend;
    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_cache api_cache;
    proxy_cache_valid 200 302 10m;
    proxy_cache_valid 404 1m;
    proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
    proxy_cache_lock on;
    
    # Заголовки кэша
    add_header X-Cache-Status $upstream_cache_status;
}

# Кэш зона
proxy_cache_path /var/cache/nginx/api levels=1:2 keys_zone=api_cache:10m max_size=1g inactive=60m use_temp_path=off;

Redis кэширование

# /etc/nginx/conf.d/redis-cache.conf
upstream redis_backend {
    server 127.0.0.1:6379;
}

# Кэширование через Redis
location /cache/ {
    # Проверка кэша в Redis
    access_by_lua_block {
        local redis = require "resty.redis"
        local red = redis:new()
        red:set_timeout(1000)
        
        local ok, err = red:connect("127.0.0.1", 6379)
        if not ok then
            ngx.log(ngx.ERR, "failed to connect to redis: ", err)
            return
        end
        
        local key = ngx.var.request_uri
        local res, err = red:get(key)
        if res and res ~= ngx.null then
            ngx.say(res)
            ngx.exit(200)
        end
    }
    
    # Если нет в кэше, проксируем запрос
    proxy_pass http://backend;
    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;
    
    # Сохранение в кэш
    header_filter_by_lua_block {
        local redis = require "resty.redis"
        local red = redis:new()
        red:set_timeout(1000)
        
        local ok, err = red:connect("127.0.0.1", 6379)
        if ok then
            local key = ngx.var.request_uri
            local value = ngx.arg[1]
            red:setex(key, 300, value) -- Кэш на 5 минут
        end
    }
}

Безопасность

Ограничение доступа

# /etc/nginx/conf.d/security.conf
# Ограничение по IP
location /admin/ {
    allow 192.168.1.0/24;
    allow 10.0.0.0/8;
    deny all;
    
    proxy_pass http://backend;
    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;
}

# Rate limiting
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=webhook:10m rate=5r/s;

location /api/ {
    limit_req zone=api burst=20 nodelay;
    
    proxy_pass http://backend;
    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;
}

location /webhook {
    limit_req zone=webhook burst=10 nodelay;
    
    proxy_pass http://backend;
    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;
}

# Блокировка вредоносных запросов
location / {
    # Блокировка SQL инъекций
    if ($args ~ "union.select.*\(") {
        return 403;
    }
    
    # Блокировка XSS
    if ($args ~ "<script.>") {
        return 403;
    }
    
    # Блокировка попыток доступа к системным файлам
    if ($uri ~* "\.(htaccess|htpasswd|ini|log|sh|sql|conf)$") {
        return 403;
    }
    
    proxy_pass http://backend;
    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;
}

ModSecurity интеграция

#!/bin/bash
# install-modsecurity.sh

# Установка ModSecurity
apt install -y libmodsecurity3 modsecurity-crs

# Копирование правил
cp /usr/share/modsecurity-crs/crs-setup.conf.example /etc/nginx/modsec/crs-setup.conf
cp /usr/share/modsecurity-crs/rules/*.conf /etc/nginx/modsec/

# Настройка ModSecurity
cat > /etc/nginx/modsec/modsecurity.conf << EOF
SecRuleEngine On
SecRule REQUEST_HEADERS:Content-Type "text/xml" \
     "id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
SecRule REQUEST_HEADERS:Content-Type "application/xml" \
     "id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
SecRule REQUEST_HEADERS:Content-Type "application/soap+xml" \
     "id:'200002',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
EOF

echo "ModSecurity установлен!"
# /etc/nginx/sites-available/modsecurity-bot
server {
    listen 443 ssl http2;
    server_name secure-bot.yourdomain.com;

    # ModSecurity
    modsecurity on;
    modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;
    modsecurity_rules_file /etc/nginx/modsec/crs-setup.conf;
    modsecurity_rules_file /etc/nginx/modsec/rules/*.conf;

    # SSL настройки
    ssl_certificate /etc/letsencrypt/live/secure-bot.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/secure-bot.yourdomain.com/privkey.pem;

    location / {
        proxy_pass http://backend;
        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;
    }
}

Мониторинг и логирование

Расширенное логирование

# /etc/nginx/conf.d/logging.conf
# Расширенный формат логов
log_format detailed '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent" '
                    '$request_time $upstream_response_time '
                    '$upstream_cache_status';

# Логирование по сайтам
access_log /var/log/nginx/telegram-bot.access.log detailed;
access_log /var/log/nginx/discord-bot.access.log detailed;
access_log /var/log/nginx/vk-bot.access.log detailed;

# Логирование ошибок
error_log /var/log/nginx/telegram-bot.error.log warn;
error_log /var/log/nginx/discord-bot.error.log warn;
error_log /var/log/nginx/vk-bot.error.log warn;

Мониторинг производительности

# nginx_monitor.py
import subprocess
import json
import time
import logging
from datetime import datetime

class NginxMonitor:
    def __init__(self):
        self.logger = logging.getLogger(__name__)
    
    def get_nginx_status(self):
        """Получение статуса Nginx"""
        try:
            result = subprocess.run(
                ['curl', '-s', 'http://localhost/nginx_status'],
                capture_output=True,
                text=True
            )
            
            if result.returncode == 0:
                lines = result.stdout.strip().split('\n')
                status = {}
                for line in lines:
                    if ':' in line:
                        key, value = line.split(':', 1)
                        status[key.strip()] = value.strip()
                return status
        except Exception as e:
            self.logger.error(f"Error getting nginx status: {e}")
        return None
    
    def get_connection_stats(self):
        """Получение статистики соединений"""
        try:
            result = subprocess.run(
                ['ss', '-tuln'],
                capture_output=True,
                text=True
            )
            
            if result.returncode == 0:
                connections = 0
                for line in result.stdout.split('\n'):
                    if ':80 ' in line or ':443 ' in line:
                        connections += 1
                return connections
        except Exception as e:
            self.logger.error(f"Error getting connection stats: {e}")
        return 0
    
    def monitor_performance(self):
        """Мониторинг производительности"""
        while True:
            try:
                status = self.get_nginx_status()
                connections = self.get_connection_stats()
                
                if status:
                    self.logger.info(f"Nginx Status: {status}")
                    self.logger.info(f"Active Connections: {connections}")
                
                time.sleep(60)  # Проверка каждую минуту
                
            except Exception as e:
                self.logger.error(f"Error in monitoring: {e}")
                time.sleep(60)

# Использование
monitor = NginxMonitor()
monitor.monitor_performance()

Алерты и уведомления

#!/bin/bash
# nginx-alerts.sh

# Проверка статуса Nginx
check_nginx_status() {
    if ! systemctl is-active --quiet nginx; then
        echo "ALERT: Nginx is not running!"
        # Отправка уведомления
        curl -X POST -H 'Content-type: application/json' \
            --data '{"text":"Nginx is down on server!"}' \
            https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK
    fi
}

# Проверка использования памяти
check_memory_usage() {
    memory_usage=$(free | grep Mem | awk '{printf "%.2f", $3/$2 * 100.0}')
    if (( $(echo "$memory_usage > 90" | bc -l) )); then
        echo "ALERT: High memory usage: ${memory_usage}%"
        curl -X POST -H 'Content-type: application/json' \
            --data "{\"text\":\"High memory usage: ${memory_usage}%\"}" \
            https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK
    fi
}

# Проверка размера логов
check_log_size() {
    log_size=$(du -m /var/log/nginx/access.log | cut -f1)
    if [ $log_size -gt 1000 ]; then
        echo "ALERT: Log file is too large: ${log_size}MB"
        # Ротация логов
        logrotate -f /etc/logrotate.d/nginx
    fi
}

# Запуск проверок
check_nginx_status
check_memory_usage
check_log_size

Заключение

В этой статье мы рассмотрели настройку Nginx для ботов:
  • ✅ Установка и базовая настройка
  • ✅ Reverse Proxy для различных типов ботов
  • ✅ SSL сертификаты и безопасность
  • ✅ Балансировка нагрузки
  • ✅ Кэширование и оптимизация
  • ✅ Безопасность и защита
  • ✅ Мониторинг и логирование
Nginx является мощным инструментом для обеспечения надежности и производительности ботов в продакшене.

Полезные ссылки

1246 просмотров
8 лайков
1 комментариев