前言
一般家宽不给开443端口(ipv4和ipv6检测到就封),所以我用8443替代https的默认443端口来反代。 但是方案要考虑同时支持ipv4和ipv6。 本文主要利用OpenResty将lxc容器 8443端口的ipv6流量 转发给443端口来实现ipv6同端口访问。
环境介绍
系统:pve
路由:pve-ikuai虚拟机
网关:pve-lxc容器安装的1panel
域名证书:所有要发布到公网的web服务都是用的同一个通配符证书(比如:*.a.com),由1panel申请、续期。
dns管理:cloudflare
前置条件,已经配置了ikuai的ipv6,内网设备能拿到公网ipv6地址(这一步网上有大把教程)
1. 双栈域名设置
- 使用ikuai的ddns(动态域名),将wan口的公网ip绑定到域名,比如a.com(A记录)
- 使用ikuai的ddns(动态域名),将lxc的容器ipv6绑定到域名(通过终端DUID配置),比如a.com(AAAA记录)
注意,ipv4和ipv6用的同一个域名。此时nslookup a.com能同时获取到ipv4和ipv6
2. ipv4设置
- ikuai做端口转发,将8443转发到lxc容器的443端口(同时转发8444作为备用)。这个配置只对ipv4有效
实现ipv4外网访问,只需此步骤即可。
3. ipv6设置
- 【重点】将lxc容器 8443端口的ipv6流量 转发给443端口 利用 1Panel 预置的 OpenResty(网站服务组件,是docker 容器)作为本地透明代理,将 8443端口的IPv6加密流量解密后转发给443端口(后续就和普通网页分发流程一样了):
-
找到OpenResty容器内的证书位置,因为都是用的同一个通配符证书,所以随便记录一个如
/www/sites/test1.a.com/ssl/fullchain.pem、/www/sites/test1.a.com/ssl/privkey.pem -
OpenResty容器内添加转发配置文件,
/usr/local/openresty/nginx/conf/nginx.conf/v6_bridge.conf:server { # 监听 IPv6 的 8443,不需要写死域名,支持所有域名 listen [::]:8443 ssl; server_name _; # 这里建议使用一个通用的证书,或者依然保留你现有的证书 ssl_certificate /www/sites/pve.966668.xyz/ssl/fullchain.pem; ssl_certificate_key /www/sites/pve.966668.xyz/ssl/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; location / { # 1. 动态传递主机名,这样后端 443 就能识别是哪个网站 proxy_set_header Host $http_host; # 2. 核心修正:透传 SNI 域名,解决 SSL internal error proxy_ssl_server_name on; proxy_ssl_name $http_host; # 3. 忽略后端证书校验(防止因为 127.0.0.1 不匹配证书名而报错) proxy_ssl_verify off; # 4. 转发给本地 443 proxy_pass https://127.0.0.1:443; # 保持 WebSocket 和其他 Header 支持 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }
proxy_set_header Host $http_host;:你浏览器里输入的是什么域名,它就原样传给后端 443。
proxy_ssl_name $http_host;:这是最关键的一行。它解决了你刚才 curl 看到的 SSL routines::tlsv1 alert internal error。它告诉后端 443 模块:“我要找的是这个域名的 SSL 证书”。
proxy_ssl_verify off;:因为你是转发到 127.0.0.1,证书里的域名通常是你的公网域名,这会导致校验失败,关掉校验可以确保 100% 转发成功。
- OpenResty容器内执行
openresty -t && openresty -s reload
拓扑图
【 互联网 (Internet)8443端口进 】
/ \
(IPv4) / \ (IPv6)
/ \
+-----------------------+ +-----------------------+
| iKuai / PVE 路由层 | | IPv6 直通 (Pass-thru) |
| (NAT 映射: 8443->443) | | (目标: LXC 容器 IPv6) |
+-----------+-----------+ +-----------+-----------+
| |
| (IPv4:443) | (IPv6:8443)
| |
________________|______________________________|_________________
| v v |
| +--------------------+ +-----------------------+ |
| | 1Panel 面板程序 | <----- | OpenResty (Nginx) | |
| | (监听 0.0.0.0:443) | proxy | (监听 [::]:8443) | |
| +---------+----------+ +-----------+-----------+ |
| | |
| | |
| [ 最终处理与响应 ] |
| |
| 【 LXC 容器内部环境 】 |
|_________________________________________________________________|
4. 测试
- 把ikuai转发的8443端口关闭(开启8444作为后备,防止在外失联)
- 使用蜂窝网络手机访问
test1.a.com:8443,能打开页面即成功(通过ipv6直接指向了lxc的8443端口) - 有ipv6的电脑测试:
curl -6 -v https://test1.a.com:8443
其他特殊nginx配置(已过时,仅参考)
transmission:端口区分
transmission的问题是静态资源加载不出来。
解决办法:除了默认的配置,还需要添加custom location:

location ^~ /transmission {
proxy_pass http://192.168.100.5:9091;
}按上述改了之后,就可以用https://群晖域名:8443/transmission访问transmission套件了。
参考
至于为啥非得加一个custom location,而且内容和界面上配置的是一样的,那我就不知道了。
当然,你如果不想重用群晖的域名,那直接用一个新域名配置反代即可:
这样不会出现静态js、css加载不出的问题
SurveillanceStation:路径区分
群晖的摄像机管理套件SurveillanceStation,是以路径挂载在群晖域名下区分管理的。
SurveillanceStation内置服务在接收到界面请求的时候会有一个重定向的动作,而这个重定向链接端口为访问来源的端口。
这时候你要问了,这不是很正常吗?对,这是正确的流程。
但是npm并不知道外部真正的访问端口是8443(路由器端口转发的),所以SurveillanceStation也不知道真正的访问端口。npm告诉SurveillanceStation它的默认端口是443,所以SurveillanceStation重定向的地址也是443端口:
xxx:8443 -> npm -> xxx:443 -> SurveillanceStation -> redirectxxx:443/webman
所以解决这个问题,我们除了添加套件服务的路径,还得手动改写请求头里的host端口:

location ^~ /webman {
proxy_pass http://192.168.100.5:5000; // 这里保持群晖的ip
proxy_set_header Host $host:8443; #这里是重点,这样配置才不会丢失端口
}按上述改了之后,就可以用https://群晖域名:8443/webman访问SurveillanceStation套件了。
ttyd:websocket协议升级
直接反代ttyd会报错,因为ws协议没有升级,location也不能直接写ttyd,这里给出解决方法:
location /ttyd {
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 1d; # dont kill connection after 60s of inactivity
proxy_pass http://127.0.0.1:7681/;
}按上述改了之后,就可以用https://群晖域名:8443/ttyd访问ttyd套件了。
alist:修改服务配置
群晖部署的alist套件,默认是5244端口,站点默认路径是根目录。请求的静态资源路径如:https://a.b.c:8443/alist/assets/index.f101cd32.js。所以一般是单独使用一个域名去代理。
如果想要代理到群晖的路径下,那么需要改alist的配置:如何对子目录进行反向代理,链接里的配置仅供参考,npm里不会生效,要采用transmission一样的方式。
- 改根路径为:
alist,进入群晖控制台,以root身份修改alist里的config.json:
/volume1/@appdata/alist3# vim config.json:
{
"force": false,
"site_url": "/alist",
...
}- 在群晖套件中心重启alist
- 配置npm

location ^~ /alist {
proxy_pass http://192.168.100.5:5244; #需要代理的服务器内网访问方式
}按上述改了之后,就可以用https://群晖域名:8443/alist访问alist套件了。