Вопрос: В Nginx, как я могу переписать все HTTP-запросы на https при сохранении поддомена?


Я хочу переписать все HTTP-запросы на моем веб-сервере как https-запросы, я начал со следующего:

сервер {
    слушайте 80;

    место нахождения / {
      rewrite ^ (. *) https: //mysite.com$1 постоянный;
    }
...


Одна из проблем заключается в том, что это удаляет любую информацию о субдомене (например, node1.mysite.com/folder), как я могу переписать выше, чтобы перенаправить все на https и поддерживать поддомен?


490
2017-09-21 14:04


Источник


Пожалуйста, подумайте о переносе «принятого ответа» на serverfault.com/a/171238/90758, Это правильно. - olafure
Просто используйте $ server_name вместо hardcoded mysite.com - Fedir RYKHTIK


Ответы:


Правильный путь в новых версиях nginx

Оказалось, что мой первый ответ на этот вопрос был правильным в определенное время, но он превратился в другую ловушку - чтобы быть в курсе, пожалуйста, проверьте Налогообложение переписывающих ловушек

Я был исправлен многими пользователями SE, поэтому кредит им идет, но что более важно, вот правильный код:

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

server {
       listen         443 ssl;
       server_name    my.domain.com;
       # add Strict-Transport-Security to prevent man in the middle attacks
       add_header Strict-Transport-Security "max-age=31536000" always; 

       [....]
}

733
2017-12-05 20:43



Вы должны были бы сделать это в домене по принципу домена, но нет? Что делать, если вы хотите применить его ко всем доменам на вашем сервере? - JM4
@ JM4: если вы используете $ host $ в rewrite вместо server_name и добавляете default_server в директиву listen, он будет работать для каждого домена на вашем сервере. - Klaas van Schelven
Важно отметить, что 301 хранится в вашем локальном кеше без истечения срока действия. Не очень полезно при изменении конфигурации - Trefex
@everyone Используйте перенаправление 307 для сохранения содержимого POST. - Mahmoud Al-Qudsi
Обратите внимание, что вы должны использовать $host вместо $server_name если вы используете субдомены. - Catfish


ПРИМЕЧАНИЕ. Лучший способ сделать это был обеспечен https://serverfault.com/a/401632/3641 - но повторяется здесь:

server {
    listen         80;
    return 301 https://$host$request_uri;
}

В простейшем случае ваш хост будет исправлен, чтобы быть вашим сервисом, на который вы хотите отправить их, - это сделает 301 переадресацию в браузер, и URL-адрес браузера обновится соответствующим образом.

Ниже приведен предыдущий ответ, который неэффективен из-за регулярного выражения, простой 301 отличный, как показано @kmindi

Я использую nginx 0.8.39 и выше и использовал следующее:

 server {
       listen 80;
       rewrite ^(.*) https://$host$1 permanent;
 }

Отправляет постоянную переадресацию клиенту.


268
2017-08-17 03:07



Я думаю, что это должно быть 80 - так как это слушает http, а затем говорит клиенту вернуться как https (443). - Michael Neale
Это должен быть главный ответ! - Nathan
Это самый налоговый ответ. - Case
это самый простой, но наименее безопасный - таким образом вы позволяете вашему серверу перенаправлять пользователя на любую страницу, не проверяя, разрешено ли даже его использовать на вашем сервере. Если ваш сервер обслуживает mydomain.co, злоумышленники могут использовать ваш сервер для перенаправления пользователей на другие домены, такие как mydomain.co, например google.com. - friedkiwi
@ cab0lt здесь нет проблемы безопасности. Обслуживание перенаправления не представляет угрозы безопасности. Если есть требования контроля доступа, они должны быть проверены в том месте, где браузер запрашивает новый URL. Браузер не получит доступ просто на основе перенаправления и не нуждается в перенаправлении для запроса нового URL-адреса. - mc0e


Я думаю, что лучший и единственный способ - использовать HTTP 301 перемещен постоянно перенаправить вот так:

server {
    listen         [::]:80;
    return 301 https://$host$request_uri;
}

HTTP 301 перемещен постоянно перенаправление также является наиболее эффективным, поскольку нет регулярного выражения для оценки, согласно уже упомянутому pitfails,


Новый HTTP 308 постоянно перемещается сохраняет метод запроса и поддерживается основными браузерами, Например, используя 308 не позволяет браузерам изменять метод запроса от POST в GET для запроса перенаправления.


Если ты хочешь сохранить имя хоста и субдомен это способ.

Эта все еще работает, если у вас нет DNS, поскольку я также использую его локально. Я прошу, например, http://192.168.0.100/index.php и будет перенаправлен точно https://192.168.0.100/index.php,

я использую listen [::]:80 на моем хосте, потому что у меня есть bindv6only установлен в false, поэтому он также привязывается к сокету ipv4. измените его на listen 80 если вы не хотите IPv6 или хотите связываться в другом месте.

Решение от Saif Bechan использует server_name который в моем случае является localhost, но недоступен по сети.

Решение от Майкла Нила хорошо, но, согласно пит-файлам, есть лучшее решение с переадресацией 301;)


119
2018-06-23 17:19



Приятно, что вы пытаетесь его процитировать, но 301 не работает на HTTPS. - Case
что не работает? указанная секция сервера предназначена для того, чтобы трафик без шифрования http (без s) был постоянно перенаправлен на зашифрованный сервер (этот раздел, который прослушивает 443 (https), не указан) - kmindi
Я проверил это отлично с https и все - @kmindi Я обновил свой ответ со ссылкой на ваш - поскольку я думаю, что это правильный путь, и это продолжает появляться! Хорошая работа. - Michael Neale
При использовании запроса домена (не-ip) не работает, если я не изменю «[::]: 80 'до« 80 ». - Joseph Lust
это может быть ожидаемое поведение: trac.nginx.org/nginx/ticket/345, Я обновил ответ, чтобы описать вариант прослушивания. - kmindi


Вышеизложенное не сработало, поскольку все новые поддомены создаются все время. например AAA.example.com BBB.example.com около 30 поддоменов.

Наконец, получил конфигурацию, которая работает со следующим:

server {
  listen 80;
  server_name _;
  rewrite ^ https://$host$request_uri? permanent;
}
server {
  listen  443;
  server_name example.com;
  ssl on;
  ssl_certificate /etc/ssl/certs/myssl.crt;
  ssl_certificate_key /etc/ssl/private/myssl.key;
  ssl_prefer_server_ciphers       on;
# ...
# rest of config here
# ...
}

17
2018-06-25 04:29



Спасибо! nginx либо вернется 301 https://*/ или отменить запрос преждевременно в других ответах здесь. server_name _; с $host был ответ, который сделал трюк. +1 - zamnuts
Это оптимально! Тем не менее, я рекомендую для некоторых заменить _ с фактическим доменом, например. .domain.com У меня было два сервера, и nginx случайно направил один из моих серверов на сервер по умолчанию. - zzz
Это единственный ответ, который сработал для меня, спасибо! - Snowman
Большое спасибо приятелю. Я пробовал много решений, но не работал. Это решение удивительно, и это сработало для меня. имя сервера _; что это значит .. Я не понял. Пожалуйста, объясните мне это. - Pavan Kumar


Внутри серверного блока вы также можете сделать следующее:

# Force HTTPS connection. This rules is domain agnostic
if ($scheme != "https") {
    rewrite ^ https://$host$uri permanent;
}

16
2017-07-31 19:50



Эта конфигурация заставила мой сервер создать цикл перенаправления - Corkscreewe
Может быть, причина в том, что на вашем сайте есть другое перенаправление или https не включен. - Oriol
Ни один из других, казалось, не работал, кроме этого. Использование nginx версии: nginx / 1.10.0 (Ubuntu) - ThatGuy343
upvoted для https: // $ host $ uri - AMB
Это путь, если вы находитесь за грузозагрузчиком! - Antwan


Я опубликовал комментарий к правильному ответу давно, давным-давно с очень важной коррекцией, но я считаю, что необходимо выделить эту коррекцию в своем собственном ответе. Ни один из предыдущих ответов не может быть безопасным для использования, если в какой-то момент у вас был небезопасный HTTP-настроенный и ожидающий пользовательский контент, формы, хост API или настроил любой сайт, инструмент, приложение или утилиту, чтобы говорить на вашем сайте.

Проблема возникает, когда POST запрос делается на ваш сервер. Если ответ сервера с простым 30x переадресовывать содержимое POST будет потеряно. Случается, что браузер / клиент обновит запрос до SSL, но упадок  POST к GET запрос. POST параметры будут потеряны, и на ваш сервер будет отправлен неверный запрос.

Решение прост. Вы должны использовать HTTP 1.1 307 перенаправления. Это подробно описано в RFC 7231 S6.4.7:

  Note: This status code is similar to 302 (Found), except that it
  does not allow changing the request method from POST to GET.  This
  specification defines no equivalent counterpart for 301 (Moved
  Permanently) ([RFC7238], however, defines the status code 308
  (Permanent Redirect) for this purpose).

Решение, адаптированное из принятого решения, заключается в использовании 307 в вашем коде перенаправления:

server {
       listen         80;
       server_name    my.domain.com;
       return         307 https://$server_name$request_uri;
}

server {
       listen         443 ssl;
       server_name    my.domain.com;
       # add Strict-Transport-Security to prevent man in the middle attacks
       add_header Strict-Transport-Security "max-age=31536000"; 

       [....]
}

6
2018-03-19 20:24



очень, очень очень удобная команда. благодаря! - Denis Matafonov


Мне удалось сделать это вот так:

server {
listen 80;
listen 443 ssl;

server_name domain.tld www.domain.tld;

# global HTTP handler
if ($scheme = http) {
        return 301 https://www.domain.tld$request_uri;
}

# global non-WWW HTTPS handler
if ($http_host = domain.tld){
        return 303 https://www.domain.tld$request_uri;
}
}

https://stackoverflow.com/a/36777526/6076984


4
2018-04-21 18:27



Обновленная версия, без IF: paste.debian.net/plain/899679 - stamster


Я бегу ngnix за AWS ELB. ELB разговаривает с ngnix по http. Поскольку ELB не имеет возможности отправлять перенаправления клиентам, я проверяю заголовок X-Forwarded-Proto и перенаправляет:

if ($http_x_forwarded_proto != 'https') {
    return 301 "https://www.exampl.com";
}

3
2018-01-04 17:09





если ты return 301 https://$host$request_uri; как ответ по умолчанию на порт 80, ваш сервер может рано или поздно попасть в список открытых прокси-серверов [1] и начать злоупотреблять, чтобы отправлять трафик в другом месте в Интернете. Если ваши журналы заполняются сообщениями, подобными этому, то вы знаете, что это случилось с вами:

42.232.104.114 - - [25/Mar/2018:04:50:49 +0000] "GET http://www.ioffer.com/i/new-fashion-fine-gold-bracelet-versaec-bracelet-641175733 HTTP/1.1" 301 185 "http://www.ioffer.com/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.1.8.0; RogueCleaner; Alexa Toolbar)"

Проблема в том, что $host будет отсылать все, что браузер отправляет в Host заголовок или даже имя хоста из начальной строки HTTP, как этот:

GET http://www.ioffer.com/i/new-fashion-fine-gold-bracelet-versaec-bracelet-641175733 HTTP/1.1

Из-за этой проблемы некоторые другие ответы здесь рекомендуют использовать $server_name вместо $host, $server_name всегда оценивает, что вы вставить server_name декларация. Но если у вас есть несколько поддоменов или используйте подстановочный знак, это не сработает, потому что $server_name использует только первый после server_name декларация и, что еще более важно, просто откликнется на шаблон (не расширьте его).

Итак, как поддерживать несколько доменов при сохранении безопасности? В моих собственных системах я рассматривал эту дилемму первый перечисление default_server блок, который не использует $host, а затем перечисляет блок подстановочных знаков, который делает:

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

(Вы также можете перечислить несколько доменов во втором блоке.)

С этой комбинацией непревзойденные домены будут перенаправлены где-то жестко запрограммированные (всегда example.com), а домены, которые соответствуют вашим собственным, пойдут в нужное место. Ваш сервер не будет полезен в качестве открытого прокси-сервера, поэтому вы не столкнетесь с проблемами.

Если вы чувствуете себя ornery, я полагаю, вы также можете сделать default_server сопоставить блок никто ваших законных доменов и служить чем-то оскорбительным. , , ,

[1] Технически «прокси» - это неправильное слово, потому что ваш сервер не выходит и выполняет запросы для клиентов, просто отправляя перенаправление, но я не уверен, что будет правильным словом. Я также не уверен, в чем цель, но он заполняет ваши журналы шумом и потребляет ваш процессор и пропускную способность, поэтому вы можете остановить его.


0
2018-03-25 05:58





rewrite ^!https https://$host$request_uri permanent;

-1
2018-06-29 04:33