Как принудительно или перенаправлять SSL в nginx?

У меня есть страница регистрации в подобласте: https://signup.example.com

Он должен быть доступен только через HTTPS, но я волнуюсь, люди могут как-то наткнуться на него через HTTP и получить 404.

Мой блок html /server в nginx выглядит так:

html {
  server {
    listen 443;
    server_name signup.example.com;

    ssl                        on;
    ssl_certificate        /path/to/my/cert;
    ssl_certificate_key  /path/to/my/key;

    ssl_session_timeout 30m;

    location / {
      root /path/to/my/rails/app/public;
      index index.html;
        passenger_enabled on;
    }
  }
}

Что я могу добавить, чтобы люди, которые переходили на http://signup.example.com, перенаправлялись на https://signup.example.com? (FYI Я знаю, что есть плагины Rails, которые могут заставить SSL, но надеялись избежать этого)

205 голосов | спросил Callmeed 22 MarpmTue, 22 Mar 2011 21:45:14 +03002011-03-22T21:45:14+03:0009 2011, 21:45:14

8 ответов


134

Согласно ловушкам nginx , немного лучше опустить ненужный захват, используя $request_uri. В этом случае добавьте знак вопроса, чтобы nginx не удваивал любые аргументы запросов.

server {
    listen      80;
    server_name signup.mysite.com;
    rewrite     ^   https://$server_name$request_uri? permanent;
}
ответил Pratik Amin 22 MarpmTue, 22 Mar 2011 22:22:25 +03002011-03-22T22:22:25+03:0010 2011, 22:22:25
233

Лучший способ, описанный в официальном руководстве , заключается в использовании return директива:

server {
    listen      80;
    server_name signup.mysite.com;
    return 301 https://$server_name$request_uri;
}
ответил VBart 4 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowTue, 04 Sep 2012 03:50:41 +0400 2012, 03:50:41
104

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

server {
    listen   80;
    listen   [::]:80;
    listen   443 default_server ssl;

    server_name www.example.com;

    ssl_certificate        /path/to/my/cert;
    ssl_certificate_key  /path/to/my/key;

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

Все остальное, используя «переписать» или «если ssl_protocol» и т. д. медленнее и хуже.

Здесь то же самое, но даже более эффективно, запустив только переписывание протокола http, он избегает проверки переменной $ schem при каждом запросе. Но серьезно, это такая незначительная вещь, что вам не нужно их разделять.

server {
    listen   80;
    listen   [::]:80;

    server_name www.example.com;

    return 301 https://$server_name$request_uri;
}
server {
    listen   443 default_server ssl;

    server_name www.example.com;

    ssl_certificate        /path/to/my/cert;
    ssl_certificate_key  /path/to/my/key;
}
ответил DELETEDACC 1 FebruaryEurope/MoscowbFri, 01 Feb 2013 00:43:21 +0400000000amFri, 01 Feb 2013 00:43:21 +040013 2013, 00:43:21
56

Если вы используете новое определение двух HTTP и HTTPS-серверов, вы можете использовать следующее:

server {
    listen   80;
    listen   [::]:80;
    listen   443 default ssl;

    server_name www.example.com;

    ssl_certificate        /path/to/my/cert;
    ssl_certificate_key  /path/to/my/key;

    if ($ssl_protocol = "") {
       rewrite ^   https://$server_name$request_uri? permanent;
    }
}

Это, похоже, работает для меня и не вызывает переадресации циклов.

Edit:

Заменены:

rewrite ^/(.*) https://$server_name/$1 permanent;

с линией перезаписи Pratik.

ответил David Pashley 8 PM00000030000004531 2011, 15:12:45
26

Еще один вариант, который сохраняет заголовок Host: request и следует примеру «GOOD» на nginx ловушки :

server {
    listen   10.0.0.134:80 default_server;

    server_name  site1;
    server_name  site2;
    server_name  10.0.0.134;

    return 301 https://$host$request_uri;
}

Вот результаты. Обратите внимание, что использование $server_name вместо $host всегда будет перенаправляться на https://site1.

# curl -Is http://site1/ | grep Location
Location: https://site1/

# curl -Is http://site2/ | grep Location
Location: https://site2/


# curl -Is http://site1/foo/bar | grep Location
Location: https://site1/foo/bar

# curl -Is http://site1/foo/bar?baz=qux | grep Location
Location: https://site1/foo/bar?baz=qux
ответил Peter 11 PMpThu, 11 Apr 2013 16:20:06 +040020Thursday 2013, 16:20:06
3

Убедитесь, что вы установили «безопасный» на любые файлы cookie, иначе они будут отправлены по HTTP-запросу и могут быть схвачены с помощью инструмента, такого как Firesheep.

ответил W. Andrew Loe III 23 MaramWed, 23 Mar 2011 03:40:57 +03002011-03-23T03:40:57+03:0003 2011, 03:40:57
1
server {
    listen x.x.x.x:80;

    server_name domain.tld;
    server_name www.domian.tld;
    server_name ipv4.domain.tld;

    rewrite     ^   https://$server_name$request_uri? permanent;
}

Это работает лучше, я думаю. x.x.x.x относится к IP-адресу вашего сервера. Если вы работаете с Plesk 12, вы можете сделать это, изменив файл «nginx.conf» в каталоге «/var/www/vhosts/system/domain.tld/conf» для любого домена, который вы хотите. Не забудьте перезапустить службу nginx после сохранения конфигурации.

ответил Caner SAYGIN 23 PM000000110000002131 2014, 23:40:21
0

Я думаю, что это самое простое решение. Заставляет как HTTPS, так и не-WWW-трафик на HTTPS и только www.

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;
    }
}

EDIT - Apr 2018: Решение без IF's можно найти в моем сообщении здесь: https://stackoverflow.com/a /36777526/6076984

ответил stamster 21 PMpThu, 21 Apr 2016 21:30:29 +030030Thursday 2016, 21:30:29

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

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

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