Since Nginx 1.3.4, there's been a significant change in how IPv6 listeners behave. Previously, when you configured:
listen [::]:80 default_server;
Nginx would automatically handle both IPv4 and IPv6 connections. However, post-1.3.4, this directive now binds to IPv6 only by default.
The standard workaround is to add ipv6only=off
to each IPv6 listener:
listen [::]:80 default_server ipv6only=off;
While this works, it becomes tedious when managing multiple server blocks across different configuration files.
For system-wide configuration, you can add this to your nginx.conf in the main context (outside any http/server blocks):
resolver ... ipv6=off;
But this doesn't fully solve our specific listener behavior. A more comprehensive approach involves modifying the core Nginx compilation:
./configure --with-http_realip_module --with-ipv6-disable
For those who can't recompile Nginx, consider these patterns:
1. Dual listen directives:
listen 80;
listen [::]:80 ipv6only=off;
2. Configuration generator script (example in Bash):
find /etc/nginx -type f -name "*.conf" -exec sed -i 's/listen $$::$$:$[0-9]\+$;/listen [::]:\1 ipv6only=off;/g' {} +
After making changes, always test with:
nginx -t
service nginx reload
Verify with:
ss -tulnp | grep nginx
curl -4 http://yourdomain.com
curl -6 http://yourdomain.com
While this solution works, be aware that:
- Each dual-stack listener consumes slightly more memory
- Connection handling becomes marginally more complex
- Some older Nginx modules might not fully support this configuration
After upgrading to Nginx 1.3.4+, many administrators noticed their servers became inaccessible via IPv4 when using configurations like:
listen [::]:80 default_server;
This stems from a deliberate change in Nginx's behavior where IPv6 socket binding now defaults to IPV6_V6ONLY
flag being enabled, making the socket IPv6-exclusive.
The standard solution is to modify each virtual host configuration:
listen [::]:80 default_server ipv6only=off;
While this works, it becomes tedious in multi-site environments where dozens of configurations need updating.
For system-wide IPv6 dual-stack behavior, add this to your nginx.conf in the main context (outside any http/server blocks):
server {
listen [::]:80 default_server ipv6only=off;
# Other global server directives...
}
Then in individual virtual hosts, simply use:
listen 80;
listen [::]:80;
For Linux systems, you can disable IPv6-only binding system-wide by modifying /etc/sysctl.conf
:
net.ipv6.bindv6only = 0
Apply with sysctl -p
. This makes all IPv6 sockets dual-stack by default.
Verify your setup with:
curl -4 http://yourserver
curl -6 http://yourserver
netstat -tulnp | grep nginx
The output should show both IPv4 and IPv6 listening sockets.
When transitioning configurations:
- Test changes in staging first
- Document the IPv6 policy for your team
- Consider adding monitoring for protocol availability