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

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

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

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


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

489 голосов | спросил MikeN 21 stEurope/Moscowp30Europe/Moscow09bEurope/MoscowMon, 21 Sep 2009 18:04:43 +0400 2009, 18:04:43

10 ответов


733

Правильный путь в новых версиях 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; 

       [....]
}
ответил Saif Bechan 6 TueEurope/Moscow2011-12-06T00:43:47+04:00Europe/Moscow12bEurope/MoscowTue, 06 Dec 2011 00:43:47 +0400 2011, 00:43:47
268

ПРИМЕЧАНИЕ. Лучший способ сделать это был предоставлен 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;
 }

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

ответил Michael Neale 17 AM00000070000002231 2010, 07:07:22
119

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

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

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


Новый 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, но недоступен по сети.

Решение от Michael Neale хорошее, но в соответствии с пит-файлами есть лучшее решение с переадресацией 301;)

ответил kmindi 23 J0000006Europe/Moscow 2012, 21:19:34
17

Вышеуказанное не работало с тем, что все новые поддомены создаются все время. например 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
# ...
}
ответил Aleck Landgraf 25 J0000006Europe/Moscow 2012, 08:29:06
16

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

# Force HTTPS connection. This rules is domain agnostic
if ($scheme != "https") {
    rewrite ^ https://$host$uri permanent;
}
ответил Oriol 31 J000000Friday15 2015, 22:50:48
6

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

Проблема возникает, когда на ваш сервер отправляется запрос POST. Если ответ сервера с простым 30x перенаправляет содержимое POST будет потеряно. Что происходит, так это то, что браузер /клиент обновит запрос до SSL, но downgrade 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"; 

       [....]
}
ответил Mahmoud Al-Qudsi 19 MarpmSun, 19 Mar 2017 23:24:33 +03002017-03-19T23:24:33+03:0011 2017, 23:24:33
4

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

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

ответил stamster 21 PMpThu, 21 Apr 2016 21:27:43 +030027Thursday 2016, 21:27:43
3

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

if ($http_x_forwarded_proto != 'https') {
    return 301 "https://www.exampl.com";
}
ответил MANCHUCK 4 Jpm1000000pmWed, 04 Jan 2017 20:09:18 +030017 2017, 20:09:18
0

Если вы 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 использует только first после server_name декларация и, что более важно, будет просто откликнуться на шаблон (не расширять его).

Итак, как поддерживать несколько доменов при сохранении безопасности? В моих собственных системах я столкнулся с этой дилеммой first , перечисляющей блок 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 совпадением none ваших законных доменов и подавать что-то оскорбительное. , , .

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

ответил Paul A Jungwirth 25 MaramSun, 25 Mar 2018 08:58:53 +03002018-03-25T08:58:53+03:0008 2018, 08:58:53
-1
rewrite ^!https https://$host$request_uri permanent;
ответил nntb2a 29 J0000006Europe/Moscow 2014, 08:33:12

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

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132