Skip to content

Latest commit

 

History

History
276 lines (178 loc) · 21.5 KB

File metadata and controls

276 lines (178 loc) · 21.5 KB

Урок 35. HTTPS, типичные ошибки деплоя и работа с сервером после запуска

В прошлых двух уроках мы полностью развернули filmsite: сервер, домен, Git, Django, Gunicorn, Nginx. Сайт уже работает по http://filmsite.ru. Осталось решить последнюю задачу — перевести сайт на защищённый протокол HTTPS.

После этого разберём три важные вещи, которые пригодятся вам не только сейчас, а на протяжении всей дальнейшей работы с проектом:

  1. расширенный чек-лист типичных ошибок деплоя — что делать, когда что-то не работает;
  2. как вносить правки в код на уже работающем сервере, не «ломая» сайт;
  3. итоговый план-шпаргалка по всему деплою — чтобы не пересматривать три урока каждый раз.

Что такое SSL и откуда мы его возьмём

Если сайт открывается по адресу вида http://filmsite.ru, браузер помечает его как небезопасный, часть функционала браузеры могут блокировать, поисковые системы понижают такой сайт в выдаче, а авторизация и передача данных происходят без шифрования.

SSL-сертификат:

  • шифрует данные между браузером пользователя и сервером;
  • подтверждает, что домен действительно принадлежит вам;
  • позволяет использовать протокол https://.

Мы используем бесплатный и полностью легальный сертификат от Let's Encrypt — он действует 90 дней и автоматически продлевается.

Certbot — инструмент для автоматической работы с SSL

Certbot сам получает сертификат, автоматически настраивает Nginx и умеет продлевать сертификаты без нашего участия.

Установка Certbot

sudo apt install certbot python3-certbot-nginx -y
  • certbot — основная утилита;
  • python3-certbot-nginx — модуль, который автоматически интегрируется с Nginx и правит его конфигурацию.

Получение сертификата

Вместо filmsite.ru укажите свой домен:

sudo certbot --nginx -d filmsite.ru -d www.filmsite.ru

В процессе Certbot:

  1. попросит указать email — на него могут приходить уведомления о проблемах с сертификатом;
  2. попросит подтвердить условия использования — вводим y;
  3. спросит про перенаправление HTTP → HTTPS — соглашаемся, выбираем автоматический редирект.

Если всё прошло успешно — вы увидите сообщение о том, что сертификат выдан.

Проверка результата в браузере

https://filmsite.ru

Ожидаем: сайт открывается по HTTPS, в адресной строке — замок, предупреждений нет. Также http://filmsite.ru должен автоматически перенаправлять на HTTPS.

Автоматическое продление

Сертификаты Let's Encrypt действуют 90 дней, но продлевать их вручную не нужно — Certbot устанавливает системный таймер:

sudo systemctl status certbot.timer

Статус active — сертификат будет продлеваться автоматически.

Проверить, что продление точно сработает, можно через симуляцию (сертификат реально не обновляется):

sudo certbot renew --dry-run

Если команда завершилась без ошибок — при реальном истечении срока сертификат продлится сам.


Чек-лист типичных ошибок деплоя

Ниже — самые частые проблемы именно на этапе первого деплоя, в формате «симптом → причина → как проверить → как исправить». Возвращайтесь к этому разделу каждый раз, когда что-то идёт не так.

502 Bad Gateway

Симптом: Nginx отдаёт страницу с ошибкой 502 вместо сайта.

Причина: Nginx работает и принимает запрос, но не может получить ответ от Gunicorn — либо Gunicorn не запущен, либо путь к .sock-файлу в конфиге Nginx не совпадает с реальным.

Как проверить:

sudo systemctl status gunicorn
ls -la /var/www/filmsite/filmsite.sock

Как исправить:

  • если статус не active (running) — смотрим причину падения: sudo journalctl -u gunicorn -n 50;
  • если сокет отсутствует или лежит в другом месте — сверьте путь --bind unix:... в gunicorn.service с путём proxy_pass http://unix:... в конфиге Nginx, они должны совпадать буква в букву;
  • после любого исправления: sudo systemctl restart gunicorn.

CSRF verification failed (403 на формах после подключения HTTPS)

Симптом: до подключения SSL все формы (вход, добавление фильма, рецензии) работали, а после перехода на HTTPS — при отправке любой формы Django возвращает 403 с текстом «CSRF verification failed».

Причина: Django, начиная с версии 4, дополнительно проверяет заголовок Origin запроса для защищённых (HTTPS) соединений за прокси. Если домен не указан в CSRF_TRUSTED_ORIGINS — проверка не проходит.

Как исправить: добавьте в settings.py:

CSRF_TRUSTED_ORIGINS = [
    'https://filmsite.ru',
    'https://www.filmsite.ru',
]

Обязательно с https:// в начале — именно так, как обращается к сайту браузер после редиректа. После изменения — sudo systemctl restart gunicorn.

DisallowedHost / 400 Bad Request

Симптом: сайт возвращает 400-ю ошибку, в логах Gunicorn — DisallowedHost.

Причина: домен, IP или поддомен, по которому пришёл запрос, не указан в ALLOWED_HOSTS.

Как проверить:

sudo journalctl -u gunicorn -n 30 | grep DisallowedHost

В сообщении будет указано, какой именно хост Django отклонил.

Как исправить: добавьте недостающее значение в ALLOWED_HOSTS в settings.py (это тот же список, который мы настраивали в уроке 34 — просто нужно свериться, не изменился ли домен/IP), затем sudo systemctl restart gunicorn.

Статические файлы или медиафайлы не загружаются (404)

Симптом: сайт открывается, но без стилей, либо не показываются постеры/аватары.

Возможные причины, по частоте:

  1. Забыли выполнить collectstatic после последних изменений — самая частая причина. Проверка: ls /var/www/filmsite/static/ — если папка пустая или устарела, выполните python manage.py collectstatic заново.
  2. Путь в конфиге Nginx не совпадает с STATIC_ROOT/MEDIA_ROOT. Откройте /etc/nginx/sites-available/filmsite и сверьте значения root в блоках location /static/ и location /media/ с реальными путями из settings.py.
  3. Права доступа. Проверка и исправление:
    sudo chmod 755 /var/www/filmsite/static
    sudo chmod 755 /var/www/filmsite/media

Проверяйте причины именно в этом порядке — права доступа на практике оказываются виноваты реже, чем забытый collectstatic или несовпадение путей, но именно к правам почему-то тянутся в первую очередь.

«Запушил изменения, а на сайте всё по-старому»

Симптом: вы сделали git push локально, git pull на сервере прошёл без ошибок, но в браузере видна старая версия сайта.

Причина: Gunicorn держит код Python-приложения загруженным в память своих worker-процессов. git pull обновляет файлы на диске, но уже запущенные процессы Gunicorn продолжают работать со старой версией кода до перезапуска.

Как исправить: после каждого git pull, если менялся Python-код (models, views, forms, urls) — обязательно:

sudo systemctl restart gunicorn

Если менялись только модели — не забудьте про миграции перед перезапуском:

python manage.py migrate
sudo systemctl restart gunicorn

Если менялась статика (CSS/JS/шаблоны, влияющие на собранные файлы) — потребуется collectstatic:

python manage.py collectstatic

OperationalError при подключении к PostgreSQL

Симптом: django.db.utils.OperationalError: could not connect to server или password authentication failed for user.

Возможные причины:

  1. Неверный пароль/имя пользователя/базы в DATABASES в settings.py — сверьте с тем, что вы указывали при CREATE USER/CREATE DATABASE в уроке 33.
  2. PostgreSQL не запущен:
    sudo systemctl status postgresql
  3. Неверный HOST. Если PostgreSQL слушает через Unix-сокет, а не TCP — иногда помогает 'HOST': '' (пустая строка) вместо 'localhost', поскольку это заставляет драйвер использовать сокет напрямую. Это скорее нюанс конкретной конфигурации сервера, чем правило — если 'localhost' не работает, стоит попробовать пустое значение.

Nginx не поднимается после правки конфига

Симптом: после sudo systemctl restart nginx сайт вообще перестал открываться — не только через HTTPS, но и полностью.

Причина: синтаксическая ошибка в конфигурационном файле — например, забытая точка с запятой или незакрытая скобка в блоке server {}.

Как избежать: всегда проверяйте синтаксис перед перезапуском:

sudo nginx -t

Если видите syntax is ok и test is successful — можно перезапускать. Если нет — Nginx покажет строку с ошибкой прямо в выводе команды.


Как вносить правки на работающем сервере

Частый вопрос новичков: «Мне нужно поправить файл через nano, а сервер запущен — придётся его останавливать?»

Нет. Открыть nano (или vim) и отредактировать любой файл проекта можно в любой момент, независимо от того, работает сайт или нет. Текстовый редактор и запущенные процессы Gunicorn/Nginx — это совершенно независимые друг от друга программы, они не мешают друг другу обращаться к одним и тем же файлам на диске.

Важно другое — что именно нужно сделать после сохранения правки, чтобы изменения реально применились на сайте. Это зависит от типа файла:

Что вы изменили Нужно ли что-то после сохранения
Python-код: views.py, models.py, forms.py, urls.py, settings.py Да — sudo systemctl restart gunicorn. Gunicorn держит код в памяти worker-процессов и не видит изменений на диске сам по себе.
Модели (добавили поле, новую таблицу) Сначала python manage.py migrate, затем sudo systemctl restart gunicorn.
HTML-шаблоны (.html в templates/) Обычно нет — Django по умолчанию читает шаблоны заново при каждом запросе. Перезапуск не помешает, но чаще всего не обязателен.
Статика (CSS/JS в исходных папках приложений) Да — python manage.py collectstatic, чтобы файлы попали в STATIC_ROOT, откуда их раздаёт Nginx. Gunicorn перезапускать не нужно.
Конфиг Nginx (/etc/nginx/sites-available/filmsite) Да, но не restart, а reload: сначала sudo nginx -t, затем sudo systemctl reload nginx.

Restart vs reload — в чём разница

Для Gunicorn мы всегда используем restart — сервис останавливается и запускается заново с новым кодом в памяти. Это занимает доли секунды и обычно проходит незаметно для пользователей благодаря механизму systemd, но кратковременно оборвёт активные запросы, если они как раз попали в этот момент.

Для Nginx предпочтительнее reload, а не restart:

sudo systemctl reload nginx

reload перечитывает конфигурацию без разрыва уже установленных соединений — Nginx продолжает обслуживать текущие запросы старой конфигурацией, пока не завершит их, и только новые запросы попадают под обновлённые правила. restart полностью останавливает и поднимает процесс заново, что для веб-сервера, который может обслуживать не только ваш проект, — более грубый и рискованный способ.

Безопасный порядок действий для правки на сервере

  1. Подключаемся по SSH.
  2. Открываем нужный файл: sudo nano путь/к/файлу (для системных файлов вроде конфига Nginx — обязательно через sudo, для файлов проекта в /var/www/filmsite — обычно можно без sudo, если вы работаете от root).
  3. Вносим правку, сохраняем (Ctrl+O, Enter, Ctrl+X в nano).
  4. В зависимости от типа файла — смотрим таблицу выше и выполняем нужную команду (restart gunicorn, collectstatic, nginx -t + reload).
  5. Проверяем результат в браузере.

Важная оговорка на будущее: постоянно редактировать код прямо на сервере через nano — рабочий способ для быстрой правки в экстренной ситуации, но не для повседневной разработки. Стандартный процесс — вносить изменения локально, коммитить, пушить на GitHub и подтягивать через git pull на сервере (как мы делали в уроке 33). Прямые правки на сервере имеют свойство «потеряться» — если вы в следующий раз сделаете git pull, а локальная версия файла отличается от той, что вы поправили вручную на сервере, git pull может конфликтовать или просто перезаписать вашу правку.


Итоговый план-шпаргалка: деплой Django-проекта с нуля

Компактная версия всего пройденного в модуле 9 — для быстрого обращения в будущем, без необходимости пересматривать все три урока целиком.

  1. Арендовать VPS (Ubuntu 24.04) и зарегистрировать доменУрок 33, Шаги 2–3.
  2. Привязать домен к IP сервера через A-запись, дождаться распространения DNS — Урок 33, Шаг 4.
  3. Подключиться к серверу по SSHУрок 33, Шаг 5.
  4. Обновить систему и установить пакеты: Python, venv, Nginx, при необходимости PostgreSQL — Урок 33, Шаг 6.
  5. [PostgreSQL] Создать базу данных и пользователяУрок 33, Шаг 7.
  6. Подготовить requirements.txt локально и перенести код через Git (git clone на сервере) — Урок 33, Шаг 8.
  7. Создать виртуальное окружение и установить зависимостиУрок 33, Шаг 9.
  8. Настроить settings.py: ALLOWED_HOSTS, DATABASES, STATIC_ROOT, MEDIA_ROOTУрок 34, Шаги 1–3.
  9. Выполнить миграции и collectstaticУрок 34, Шаг 4.
  10. Проверить сайт через runserver, затем через gunicorn напрямую — Урок 34, Шаги 5, 8.
  11. Переключить DEBUG = FalseУрок 34, Шаг 7.
  12. Настроить Gunicorn как systemd-сервисУрок 34, Шаг 9.
  13. Настроить и проверить конфиг Nginx (nginx -t перед перезапуском!) — Урок 34, Шаг 10.
  14. Открыть нужные порты через firewallУрок 34, Шаг 11.
  15. Вынести секреты (SECRET_KEY, пароль от БД) в .envУрок 34, Бонус.
  16. Получить SSL-сертификат через CertbotУрок 35, начало.
  17. [После HTTPS] Добавить CSRF_TRUSTED_ORIGINS, если формы начали отдавать 403 — Урок 35, чек-лист ошибок.
  18. При каждом обновлении кода: git pull → (если менялись модели) migrate → (если менялась статика) collectstaticrestart gunicorn.
  19. При правке конфига Nginx: nginx -treload nginx (не restart).

Этот список можно дополнять собственными пометками и ссылками — он и задумывался как рабочий чек-лист, а не как исчерпывающая документация: подробности при необходимости всегда можно найти в соответствующем уроке.


Предыдущий урок |