Належне налаштування сервера nginx для замовчування для https


70

У мене є кілька серверів, які працюють на одній машині, деякі лише з http, деякі з http і https. Існує кілька блоків серверів, визначених в окремих файлах, які входять в основний конфігураційний файл.

Я створив сервер "за замовчуванням" для http, який буде обслуговувати загальну "сторінку обслуговування" для запитів, які не відповідають жодному з інших імен серверів у інших файлах конфігурації. Сервер http за замовчуванням працює, як очікувалося, він використовує ім'я_сервера "_", і воно з'являється першим у списку включень (тому що я помітив, що у випадку дублювання імен_сервер на всіх серверах використовується те, що з'являється першим). Це чудово працює.

Я б очікував того самого точного блоку сервера (лише переключення "прослухати 80 за замовчуванням_сервер" на "прослухати 443 за замовчуванням_сервер", а також замість того, щоб обслуговувати сторінку "повернути 444"), однак це не так. Натомість з'ясовується, що новий сервер https за замовчуванням насправді перехоплює всі вхідні з'єднання https та призводить до їх відмови, хоча інші блоки серверів мають більш відповідні імена_сервера для вхідних запитів. Видалення нового сервера https за замовчуванням призведе до відновлення напівправильної поведінки: всі веб-сайти з https завантажуватимуться правильно; але веб-сайти без https усі будуть перенаправлені на перший https-сервер у файлах включення (які згідно з документами, якщо не з'являється "default_server", тоді перший серверний блок, який з'явиться, буде "за замовчуванням").

Отже, моє запитання полягає в тому, який правильний спосіб визначити "сервер за замовчуванням" в nginx для ssl-з'єднань? Чому це так, що коли я явно встановлюю "default_server", він стає жадібним і захоплює всі з'єднання, тоді як коли я неявно дозволяю nginx вирішити "сервер за замовчуванням", він працює так, як я б очікував (з неправильним сервером, встановленим як за замовчуванням, та іншими реальними серверами поводиться правильно)?

Ось мої «сервери за замовчуванням». Http працює без злому інших серверів. Https розбиває інші сервери і споживає все.

server {
    listen 443 ssl default_server;
    server_name _;

    access_log /var/log/nginx/maintenance.access.log;
    error_log /var/log/nginx/maintenance.error.log error;

    return 444;
}

server {
    listen *:80 default_server;
    server_name _;
    charset utf-8;

    access_log /var/log/nginx/maintenance.access.log;
    error_log /var/log/nginx/maintenance.error.log error;

    root /home/path/to/templates;

    location / {
        return 503;
    }

    error_page 503 @maintenance;

    location @maintenance {
        rewrite ^(.*)$ /maintenance.html break;
    }
}

Хтось із вас бачить, що тут може бути не так?

ssl  https  nginx 

Відповіді:


27

У вас немає жодного ssl_certificate або ssl_certificate_key, визначеного у вашому блоці https "за замовчуванням". Хоча ви не маєте або не хочете справжнього ключа для цього сценарію за замовчуванням, вам все одно потрібно налаштувати один або інший nginx матиме небажану поведінку, яку ви описуєте.

Створіть самопідписаний сертифікат із загальним іменем * та підключіть його до своєї конфігурації, і він почне працювати так, як вам потрібно.

Поведінка за замовчуванням в рамках цього налаштування полягала б у тому, що браузер отримає попередження про те, що сертифікату не можна довіряти, якщо користувач додасть сертифікат як виняток, з'єднання буде перервано на nginx, і вони побачать за замовчуванням свого браузера Повідомлення про помилку "не вдалося підключити"


1
Я спробував це, але це все ще не працює: Усі запити ssl до IP переходять до мого іншого хоста ssl. Що ще я міг би спробувати?
Michael Härtl

22

Мені вдалося налаштувати спільний спеціалізований хостинг на одному IP з nginx. HTTP та HTTPS за замовчуванням, що обслуговують 404 для вхідних невідомих доменів.

1 - Створіть зону за замовчуванням

Оскільки nginx завантажує vhosts в порядку ascii, ви повинні створити 00-defaultфайл / символічне посилання у своє /etc/nginx/sites-enabled.

2 - Заповніть зону за замовчуванням

Заповніть свої 00-defaultстандартні привітання. Ось зона, яку я використовую:

server {
    server_name _;
    listen       80  default_server;
    return       404;
}


server {
    listen 443 ssl;
    server_name _;
    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;
    return       404;
}

3 - Створіть самопідписаний сертифікат, тестування та перезавантаження

Вам потрібно буде створити сертифікат самопідписання /etc/nginx/ssl/nginx.crt.

Створіть сертифікат самопідписання за замовчуванням:

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt

Просто нагадування:

  • Перевірте конфігурацію nginx перед перезавантаженням / перезапуском: nginx -t
  • Перезавантажте насолоду: sudo service nginx reload

Сподіваюся, це допомагає.


2
Не вирішує попередження браузера про відвідування незахищеного сайту.
gdbj

4
Неможливо вирішити, оскільки загальний вміст повинен відповідати будь-яким доменам. Жоден SSL не може підкреслити всі домени. Уявіть, що якщо ви підробляєте адресу google.fr на своєму сервері, ви зможете автентифікувати свій сервер як google.fr. Це було б серйозним питанням безпеки :(
Ifnot

Так, я думаю, це має сенс. На жаль, у Chrome ви отримуєте страхітливе попередження перед переглядом сторінки 404, що гірше, ніж сервер просто відхиляє трафік. Виглядає так, що сервер неправильно налаштований.
gdbj

Дуже дякую. Це працювало для мене, за винятком того, що мені довелося додати default_serverдля прослуховування 443, і я додав IPv6 адреси [::]: 80 та [::]: 443 с default_server.
chmike

16

Ми в основному хочемо за будь-яку ціну уникнути того, що перше визначення сервера в нашому конфігураційному файлі подається як сервер загального доступу для SSL-з'єднань. Ми всі знаємо, що це робить це (на відміну від http та використання конфігурації default_server, яка добре працює).

Цього неможливо досягти декларативно для SSL (поки що), тому нам доведеться кодувати його ІМЕ ...

Змінна $host- ім'я хоста з рядка запиту або заголовка http. Змінна $server_name- це ім'я блоку сервера, в якому ми зараз знаходимося.

Отже, якщо ці двоє не рівні, ви обслуговували цей блок SSL-сервера для іншого хоста, так що його слід заблокувати.

Код не містить конкретних посилань на IP-адреси вашого сервера, тому його можна легко використовувати для інших конфігурацій сервера без змін.

Приклад:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    ###
    ### Section: SSL

    #
    ## Check if this certificate is really served for this server_name
    ##   http://serverfault.com/questions/578648/properly-setting-up-a-default-nginx-server-for-https
    if ($host != $server_name) {
        #return 404 "this is an invalid request";
        return       444;
    }

    ...

Ви могли б пояснити, що listen [::]:443 ssl http2;робить? У мене виникають проблеми з пошуком документації на це.
Ендрю Браун

Я думаю, що я його знайшов, просто потрібно було знати, що шукати. Директиви IPV4 та IPV6.
Ендрю Браун

7

Детальніше про відповідь Радмілли Мустафи:

Nginx використовує заголовок "Хост" для відповідності імені сервера. Він не використовує TLS SNI. Це означає, що для SSL-сервера nginx повинен мати можливість приймати з'єднання SSL, яке зводиться до наявності сертифіката / ключа. Cert / ключ може бути будь-яким, наприклад самопідписаним.

Дивіться документацію

Отже, рішення таке:

server {
    server_name _;
    listen 80 default_server;
    listen 443 ssl default_server;

    ## To also support IPv6, uncomment this block
    # listen [::]:80 default_server;
    # listen [::]:443 ssl default_server;

    ssl_certificate <path to cert>;
    ssl_certificate_key <path to key>;
    return 404; # or whatever
}

Я відчуваю, що це повинна бути прийнята відповідь. Дуже дякую.
aggregate1166877

2

Для кожного, хто втратив стільки волосся над цим, як і я (витратив майже цілий день на це сьогодні). Я спробував майже все, і те, що змусило його нарешті правильно працювати, була ця дурна лінія:

ssl_session_tickets off;

Спираючись на відповідь Ifnot , моїм робочим прикладом є:

server {
    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;
    server_name _;

    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;
    ssl_session_tickets off;

    return 404;
}

Я не маю поняття, чому це було потрібно, єдиний принцип, який я вийшов з цього, - це те, що nginx поводиться дуже дивно, коли ми не даємо йому того, що він хоче.


1
ти легенда.
Нізар Блондин

1

Якщо ви хочете бути абсолютно впевненими, використовуйте окремі IP адреси для хостів, які не повинні відповідати на HTTPS та хостів, які повинні. Це також вирішує проблему попередження браузера "недійсний сертифікат".

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.