Назад | Перейти на главную страницу

Поддомены nginx неправильно действуют как подстановочные знаки?

У меня странная проблема с поддоменами nginx. Во-первых, моя конфигурация:

server {
    listen              443 ssl;
    server_name         secure.example.com;
    ssl_certificate     example.crt;
    ssl_certificate_key example.key;
    keepalive_timeout   70;

    location / {
        fastcgi_pass    127.0.0.1:8000;
        ...
    }
}

server {
    listen              80;
    server_name         example.com www.example.com;

    location / {
        fastcgi_pass    127.0.0.1:8000;
        ...
    }
}

Идея в том, что у меня есть защищенный домен, secure.example.com и нормальный домен, example.com. На практике я могу перейти на https://example.com и http://secure.example.com. Я обошел вторую проблему с промежуточным сервером:

server {
    listen              80;
    server_name         secure.example.com;
    rewrite     ^(.*)  https://secure.example.com$1 permanent;
}

Но это не оптимальное решение, и мне пришлось бы создать еще один, чтобы перенаправить https с tld на поддомен. Я чувствую, что, должно быть, делаю что-то не так, если мне нужно несколько таких серверов. Почему https://example.com работают, когда там нет слушающего сервера на 443? Разве он не должен просто не подключиться? Я немного запутался.

Почему https://example.com работают, когда там нет слушающего сервера на 443? Разве он не должен просто не подключиться?

В server_name (или, точнее, заголовок HTTP / 1.1 Host) оценивается после установления соединения по 80 / tcp (HTTP) или 443 / tcp (HTTPS). Это означает, что если secure.example.com и example.com имеют одну и ту же запись ресурса A (они указывают на один и тот же IP-адрес), невозможно определить, какой виртуальный хост хочет видеть клиент до того, как соединение будет установлено и заголовок HTTP / 1.1 Host не был отправлен.

Еще точнее TCP / IP работает с IP-адресами (часть IP) и портами (часть TCP). Поэтому, если вы привязываете процесс (например, nginx) к определенному IP-адресу и порту, он всегда будет отвечать на этом сокете, а TCP / IP ничего не знает о HTTP / 1.1 и его заголовке Host.

Если вы хотите оптимизировать конфигурацию nginx, вы можете написать следующее:

server {
    listen              443 ssl;
    listen              80;

    server_name         secure.example.com;
    ssl_certificate     example.crt;
    ssl_certificate_key example.key;
    keepalive_timeout   70;

    if ($scheme = http) {
        rewrite  ^(.+)$  https://example.com$1  redirect;            
    }

    location / {
        fastcgi_pass    127.0.0.1:8000;
        # ...
    }
}

server {
    listen              80;
    server_name         example.com www.example.com;

    location / {
        fastcgi_pass    127.0.0.1:8000;
        # ...
    }
}

Взгляните на Nginx документация server_name. Он говорит, что если в вашем списке виртуальных хостов нет совпадений, nginx будет использовать первый сервер {} блок с соответствием Слушать директива.

Если вы хотите заставить пользователей использовать secure.example.com принимать с https, у вас может быть тот же способ обхода, который вы использовали для противоположного случая.