# config/nginx/oknardia-app--external-nginx.conf # ============================================================================== # КОНФИГУРАЦИОННЫЙ ФАЙЛ NGINX (Reverse Proxy для Docker + Production) # ============================================================================== # # ИНФОРМАЦИЯ: # 1. Этот файл используется как шаблон при деплое # 2. При первом деплое пути `/home/user/path-to-oknardia-app` заменяются на реальный путь через sed # 3. Сгенерированный конфиг скопируется в `/etc/nginx/sites-available/oknardia` # 4. Последующие деплои ОБНОВЛЯЮТ этот файл автоматически (sed + копирование) # # АРХИТЕКТУРА: # - Nginx (порты 80/443) <-> Gunicorn контейнер (localhost:8000) # - Медиа файлы отдаются из `/home/user/path-to-oknardia-app/media/` напрямую # - Ошибки 5xx берутся из `media/_error` (копируются контейнером при старте) # - Sitemap.xml отдается через Django/WhiteNoise (в media/_serv_sitemap/) # - Static файлы (/static/) тоже отдаются через Django/WhiteNoise # 1. Описываем, где живет наш Django в Docker upstream oknardia-django { # Мы пробрасываем порт 8050 из контейнера наружу (в docker-compose.yml имя сервиса 'web', контейнер 'oknardia-backend') server 127.0.0.1:8060; keepalive_requests 200; } # 2. Конфигурируем сервер server { server_name tmp.oknardia.ru; # Основное доменное имя # Слушаем 80 порт (Certbot потом добавит сюда редирект на 443 и настройки SSL) listen 80; listen [::]:80; charset utf-8; client_max_body_size 10M; # Разрешаем загрузку не слишком больших картинок # Логи (пути могут отличаться в зависимости от настроек сервера, здесь стандартные для Ubuntu) access_log /var/log/nginx/oknardia.access.log; error_log /var/log/nginx/oknardia.error.log; # --- GZIP (Сжатие) --- # Очень важно для динамического HTML от Django, который Gunicorn отдает несжатым. gzip on; gzip_vary on; # Добавляет заголовок Vary: Accept-Encoding gzip_proxied any; # Сжимать ответы, даже если мы за прокси gzip_comp_level 6; # Оптимальный баланс скорость/сжатие gzip_min_length 1000; # Не сжимать совсем мелочь # Типы файлов для сжатия (HTML сжимается автоматически, его писать не нужно) gzip_types text/plain text/css text/xml text/javascript application/javascript application/json application/xml application/xml+rss image/svg+xml image/x-icon application/vnd.ms-fontobject font/woff font/woff2; # --- МЕДИА ФАЙЛЫ (Загруженный контент) --- # Nginx отдает их напрямую с диска хоста, не дергая Docker. # Сюда входит: загруженные картинки, документы, свитмапы, ошибки 5xx # Путь должен совпадать с тем, где лежит volume на хост-машине. location /media/ { alias /home/user/path-to-oknardia-app/media/; expires 30d; # Кешируем картинки на месяц add_header Cache-Control "public, no-transform"; } # --- SITEMAP.XML --- # Sitemap хранится в media/_serv_sitemap/ но должен быть доступен из корня # для поисковиков (они ищут http://example.com/sitemap.xml) location = /sitemap.xml { alias /home/user/path-to-oknardia-app/media/_serv_sitemap/sitemap.xml; expires 7d; # Кешируем на неделю (редко меняется) add_header Cache-Control "public"; } # --- СТРАНИЦЫ ОШИБОК (Custom Error Pages) --- # Если Django упал (502) или сработал тайм-аут (504), Nginx должен отдать статический HTML. # Эти файлы копируются в `media/_error` при старте контейнера Docker. # # ВАЖНО: error_page директива перехватывает ошибки от апстрима (Gunicorn). error_page 500 /500.html; error_page 502 /502.html; error_page 503 /503.html; error_page 504 /504.html; location = /500.html { root /home/user/path-to-oknardia-app/media/_error; internal; } location = /502.html { root /home/user/path-to-oknardia-app/media/_error; internal; } location = /503.html { root /home/user/path-to-oknardia-app/media/_error; internal; } location = /504.html { root /home/user/path-to-oknardia-app/media/_error; internal; } error_page 400 /400.html; error_page 401 /401.html; error_page 403 /403.html; error_page 404 /404.html; error_page 413 /413.html; error_page 429 /429.html; location = /400.html { root /home/user/path-to-oknardia-app/media/_error; internal; } location = /401.html { root /home/user/path-to-oknardia-app/media/_error; internal; } location = /403.html { root /home/user/path-to-oknardia-app/media/_error; internal; } location = /404.html { root /home/user/path-to-oknardia-app/media/_error; internal; } location = /413.html { root /home/user/path-to-oknardia-app/media/_error; internal; } location = /429.html { root /home/user/path-to-oknardia-app/media/_error; internal; } error_page 405 406 407 408 409 410 411 412 414 415 416 417 418 421 422 423 424 425 426 428 431 451 /under_reconstruction.html; location = /under_reconstruction.html { root /home/user/path-to-oknardia-app/media/_error; internal; } # --- ВСЁ ОСТАЛЬНОЕ (Django + WhiteNoise) --- # Статика (/static/), robots.txt, favicon.ico и сам сайт обрабатываются внутри контейнера. # Nginx просто прокидывает запрос внутрь. location / { proxy_pass http://oknardia-django; # Передаем правильные заголовки, чтобы Django знал реальный IP и протокол proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # Если нужно чтобы Django обрабатывал и HTTP, и HTTPS, то можно раскомментировать эту строку # и передавать реальный протокол от клиента # proxy_set_header X-Forwarded-Proto $scheme; # Явно указываем https, потому что клиент всегда приходит по HTTPS к Nginx # Даже если внутри контейнера это HTTP на 127.0.0.1:8050, для Django это должно быть HTTPS proxy_set_header X-Forwarded-Proto https; # Тайм-ауты (важно для долгих операций, если они есть) proxy_read_timeout 180s; proxy_connect_timeout 180s; } } # 3. Редирект с www на основной домен (SEO best practice) server { server_name www.tmp.oknardia.ru; listen 80; listen [::]:80; return 301 $scheme://tmp.oknardia.ru$request_uri; }