Перенаправление Nginx с http www на https без www

Я пытаюсь перенаправить http://www.example.com в Nginx. Сертификат установлен только для версии без www. У меня есть два правила перенаправления 301 в таком порядке:

1) С http://example.com на

server {
  listen 80;
  listen 443 ssl;
  server_name example.com;

  if ($scheme = http) {
    return 301 https://$server_name$request_uri;
  }
}

2) С http://WWW.example.com на http://example.com

server {
  listen 80;
  server_name www.example.com;
  return 301 $scheme://example.com$request_uri;
}

Когда я запрашиваю www.example.com через curl с терминала, я вижу:

HTTP/1.1 301 Moved Permanently
Location: http://example.com/

Это именно то, что я ожидал. Однако, когда я делаю то же самое в браузере, он перенаправляет меня и выдает ошибку сертификата.

Я исправил это, добавив сертификат в www-версию, но мне интересно, почему он не работал без него? И почему curl дает другой результат?

На всякий случай, параметры SSL, которые я использую:

ssl_session_cache shared:SSL:50m;
ssl_session_timeout 5m;
ssl_dhparam /etc/nginx/pki/dhparam.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
resolver 8.8.8.8;
ssl_stapling on;
add_header Strict-Transport-Security "max-age=31536000";
1
задан 24 November 2016 в 13:36
3 ответа

Для очищенной дискуссии предлагаю разделить всю логику nginx на основной узел (example.conf config) и "сателлиты" (www_example.conf и т.д.). Спутники не должны иметь огромную логику.

Если в главном узле вы перенаправляете весь HTTP-трафик на HTTPS, - я предлагаю сделать это и в сателлитах - это немного быстрее:

www_example. conf

server {
  listen 80;
  server_name www.example.com;
  return 301 https://example.com$request_uri;
}

Я изменил $scheme на https.

Тогда, если я правильно понимаю вас - у вас две проблемы.

1. CURL не следует за вашими перенаправление. По умолчанию он этого не делает, вы должны пройти -L:

curl "http://www.example.com" -L

2. Еще одна проблема заключается в том, как nginx разбирает SSL-соединения. SSL не проверяет на уровне "config сервера". Он проверяет задолго до того, как сервер получит пакеты данных соединения и начнёт выполнять хендшейк - таким образом, ваши конфигы с именем_сервера во время этой проверки не используются.

Когда ваш сервер получает входящее соединение для SSL-хендшейка, он получает первый конфиг, который прослушивает текущий ip:port и пытается сделать хендшейк с ключом, цепочкой и сертификатом ssl.

Итоги:

Если вы хотите передать "https://www.example.com" и получить ответ с "https://example.com" - у вас должны быть оба сервера, настроенные на SSL.

Если вы хотите передать "http://www.example.com" и получить ответ с "https://example.com", вы должны быть уверены, что рукопожатие работает только на example.com, а не перед входом в этот домен. Как "разрешающие шаги" вашего сервера вы можете проверить через вывод wget - это самый простой способ.

Здесь вы можете найти мой конфигурационный файл, который я использовал для проверки вашей проблемы:

server {
    listen 80;
    listen 443 ssl;
    server_name example.com;

    ssl on;
    ssl_certificate /path/to.crt;
    ssl_certificate_key /path/to.key;

    ssl_protocols        TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers          ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4;
    ssl_prefer_server_ciphers on;


    if ($scheme = http) {
        return 301 https://$server_name$request_uri;
    }

    location / {
        add_header Content-type text/plain;
        return 200 "OK";
    }
}

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

    return 301 https://example.com$request_uri;
}

я добавил для отладки раздел location с return 200 "OK". Затем в CMD:

$ curl "http://www.example.com" -L
OK

$ wget "http://www.example.com" -O /dev/null
--2016-11-24 15:54:33--  http://www.example.com/
Resolving www.example.com (www.example.com)... 127.0.0.1
Connecting to www.example.com (www.example.com)|127.0.0.1|:80... connected.
HTTP request sent, awaiting response... 301 Moved Permanently
Location: https://example.com/ [following]
--2016-11-24 15:54:33--  https://example.com/
Resolving example.com (example.com)... 127.0.0.1
Connecting to example.com (example.com)|127.0.0.1|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2 [application/octet-stream]

В последнем выводе видно, что "шаги по разрешению" работают корректно.

В браузере тоже все работает корректно.

.
2
ответ дан 3 December 2019 в 18:32

Если сайт www.example.com ранее обслуживался с заголовком Strict-Transport-Security (или includeSubdomains) на примере . com) - браузер запомнит (на долгое время - например, 31536000 секунд) и всегда будет продвигать http подключения к https еще до того, как получит доступ к www.example.com.

.
1
ответ дан 3 December 2019 в 18:32

Другое решение, использующее модуль map .

В этом случае требуется только одна серверная директива для http (хотя это может быть достигнуто с помощью жесткого- закодированный хост в предложении return ). Кроме того, это позволяет повторно использовать полученную переменную $ root_domain из модуля карты в любом виртуальном хосте и инструментах автоматизации. А также нет необходимости в директиве if.

Итак, для получения «чистого» имени хоста:

map $host $root_domain {
  default none;
  ~*^www\.(.*)$ $1;
  ~*(.*) $1;
}

В nginx.conf

А затем для HTTP:

server {
  listen 80;
  server_name .example.org;
  return 301 https://$root_domain$request_uri;
}

и HTTPS:

server {
  listen 443 ssl http2;
  ssl_certificate ...;
  ssl_certificate_key  ...;
  server_name www.example.org;
  return 301 https://$domain_root$request_uri;
}
0
ответ дан 3 December 2019 в 18:32

Теги

Похожие вопросы