Назад | Перейти на главную страницу

lighttpd не запускается при загрузке после включения ipv6

Несколько дней назад я настроил lighttpd для прослушивания моего IPv6-адреса VPS. Он работает на Debian 7 Xen VPS (Linode) с 3.15.4-x86_64-linode45 ядро. Версия lighttpd - 1.4.31-4+deb7u3.

Мой lighttpd.conf использовал эту конфигурацию для прослушивания IPv4:

server.bind                 = "10.0.0.1"
server.port                 = 80

Я добавил следующее, чтобы включить IPv6 согласно http://redmine.lighttpd.net/projects/lighttpd/wiki/IPv6-Config

$SERVER["socket"] == "[2001:DB8::1]:80" {  }

Теперь, когда я перезапустил lighttpd, все было в порядке - в итоге он прослушал оба, как планировалось.

Проблема появилась после того, как мне пришлось перезагрузить свой VPS. Оказывается, во время загрузки запуск lighttpd завершается ошибкой с выводом на консоль следующего сообщения:

[....] Starting web server: lighttpd2014-10-20 21:00:19: (network.c.405)
       can't bind to port: 2001:DB8::1 80 Cannot assign requested address

Если я войду и бегу service lighttpd start он запускается без проблем, прослушивая как IPv4, так и IPv6.

Я подумал, что, возможно, во время загрузки у него не было адреса IPv6, поэтому я сделал вывод ifconfig в файл перед попыткой запуска (в сценарии инициализации), и оба IP-адреса назначены интерфейсу.

Есть идеи, в чем может быть проблема или как ее устранить?

Когда IPv6-адреса настроены, они не доступны сразу. Система сначала выполняет DAD (обнаружение повторяющегося адреса), чтобы убедиться, что ее новый адрес не конфликтует с существующим адресом в другой системе. Приложения не могут связываться (по крайней мере, с настройками по умолчанию) с адресами, которые все еще являются предварительными.

Последние версии Пакет Debian ifupdown содержит сценарий под названием settle-dad.sh это будет приостановлено, пока интерфейс не выйдет из предварительного состояния. Возможно, вы захотите добавить такой сценарий в процесс загрузки между настройкой сетевого интерфейса и запуском серверов.

Это не так уж и сложно:

#!/bin/sh

# 6 seconds maximum wait time
attempts=${IF_DAD_ATTEMPTS:-60}
delay=${IF_DAD_INTERVAL:-0.1}

[ $attempts -eq 0 ] && exit 0

echo -n "Waiting for DAD... "
for attempt in $(seq 1 $attempts); do
    tentative=$(ip -o -6 address list dev "$IFACE" to "${IF_ADDRESS}/${IF_NETMASK}" tentative | wc -l)
    if [ $tentative -eq 0 ]; then
        attempt=0 # This might have been our last attempt, but succesful
        break
    fi
    sleep $delay
done

if [ $attempt -eq $attempts ]; then
    echo "Timed out"
    exit 1
fi

dadfailed=$(ip -o -6 address list dev "$IFACE" to "${IF_ADDRESS}/${IF_NETMASK}" dadfailed | wc -l)

if [ $dadfailed -ge 1 ]; then
    echo "Failed"
    exit 1
fi

echo Done

Распространяется под Лицензия GPLv2.