Apache (Linux) httpd listen on link-local IPv6 address

apache-2.4arch-linuxhttpd.confipv6link-local

I would like Apache to listen on the link-local ipv6 address on a particular interface. I have the following line in my httpd.conf:

Listen [fe80::a00:16ff:fe89:420f]:80

Which is based on the Apache documentation here: https://httpd.apache.org/docs/2.4/bind.html "IPv6 addresses must be enclosed in square brackets"

My operating system/Apache version details are as follows:

$ httpd -v
Server version: Apache/2.4.18 (Unix)
Server built:   Dec 14 2015 08:05:54
$ uname -rv
4.3.3-3-ARCH #1 SMP PREEMPT Wed Jan 20 08:12:23 CET 2016

The result shown using journalctl -e is:

(22)Invalid argument: AH00072: make_sock: could not bind to address [fe80…..

IPv6 is working because I have sshd and dnsmasq listening. I have tried appending two different scope ID suffixes to the address. You can use either the interface id 3 or name net1 as a scopeid in both ping6 and sshd.

$ ip addr | grep -Po "^\d: \S+"
1: lo:
2: net0:
3: net1:

$ for scopeid in 3 net1; do ping6 -c 1 fe80::a00:16ff:fe89:420f%$scopeid; done | grep loss
1 packets transmitted, 1 received, 0% packet loss, time 0ms
1 packets transmitted, 1 received, 0% packet loss, time 0ms

sshd_config works with either: ListenAddress fe80::a00:16ff:fe89:420f%3

or: ListenAddress fe80::a00:16ff:fe89:420f%net1

So with all this in mind I tried the following in httpd.conf

Listen [fe80::a00:16ff:fe89:420f%3]:80

and Listen [fe80::a00:16ff:fe89:420f%net1]:80

Adding either scopeid made Apache fail earlier in its start up process. journalctl -e shows a syntax error when parsing httpd.conf as follows:

AH00526: Syntax error on line 52 of /etc/httpd/conf/httpd.conf:
Scope id is not supported

Apache listens on the localhost ipv6 if I do Listen [::1]:80

I would expect Listen 80 to get Apache to bind to both ipv4 and ipv6, but it doesn't. It only binds to ipv6 addresses – netstat shows:

tcp6  0  0    :::80    :::*     LISTEN

In this case, Apache does accept requests on the link-local address on net1. I have to specify 0.0.0.0:80 or a specific ipv4 address for it to listen on ipv4.

So, how do I make Apache bind to one specific link-local address (not all of them – I want to avoid listening on other interfaces), or is it just not possible for Apache to listen on a link-local ipv6 address?

Best Answer

Having spent some time on this it seems that the Apache documentation could be misleading, although I may have missed something. It says IPv6 addresses must be enclosed in square brackets. This is true for non link-local addresses. But I have now discovered that link-local addresses can be used, and must include a scope id, but without the square brackets. See below:

Apache documentation:

$ wget -q -O- https://httpd.apache.org/docs/2.4/bind.html | grep -Pao "(?<=p.)IPv6[ a-z]+"
IPv6 addresses must be enclosed in square brackets

My configuration:

$ grep -R ^Listen /etc/httpd/conf/
/etc/httpd/conf/httpd.conf:Listen fe80::a00:16ff:fe89:420f%3:80
/etc/httpd/conf/extra/httpd-ssl.conf:Listen fe80::a00:16ff:fe89:420f%net1:443

As you can see, I've used the interface id for the scope id with port 80, and the interface name for the scope id with port 443. This is just to show that either the interface id or name can successfully be used as the scope id.

Results:

$ sudo netstat -pant | grep -i httpd
tcp6   0    0 fe80::a00:16ff:fe89::80 :::*  LISTEN   709/httpd
tcp6   0    0 fe80::a00:16ff:fe89:443 :::*  LISTEN   709/httpd