Как заставить или перенаправить на 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? (Кстати, я знаю, что есть плагины Rails, которые могут заставить SSL но надеялся избежать этого)

8 ответов

Решение

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

server {
    listen      80;
    server_name signup.mysite.com;
    rewrite     ^   https://$server_name$request_uri? permanent;
}

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

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

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

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, он избегает необходимости проверять переменную $ circuit при каждом запросе. А если серьезно, это настолько незначительная вещь, что вам не нужно их разделять.

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

Если вы используете новое определение двух серверов 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;
    }
}

Похоже, это работает для меня и не вызывает петли перенаправления.

Редактировать:

Заменены:

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

с линией переписывания Пратика.

Еще один вариант, который сохраняет заголовок запроса Host: и следует примеру "ХОРОШО" в ловушках 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

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

Я думаю, что это самое простое решение. Форсирует как 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;
    }
}

РЕДАКТИРОВАТЬ - Апр 2018: Решение без IF можно найти в моем сообщении здесь: https://stackoverflow.com/a/36777526/6076984

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

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

Другие вопросы по тегам