Вам нужны отдельные директивы для прослушивания IPv4 и IPv6 в nginx?

72

Я видел различные примеры конфигурации для работы с виртуальными хостами с двумя стеками IPv4 и IPv6 на nginx. Многие предлагают эту модель:

listen 80;
listen [::]:80 ipv6only=on;

Насколько я вижу, это достигается точно так же, как:

listen [::]:80 ipv6only=off;

Почему вы используете первый? Единственная причина, о которой я могу подумать, - это если вам нужны дополнительные параметры, специфичные для каждого протокола, например, если вы хотите установить только deferredIPv4.

Синхронная
источник
Задуманный как не имеющий ничего общего с версией стека IP, это опция TCP.
Ксавье Лукас
1
Конечно, но вы устанавливаете его в listenдирективах, и параметры применяются для пары хост: порт.
Synchro
Хм, я действительно не могу представить себе случай, когда вы захотите это сделать. Я думаю, что единственная причина - историческая, и Майкл Хэмптон прибил это.
Ксавье Лукас

Ответы:

48

Вероятно, это единственная причина, по которой вы бы использовали прежнюю конструкцию в наши дни.

Причина, по которой вы видите это, вероятно , заключается в том, что значение по умолчанию ipv6onlyизменилось в nginx 1.3.4. До этого он по умолчанию off; в новых версиях по умолчанию on.

Это происходит во взаимодействии с опцией сокета IPV6_V6ONLY в Linux и аналогичными опциями в других операционных системах, значения по умолчанию которых не всегда предсказуемы. Таким образом, прежняя конструкция требовалась до 1.3.4, чтобы убедиться, что вы действительно прослушиваете соединения как на IPv4, так и на IPv6.

Изменение по умолчанию для nginx ipv6onlyгарантирует, что значение по умолчанию для операционной системы для сокетов с двумя стеками не имеет значения. Теперь nginx либо явно привязывается к IPv4, IPv6, либо к обоим, независимо от того, какая ОС по умолчанию создает сокет с двумя стеками.

Действительно, мои стандартные конфигурации nginx для версии до 1.3.4 имеют первую конфигурацию, а все версии после 1.3.4 имеют вторую конфигурацию.

Хотя, поскольку привязка сокета с двумя стеками - это только для Linux, мои текущие конфигурации теперь больше похожи на первый пример, но без ipv6onlyнабора:

listen [::]:80;
listen 80;
Майкл Хэмптон
источник
4
Некоторые операционные системы вообще не поддерживают двойные сокеты ipv4 и ipv6, например OpenBSD, поэтому для этого вам придется прослушивать дважды.
Джастин Кормак,
@JustinCormack Да, вы правы, и я принял это во внимание в течение некоторого времени. Просто не обновил этот пост до сих пор.
Майкл Хэмптон
1
listen localhost:8080;кажется, что слушает оба (1.12.2) и использует proxy_pass http://localhost:8080баланс нагрузки между :: 1 и 127.0.0.1 - мне пришлось добавить строку для ipv6, чтобы получить реальный ip в логахset_real_ip_from 127.0.0.1; set_real_ip_from ::1; real_ip_header X-Forwarded-For;
Энтони Гиббс
65

Если вы размещаете несколько доменов vhost с одним экземпляром Nginx, вы не можете использовать одну объединенную директиву listen

listen [::]:80 ipv6only=off;

для каждого из них. Nginx имеет странную причуду, когда вы можете указать ipv6onlyпараметр только один раз для каждого порта, иначе он не запустится. Это означает, что вы не можете указать его для каждого блока сервера домена vhost.

Как упоминал Майкл, начиная с Nginx 1.3.4, этот ipv6onlyпараметр по умолчанию имеет значение on.

Поэтому, если вы хотите разместить несколько доменов на IPv4 и IPv6 на одном сервере Nginx, вы вынуждены использовать две директивы listen для каждого блока сервера домена:

listen 80;
listen [::]:80; 

Кроме того, как упомянул Сандер, у использования ipv6only=offесть недостаток, заключающийся в том, что адреса IPv4 преобразуются в IPv6. Это может вызвать проблемы, если ваше приложение выполняет проверку IP по черным спискам, таким как Akismet или StopForumSpam, потому что, если вы не создадите слой обратного перевода, ваше приложение будет проверять трансляцию IPv6 IPv4-адреса спаммера, который не будет совпадать ни с одним из IPv4-адресов в черный список.

Джефф Видман
источник
2
Да, это то же самое, что я упоминал deferred, и другие директивы для каждого протокола. Было бы полезно, если бы они могли быть указаны отдельно от директивы listen по той причине, о которой вы говорите.
Синхронный
1
И суть в том, что вам нужно указать директиву listen для каждого домена отдельно. Иначе что будет? сайт будет работать нормально через ipv4 и через ipv6 он покажет страницу приветствия nginx. ROFL
Серебряная Луна
2
Спасибо за подробное объяснение! Я получал непонятную ошибку, когда указывал один и ipv6only=offтот же порт дважды. Ваш ответ решил проблему!
1
Кроме того, если вы хотите использовать 2 ВХосты слушающих 443: listen 443; listen [::]:443;. Использование listen [::]:80 ipv6only=off;выдаст ошибку nginx, что порт уже используется
lukeaus
16

При использовании ipv6only=offстиля конфигурации адреса IPv4 могут отображаться как адреса IPv6 с использованием (только программных) адресов IPv6, сопоставленных с IPv4, например, в файлах журналов, переменных среды (REMOTE_ADDR) и т. Д.

Сандер Штеффанн
источник
3
Да, они показаны таким образом.
Майкл Хэмптон
2

Насколько я понимаю (и в соответствии с документами на http://nginx.org/en/docs/http/ngx_http_core_module.html#listen ), используя только

listen 80;

... достаточно, если вы хотите направить трафик IPv4 и IPv6 на один и тот же порт.

fevangelou
источник
1
Это уже установлено и упоминается в вопросе. Пожалуйста, посмотрите другие ответы на разницу.
Synchro
3
Это не для меня, мне нужны были оба. wget и curl, где происходит сбой при использовании ipv6, пока я не добавил строку «listen [::]: 80 ipv6only = on;»
Василий А