title: “Creating Dockerfile” date: 2023-09-12T13:01:00+03:00 draft: true
У нас есть очень простая ситуация. Есть один сайт с одним доменом, который хочет принимать подключения по SSL на 443 порту. И нам НЕ НУЖНО принимать подключения с любых других доменов, а также с IP адреса сервера по 80 и 443 портам. Как ни странно, решение данной ситуации оказывается совсем не простым.
Проблема заключается в особенностях обработки запросов у Nginx. Этот веб-сервер сначала принимает подключение по 443 порту, а затем выбирает какой server
в конфигурации будет обрабатывать это подключение. Такое поведение приводит к следующим проблемам:
- В общем случае, все домены должны или поддерживать SSL, или не поддерживать SSL (чтобы не было ошибок или странного поведения браузера).
- Не получится сделать редирект для домена, к которому идет попытка подключиться по 443 порту, и который не имеет SSL сертификат
- Запрос на 443 порт по IP адресу сервера также приведет к проблемам: получить сертификат на IP нельзя, и придется создавать самоподписной сертификат для обработки запросов на 443 порт. А без сертификата при прописанном
listen 443
nginx
просто не запустится, будет выдавать ошибку. Потому что он уже принял запрос по 443 порту, и ему нужно дать какой-то сертификат.
Есть несколько способов обхода этой проблемы.
- Создать для каждого домена/IP самоподписной сертификат. Это не решит проблему “мусорных” доменов, которые указывают на ваш IP адрес, но решит проблему хотя бы на уровне ваших доменов и IP адреса сервера.
- Можно установить глобально для всех доменов (и ip адреса) какой-то сертификат, например, сертификат основного домена. Тогда nginx не будет ругаться на отсутствие сертификата для любых доменов (как прописанных в конфиге, так и не прописанных). Однако, будет ругаться браузер, который будет получать один и тот же сертификат для всех доменов.
- Если у вас
Nginx
версии начиная с 1.19.4 (вышла 27 октября 2020 года), то вы можете использовать директивуssl_reject_handshake
. Она была создана как раз для таких ситуаций:
# HTTP:80 = catch-all server block, resulting in a 444 response for unknown domains.
# HTTPS:443 = catch-all server block, resulting in reject SSL connection for unknown domains.
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name "_";
return 444; # Connection closed without response
}
server {
listen 443 default_server;
listen [::]:443 default_server;
server_name "_";
ssl_reject_handshake on; # Reject SSL connection
}