如何在Nginx中为每个域名分配不同的IPv6地址?
看起来你已经给每个域名在Nginx里指定了专属的IPv6监听地址,也配置好了DNS的AAAA记录,但遇到了出站请求(比如PHP的curl调用)总是用系统默认IPv6的问题——这是因为Linux默认会选网卡上的“主”IPv6作为所有出站流量的源地址,不管Nginx监听的是哪个IP。下面分两步帮你解决:
一、先确认系统已加载所有需要的IPv6地址
首先得确保服务器系统上真的配置了所有你要用到的IPv6,而不只是在控制面板里添加了。登录服务器执行命令:
ip -6 addr show
检查输出里有没有你给各个域名分配的IPv6(比如79de:d3e4:211c:3963:e2d5:4b9d:00b8:2c60)。如果某个IP没出现,就得手动在系统里配置:
Ubuntu 22.04用Netplan管理网络,编辑/etc/netplan/00-installer-config.yaml(文件名可能不同,找你的Netplan配置文件),添加额外IPv6:
network: ethernets: ens3: # 替换成你的网卡名,用`ip link show`查看 addresses: - 你的主IPv6/64 - 79de:d3e4:211c:3963:e2d5:4b9d:00b8:2c60/64 - 其他需要的IPv6/64 gateway6: 你的IPv6网关(通常是子网第一个IP,比如xxxx:xxxx:xxxx:xxxx::1) nameservers: addresses: [2606:4700:4700::1111, 2001:4860:4860::8888] version: 2
执行netplan apply让配置生效,再用ip -6 addr show确认所有IP都已加载。
二、解决PHP出站请求的源IP问题
方法1:在PHP代码中指定源IP(简单直接)
这种方法适合只需要调整curl请求的场景。你可以在Nginx里给每个域名传递对应的IPv6,再让curl用这个IP作为源地址。
- 修改Nginx的server配置,添加
fastcgi_param传递IP:
server { listen [79de:d3e4:211c:3963:e2d5:4b9d:00b8:2c60]:80; server_name sub.domain.com www.sub.domain.com; # 新增这行,把当前域名的IPv6传给PHP fastcgi_param PHP_SOURCE_IP "79de:d3e4:211c:3963:e2d5:4b9d:00b8:2c60"; access_log /var/log/nginx/sub.domain.com.access.log rt_cache; error_log /var/log/nginx/sub.domain.com.error.log; root /var/www/sub.domain.com/htdocs; index index.php index.html index.htm; include common/php81.conf; include common/locations-wo.conf; include /var/www/sub.domain.com/conf/nginx/*.conf; }
- 修改PHP代码,让curl使用指定的源IP:
<?php // 获取Nginx传递的IPv6地址 $sourceIp = $_SERVER['PHP_SOURCE_IP'] ?? ''; // 创建cURL资源 $ch = curl_init(); // 设置检测公网IP的目标URL curl_setopt($ch, CURLOPT_URL, "https://ipv6.icanhazip.com"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 强制用IPv6,并指定源IP if (!empty($sourceIp)) { curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6); curl_setopt($ch, CURLOPT_INTERFACE, $sourceIp); } // 执行请求并输出结果 $result = curl_exec($ch); curl_close($ch); echo "当前出站IPv6:" . $result; ?>
修改后重启服务:
systemctl restart nginx systemctl restart php8.1-fpm
现在访问这个PHP文件,应该会显示当前域名对应的IPv6了。
方法2:为每个域名创建独立PHP-FPM池(全站流量用对应IP)
如果你的网站有很多出站请求(不止curl),想让整个域名的PHP进程都用指定IPv6,可以给每个域名单独建PHP-FPM池,再配置路由规则绑定IP。
- 创建新的FPM池配置文件,比如
/etc/php/8.1/fpm/pool.d/sub.domain.com.conf:
[sub.domain.com] listen = /run/php/php8.1-fpm-sub.domain.com.sock listen.owner = www-data listen.group = www-data listen.mode = 0660 user = www-data group = www-data pm = dynamic pm.max_children = 5 pm.start_servers = 2 pm.min_spare_servers = 1 pm.max_spare_servers = 3 env[PATH] = /usr/local/bin:/usr/bin:/bin
- 修改Nginx的server块,让它使用这个新FPM池:
在当前server块里覆盖默认的FPM sock路径:
server { listen [79de:d3e4:211c:3963:e2d5:4b9d:00b8:2c60]:80; server_name sub.domain.com www.sub.domain.com; # 替换成新的FPM sock location ~ \.php$ { fastcgi_pass unix:/run/php/php8.1-fpm-sub.domain.com.sock; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } # 其他原有配置... }
- 配置路由规则,绑定FPM池到指定IPv6:
先创建新路由表并添加默认路由:
echo "100 subdomain" >> /etc/iproute2/rt_tables ip -6 route add default via 你的IPv6网关 src 79de:d3e4:211c:3963:e2d5:4b9d:00b8:2c60 table 100
再添加规则,让这个FPM池的进程(属于www-data用户)用这个路由表:
ip -6 rule add uidrange www-data-www-data lookup 100
为了让配置重启后生效,把命令加到/etc/rc.local(没有就创建,记得加执行权限chmod +x /etc/rc.local):
#!/bin/bash ip -6 route add default via 你的IPv6网关 src 79de:d3e4:211c:3963:e2d5:4b9d:00b8:2c60 table 100 ip -6 rule add uidrange www-data-www-data lookup 100 exit 0
最后重启服务:
systemctl restart php8.1-fpm systemctl restart nginx
这样这个域名下所有PHP进程的出站请求,都会用指定的IPv6地址。
备注:内容来源于stack exchange,提问作者TravelWhere

