0

A few days ago I configured lighttpd to listen on my VPS IPv6 address as well. It runs on a Debian 7 Xen VPS (Linode) with a 3.15.4-x86_64-linode45 kernel. The version of lighttpd is 1.4.31-4+deb7u3.

My lighttpd.conf used this configuration to listen to IPv4:

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

I added the following to enable IPv6 as per http://redmine.lighttpd.net/projects/lighttpd/wiki/IPv6-Config

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

Now, when I restarted lighttpd, everything was alright - it ended up listening to both as planned.

The problem appeared after I had to reboot my VPS. Turns out at boot time, starting lighttpd fails with the following message to the console:

[....] 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

If I login and run service lighttpd start it starts without a problem, listening on both IPv4 and IPv6.

I thought that maybe it didn't have the IPv6 address at boot time, so I made it output ifconfig to a file before attempting to start (in the init script) and it has both IPs assigned to the interface.

Any ideas what might be the problem or how to troubleshoot this further?

noaru
  • 3
  • 2

1 Answers1

3

When IPv6 addresses are configured they aren't available immediately. The system first performs DAD (Duplicate Address Detection) to make sure that its new address doesn't conflict with an existing address on another system. Applications cannot bind (at least not with default settings) to addresses that are still tentative.

Recent versions of the Debian ifupdown package contains a script called settle-dad.sh that will pause until the interface has left the tentative state. You might want to add such a script to your boot process between configuring the network interface and starting your servers.

It's not that big/complex:

#!/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

It is distributed under the GPLv2 license.

Sander Steffann
  • 7,572
  • 18
  • 29
  • 1
    Alternatively one could change the `accept_dad` setting to disable DAD. On a server with a static IP address, DAD isn't very useful after all. – kasperd Oct 21 '14 at 00:31
  • It makes sense, thanks. I'll try integrating it tonight as a dependency. Seeing as it's in sid I might spin it up in a VM to see how it's called. @kasperd Completely agree with you, but in this case the IP is assigned via DHCPv6. – noaru Oct 21 '14 at 17:52
  • If you get the address via dhcpv6 binding to "[::]:80" sounds like the better solution :) – Stefan Oct 22 '14 at 04:52
  • Yeah, getting an address through a dynamic protocol and then putting it statically in some other configuration files sounds like a unnecessary complication. I would personally do everything statically in such a case. – Sander Steffann Oct 22 '14 at 08:59
  • I agree that logically it doesn't make sense. But that DHCP binding is static (it's just an IP that can't be allocated via SLAAC) and its use is mandated by the whole VPS setup (ties in with DNS and their tools). – noaru Oct 24 '14 at 17:40
  • Integrating settle_dad.sh into existing scripts is more trouble than I have time for. Your answer is right though (thanks!), it is DAD that's preventing lighttpd from binding. I've solved it in a dirtier fashion by making the lighttpd start-up script wait until DAD is done. – noaru Oct 24 '14 at 17:43