Как перенаправить запросы https: // на http: // в NGINX? - PullRequest
39 голосов
/ 08 октября 2010

Есть ли способ перенаправить запросы https: // на http: //, добавив правило в файл vhost домена? Я использую NGINX.

Ответы [ 6 ]

33 голосов
/ 25 октября 2013

rewrite и if следует избегать с Nginx.Знаменитая строка: «Nginx - это не Apache»: другими словами, Nginx имеет лучшие способы обработки URL-адресов, чем переписывание.return все еще технически является частью модуля перезаписи, но он не несет издержек rewrite и не так подвержен предостережениям, как if.

Nginx имеет всю страницу на почему if является "злом" .Он также предоставляет конструктивную страницу, объясняющую , почему rewrite и if плохие , и как вы можете обойти это.Вот что говорит эта страница относительно rewrite и if:

Это неправильный, громоздкий и неэффективный способ.

Вы можете решить эту проблемуправильно используя return:

server {
    listen 443 ssl;

    # You will need a wildcard certificate if you want to specify multiple
    # hostnames here.
    server_name domain.example www.domain.example;

    # If you have a certificate that is shared among several servers, you
    # can move these outside the `server` block.
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/cert.key;

    # 301          indicates a permanent redirect.  If your redirect is
    #              temporary, you can change it to 302 or omit the number
    #              altogether.
    # $http_host   is the hostname and, if applicable, port--unlike $host,
    #              which will break on non-standard ports
    # $request_uri is the raw URI requested by the client, including any
    #              querystring
    return 301 http://$http_host$request_uri;
}

Если вы ожидаете, что многие боты не отправляют заголовок Host, вы можете использовать $host вместо $http_host, пока вы придерживаетесьпорты 80 и 443. В противном случае вам нужно будет динамически заполнить замену $http_host.Этот код эффективен и безопасен, пока он появляется в корне server (а не в блоке location), несмотря на использование if.Однако вам нужно будет использовать сервер по умолчанию, чтобы это было применимо, чего следует избегать с помощью https.

set $request_host $server_name:$server_port;
if ($http_host) {
    set $request_host $http_host;
}

Если вы хотите использовать SSL / TLS для определенных путей, но запретите это в противном случае:

server {
    listen 443 ssl;
    server_name domain.example;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/cert.key;

    location / {
        return 301 http://$host$request_uri;
    }

    location /secure/ {
        try_files $uri =404;
    }
}

server {
    listen 80;
    server_name domain.example;

    location / {
        try_files $uri =404;
    }

    location /secure/ {
        return 301 https://$http_host$request_uri;
    }
}

Если ваш сервер не имеет прямой связи с клиентом - например, если вы используете CloudFlare - все становится немного сложнее.Вам нужно будет убедиться, что любой сервер, имеющий прямую связь с клиентом, добавляет в запрос соответствующий заголовок X-Forwarded-Proto.

Использование этого беспорядочного предложения;полное объяснение см. IfIsEvil .Чтобы это было полезно, блок if не может быть внутри блока location по ряду сложных причин.Это заставляет использовать rewrite для тестирования URI. Короче говоря, если вам нужно использовать это на рабочем сервере ... не надо.Подумайте об этом так: если вы переросли Apache, вы переросли это решение.

/ secure, / secure / и все, что находится в / secure /, обеспечит применение https, тогда как все другие URIбудет обеспечивать http.(?! ) PCRE-конструкция является отрицательным прогнозным утверждением .(?: ) является не захватывающей группой .

server {
    # If you're using https between servers, you'll need to modify the listen
    # block and ensure that proper ssl_* statements are either present or
    # inherited.
    listen 80;
    server_name domain.example;

    if ($http_x_forwarded_proto = https) {
        rewrite ^(?!/secure)/ http://$http_host$request_uri? permanent;
    }
    if ($http_x_forwarded_proto != https) {
        rewrite ^/secure(?:/|$) https://$http_host$request_uri? permanent;
    }
}
33 голосов
/ 12 октября 2010

Почему что-то подобное полезно? На первый взгляд, я не был уверен, можно ли это сделать. Но он поставил интересный вопрос.

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

  1. Сервер выдаст перенаправление - то, что вы, похоже, хотите.
  2. Сервер сначала выполнит обмен https, а затем произведет перенаправление, в каком случае, какой смысл?

Добавлю больше, если я придумаю что-то более конкретное.

ОБНОВЛЕНИЕ: (пару часов спустя) Вы можете попробовать это. Вам нужно поместить это в ваш файл nginx.conf -

server {
       listen 443;
       server_name _ *;
       rewrite ^(.*) http://$host$1 permanent;
 }

Отправляет клиенту постоянное перенаправление. Я предполагаю, что вы используете порт 443 (по умолчанию) для https.

server {
    listen      80;
    server_name _ *;
    ...
}

Добавьте это, чтобы ваши обычные http-запросы на порт 80 не нарушались.

ОБНОВЛЕНИЕ: 18 декабря 2016 - server_name _ следует использовать вместо server_name _ * в версиях nginx> 0.6.25 (спасибо @Luca Steeb)

6 голосов
/ 12 октября 2010
location / {
    if ($scheme = https) {
        rewrite ^(.*)? http://$http_host$1 permanent;
    }
}
4 голосов
/ 16 октября 2013

этот вопрос лучше подошел бы для сайта serverfault.com.

Лучший способ сделать переадресацию на http:

server {
   listen 443;
   return 301 http://$host$request_uri;
}

Это позволит избежать предложения 'if'и регулярное выражение в переписывании, которые являются особенностями других решений на сегодняшний день.И то, и другое влияет на производительность, хотя на практике вам понадобится довольно много трафика, прежде чем это будет иметь значение.

В зависимости от настроек, вы, вероятно, захотите также указать ip в предложении listen,и, возможно, пункт о названии сервера в приведенном выше.Как это, он будет применяться ко всем запросам порта 443 для всех доменных имен.Обычно для каждого домена требуется IP-адрес с https, поэтому в большинстве случаев привязка вышеуказанного к IP-адресу более важна, чем привязка его к имени домена, но есть различия в этом, например, когда все домены являются поддоменами одного домена.

РЕДАКТИРОВАТЬ: TLS сейчас близка к универсальной, а вместе с ней идентификация имени сервера (SNI), которая позволяет HTTPS-сайтам в нескольких доменах с одним IP.Здесь хорошая статья

0 голосов
/ 16 июня 2015

Это помогло мне:

server {
    listen 443;
    server_name server.org www.server.org;
    rewrite ^ http://$server_name$request_uri? permanent;
}
0 голосов
/ 16 октября 2010

Единственное простое правило уже объяснено в посте выше меня:

server {
    listen ip:443;
    server_name www.example.com;
    rewrite ^(.*) http://$host$1 permanent;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...