Nginx 400: The plain HTTP request was sent to HTTPS port — Решение
При попытке открыть сайт по протоколу HTTP на SSL-порту (например, http://example.com:443) Nginx возвращает HTML-страницу: 400 Bad Request: The plain HTTP request was sent to HTTPS port. В error.log записывается ошибка парсинга протокола.
| Схема URL клиента | Порт Nginx | Результат обработки |
|---|---|---|
https://example.com | 443 ssl | 200 OK (Штатный TLS Handshake) |
http://example.com | 80 (редирект) | 301 Moved Permanently на https:// |
http://example.com:443 | 443 ssl | 400 Bad Request (Plain HTTP на SSL сокет) |
- Клиенты, вручную вбивающие
http://domain:443или использующие некорректно настроенные скрипты автоматизации, видят «сырую» страницу ошибки. - В современных версиях Nginx директива
listen 443 ssl;ожидает обязательное TLS-рукопожатие при первом входящем байте.
- Убедитесь, что у вас настроен раздельный блок для приема стандартного незашифрованного HTTP-трафика на 80 порту с редиректом:
server { listen 80; server_name example.com www.example.com; return 301 https://$host$request_uri; } - В основном SSL-блоке
serverнастройте специальную внутреннюю директиву перехвата ошибки 497 для прозрачного редиректа на HTTPS:server { listen 443 ssl; server_name example.com www.example.com; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # Автоматический редирект клиента с HTTP на HTTPS при ошибке протокола: error_page 497 https://$host:$server_port$request_uri; location / { proxy_pass http://backend; } } - Проверьте синтаксис файлов конфигурации:
sudo nginx -t. - Примените изменения без разрыва соединений:
sudo systemctl reload nginx.
497 — это нестандартный внутренний код возврата самого Nginx, который генерируется специально в ситуациях, когда клиент отправляет незашифрованный текстовый HTTP-запрос в сокет, настроенный исключительно на прием SSL/TLS.Частые вопросы (FAQ)
Почему Nginx не делает этот редирект по умолчанию?
По стандартам безопасности RFC чистый HTTP-клиент, случайно постучавшийся в защищенный SSL-порт, не должен неявно переключаться без явного согласования криптографического контекста.
Работает ли директива 'ssl on;' в новых версиях Nginx?
Директива 'ssl on;' устарела и удалена. Начиная с Nginx 1.15+, параметр ssl указывается строго внутри директивы listen: 'listen 443 ssl;'.
Что произойдет, если забыть флаг ssl в listen 443?
Nginx будет ожидать открытый HTTP-трафик на 443 порту. При попытке зайти по https:// браузер выдаст ошибку SSL_ERROR_RX_RECORD_TOO_LONG.
Можно ли слушать HTTP и HTTPS на одном и том же порту?
Штатно протоколы разделяются, но с помощью обработки error_page 497 можно добиться бесшовного перенаправления клиента на HTTPS на том же самом порту.