Виртуальные хосты на основе имен nginx на IPv6

44

У меня есть сервер nginx, обслуживающий почти полдюжины разных сайтов. Он работает на Linode, который только что получил собственную поддержку IPv6 (центр обработки данных в Далласе), и я пытаюсь настроить большинство моих сайтов для работы с двумя стеками. Я получил первый и работающий с использованием субдомена только для IPv6:

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

    server_name example.com ipv6.example.com;

    root /var/www/example.com/htdocs;

    #More stuff, including PHP, WordPress
}

Это прекрасно работает - example.com только для IPv4 (на данный момент), а ipv6.example.com только для IPv6 (в основном там для целей тестирования). Я могу ping6 ipv6.example.com, и даже wget ipv6.example.comне потревожив - это было приятно безболезненно (после того, как я нашел «gotcha» с помощью способа, которым nginx связывает виртуальные хосты, требуя ipv6only=onаргумента и двойных listenдиректив).

Однако сейчас я пытаюсь расширить это для поддержки других моих доменов, начиная со static.example.com; однако, когда я использую тот же подход, что и выше (двойные listenдирективы, включая ipv6only=onаргумент), я получаю следующую ошибку при перезапуске nginx:

* Starting Nginx Server...
nginx: [emerg] a duplicate listen options for [::]:80 in /etc/nginx/sites-enabled/example.com.conf:3

Похоже, что метод привязки nginx для IPv6 не позволяет использовать виртуальные хосты на основе имен? Нужно ли мне получать дополнительные адреса IPv6 с моего хоста (не проблема) и использовать виртуальный хостинг на основе IP на IPv6 с виртуальным хостингом на основе имен через IPv4? Или мне не хватает решения, которое позволит моим конфигурациям оставаться согласованными в обоих стеках?

Я надеялся, что мой сайт будет полностью помещен в стек IPv6 как раз к Всемирному дню IPv6 , но, если я не смогу это быстро прояснить, я не буду готов. Ничего страшного с любой практической точки зрения - ни один из моих сайтов не может считаться «крупной организацией», как ни крути, но помогите мне сэкономить на этом!

Отредактировано, чтобы добавить:

Благодаря ответу @kolbyjack у меня теперь есть полнофункциональный веб-сервер с двумя стеками. Ради ясности, я редактирую решение, которое он дал мне, чтобы все могли ясно видеть ответ.

Мой по умолчанию catchall vhost имеет следующие listenдирективы:

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

Я не знаю, имеет ли значение порядок, но это так. Затем каждый дополнительный vhost имеет следующие listenдирективы:

listen 80;
listen [::]:80;

(Или 8080 для того, который вместо этого прослушивает этот порт.) Важной частью здесь, по-видимому, является полное отсутствие каких-либо дополнительных аргументов для всех, кроме listenдиректив vhost по умолчанию - т.е. нет повторения ipv6only=on.

Опять же, большое спасибо @kolbyjack за решение здесь!

Kromey
источник
С nginx 1.2.1 мне не нужно было указывать ipv6only=on. Однако все остальное осталось прежним, спасибо за это!
BeepDog

Ответы:

46

Вам нужны только параметры прослушивания в одном объявлении для сокета. Обычно вы помещаете их в объявление, которое также включает флаг default_server, но для некоторых опций, я думаю, вы можете просто установить их в любой директиве listen. Просто удалите ipv6only = on из всех прослушиваний, кроме одного.

kolbyjack
источник
2
Подожди, я в замешательстве. Я подумал, что требуется по крайней мере одна директива listen для каждой декларации сервера - иначе как бы nginx узнал, с каким блоком сервера предполагается отвечать на какой порт (ы)? Я не упомянул об этом выше, потому что я не думал, что это уместно, но у меня есть один сервер на 8080, остальные на 80, и я собираюсь предложить 443 для пары, так же, как только я сгладил это и тогда получите себе сертификат SSL.
Кромей
Ладно, еще раз посмотрев документацию, сайты, которые находятся на порте 80, выглядят так, как будто им вообще не нужна директива listen, только одна с флагом default_server на моем сборном виртуальном хосте. Тем не менее, это все еще не удается для моего сервера на 8080, для которого я также использую перехват по умолчанию (перехват написан так, чтобы просто игнорировать любые запросы имени хоста, которые я явно не настроил в другом vhost).
Кромей
1
Я не говорю, чтобы удалить все ваши директивы прослушивания. Просто удалите флаг ipv6only = on из всех, кроме одного. Без директивы listen на каждом сервере они по умолчанию будут просто слушать 80; который может включать или не включать ipv6. Я думаю, что правильный подход - включить обе директивы listen на каждом сервере, но включить ipv6only = только на одном из серверов.
kolbyjack
4
Ах, теперь я понимаю, что вы имеете в виду. Я неправильно прочитал ваш пост. Это сработало для меня: ipv6only=onтолько перечислено (для каждого порта, который я слушаю) в моем по умолчанию vhost (рядом default_server); тогда каждый vhost просто указывает listen 80;и listen [::]:80(без дополнительных параметров) функционирует как на IPv4, так и на IPv6. Теперь все, что мне нужно сделать, это закончить добавление записей AAAA для моих доменов с двумя стеками, и я должен быть здесь. Благодарность!
Кромей
1
работал для меня, но я не понимаю, почему я nginx может слушать на ipv4 для нескольких блоков, но не ipv6. , Вы можете объяснить ?
Aeerlike