When expanding Nginx configurations to support IPv6 alongside existing IPv4 name-based virtual hosts, many administrators encounter the frustrating "duplicate listen options" error. This occurs because of how Nginx handles socket binding in dual-stack environments.
The fundamental problem stems from Nginx's requirement for explicit default server declarations in IPv6 configurations. Unlike IPv4 where the first server block implicitly becomes the default, IPv6 requires explicit declaration using default_server
parameter.
# Problematic configuration causing the error
server {
listen [::]:80 ipv6only=on; # This causes conflicts
listen 80;
server_name site1.example.com;
}
server {
listen [::]:80 ipv6only=on; # Duplicate option error
listen 80;
server_name site2.example.com;
}
The solution involves establishing a clear default server for IPv6 while keeping other virtual hosts simple:
# Default catch-all server
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
server_name _;
return 444; # Close connection without response
}
# Regular virtual hosts
server {
listen 80;
listen [::]:80; # Notice no ipv6only parameter here
server_name site1.example.com;
root /var/www/site1;
}
server {
listen 80;
listen [::]:80;
server_name site2.example.com;
root /var/www/site2;
}
For more complex setups involving multiple ports or SSL configurations:
# HTTPS configuration example
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name secure.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# SSL configuration directives...
}
# Port-specific configuration
server {
listen 8080;
listen [::]:8080;
server_name dev.example.com;
}
After implementing these changes, verify your configuration with:
nginx -t
service nginx reload
Test connectivity using both IPv4 and IPv6 tools:
curl -4 http://example.com
curl -6 http://example.com
ping6 example.com
When running dual-stack configurations:
- Ensure your DNS has both A (IPv4) and AAAA (IPv6) records
- Monitor connection statistics separately for each protocol
- Consider implementing Happy Eyeballs for optimal client connectivity
When implementing IPv6 support for multiple websites on nginx, many administrators encounter the "duplicate listen options" error. This occurs because nginx handles IPv6 binding differently than IPv4 when using name-based virtual hosts.
For a basic single-site setup, this configuration works well:
server {
listen [::]:80 ipv6only=on;
listen 80;
server_name example.com ipv6.example.com;
root /var/www/example.com/htdocs;
# Additional configuration
}
When attempting to add additional virtual hosts with similar configurations:
server {
listen [::]:80 ipv6only=on;
listen 80;
server_name static.example.com;
root /var/www/static.example.com/htdocs;
# Additional configuration
}
This triggers the error: nginx: [emerg] a duplicate listen options for [::]:80
The key is to properly configure your default server first, then simplify the virtual host declarations:
Default Server Configuration
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
server_name _;
return 444; # Silent drop for unmatched hosts
}
Virtual Host Configuration
For each named virtual host, use simplified listen directives:
server {
listen 80;
listen [::]:80;
server_name example.com ipv6.example.com;
root /var/www/example.com/htdocs;
# Site-specific configuration
}
server {
listen 80;
listen [::]:80;
server_name static.example.com;
root /var/www/static.example.com/htdocs;
# Site-specific configuration
}
1. The ipv6only=on
parameter should only appear in the default server block
2. Order of listen directives doesn't matter
3. Each virtual host must have both IPv4 and IPv6 listen directives
4. Port numbers must be consistent between protocol versions
After implementing these changes:
sudo nginx -t # Test configuration
sudo systemctl restart nginx # Apply changes
Verify with:
curl -I http://example.com
curl -6 -I http://example.com
For SSL/TLS configurations, the same pattern applies:
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name secure.example.com;
root /var/www/secure.example.com/htdocs;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# SSL configuration
}