本教程将向您展示如何使用 HAProxy 在同一台机器上运行 OpenConnect VPN 服务器 (ocserv) 和 Apache/Nginx。 OpenConnect (ocserv) 是 Cisco AnyConnect VPN 协议的开源实现。
vpn-server-apache-nginx-haproxy/ocserv-apache-nginx-haproxy.png" style="font-family: "Open Sans"; font-size: 16px; text-align: justify; text-wrap: wrap; box-sizing: border-box; color: rgb(0, 123, 255); text-decoration-line: none;">
先决条件
为了学习本教程,假设您已经使用 Let’s Encrypt TLS 服务器证书设置了 OpenConnect VPN 服务器。如果没有,请按照以下教程之一进行操作。
-
使用 Let’s Encrypt 在 Ubuntu 20.04 上设置 OpenConnect VPN 服务器 (ocserv)
-
使用 Let’s Encrypt 在 Ubuntu 16.04/18.04 上设置 OpenConnect VPN 服务器 (ocserv)
-
使用 Let’s Encrypt 在 Debian 10 Buster 上设置 OpenConnect VPN 服务器 (ocserv)
-
使用 Let’s Encrypt 在 CentOS 8/RHEL 8 上设置 OpenConnect VPN 服务器 (ocserv)
使 OpenConnect VPN 服务器和 Web 服务器同时使用端口 443
默认情况下,OpenConnect VPN 服务器侦听端口 443。如果您已经有 Apache/Nginx 侦听端口 443,则 ocserv 无法绑定到端口 443。您可以将 ocserv 配置为侦听另一个端口,但这需要最终用户在客户端软件中指定端口,如果您关心用户体验,则应避免这样做。此外,TCP 端口 443 上的 TLS 流量通常在 QoS(服务质量)方面享有更高的优先级,因此您将获得更好的速度。
通常情况下,一个端口只能被一个进程使用。但是,我们可以使用HAproxy(高可用性代理)和SNI(服务器名称指示)来使ocserv和Apache/Nginx同时使用端口443。
观察服务配置
首先,编辑 ocserv 配置文件。
sudo nano /etc/ocserv/ocserv.conf
取消注释以下行。这将允许 ocserv 获取客户端 IP 地址而不是 HAproxy IP 地址。
listen-proxy-proto = true
然后找到以下行。
#listen-host = [IP|HOSTNAME]
将其更改为
listen-host = 127.0.0.1
这将使 ocserv 侦听 127.0.0.1,因为稍后 HAproxy 将需要侦听公共 IP 地址。保存并关闭文件。然后重新启动 ocserv。
sudo systemctl restart ocserv
接下来,我们还需要让 Web 服务器仅侦听本地主机,而不是侦听公共 IP 地址。
Nginx 配置
如果您使用 Nginx,请编辑服务器块文件。
sudo nano /etc/nginx/conf.d/example.com.conf
在 SSL 服务器块中,找到以下指令。
listen 443 ssl;
将其更改为
listen 127.0.0.2:443 ssl;
这次我们让它监听 127.0.0.2:443
,因为 127.0.0.1:443
已被 ocserv 占用。保存并关闭文件。 Nginx 主配置文件 /etc/nginx/nginx.conf
和默认服务器块 /etc/nginx/sites-enabled/default
可能包含监听的默认虚拟主机443,所以您可能还需要编辑此文件。
然后重新启动Nginx。
sudo systemctl restart nginx
阿帕奇配置
如果您使用 Apache Web 服务器,请编辑您的虚拟主机文件。
Debian/Ubuntu
sudo nano /etc/apache2/sites-enabled/example.com.conf
CentOS/RHEL
sudo nano /etc/httpd/conf.d/example.com.conf
在SSL虚拟主机中,更改
<VirtualHost *:443>
到
<VirtualHost 127.0.0.2:443>
这次我们让它监听 127.0.0.2:443
,因为 127.0.0.1:443
已被 ocserv 占用。保存并关闭文件。
然后在 Debian/Ubuntu 上编辑 /etc/apache2/ports.conf
文件。
sudo nano /etc/apache2/ports.conf
在 CentOS/RHEL 上编辑 /etc/httpd/conf.d/ssl.conf
文件。
sudo nano /etc/httpd/conf.d/ssl.conf
改变
Listen 443
到
Listen 127.0.0.2:443
保存并关闭文件。重新启动阿帕奇。
sudo systemctl restart apache2
或者
sudo systemctl restart httpd
HAProxy 配置
现在安装 HAproxy。
sudo apt install haproxy
或者
sudo dnf install haproxy
启动HAProxy
sudo systemctl start haproxy
编辑配置文件。
sudo nano /etc/haproxy/haproxy.cfg
如果您使用 Nginx,请将以下行复制并粘贴到文件末尾。将 12.34.56.78
替换为您服务器的公共 IP 地址。将 vpn.example.com
替换为 ocserv 使用的域名,将 www.example.com
替换为您的 Web 服务器使用的域名。
frontend https bind 12.34.56.78:443 mode tcp tcp-request inspect-delay 5s tcp-request content accept if { req_ssl_hello_type 1 } use_backend ocserv if { req_ssl_sni -i vpn.example.com } use_backend nginx if { req_ssl_sni -i www.example.com } use_backend nginx if { req_ssl_sni -i example.com } default_backend ocserv backend ocserv mode tcp option ssl-hello-chk # pass requests to 127.0.0.1:443. Proxy protocol (v2) header is required by ocserv. server ocserv 127.0.0.1:443 send-proxy-v2 backend nginx mode tcp option ssl-hello-chk server nginx 127.0.0.2:443 check
如果您使用 Apache,请将以下行复制并粘贴到文件末尾。将 12.34.56.78
替换为您服务器的公共 IP 地址。将 vpn.example.com
替换为 ocserv 使用的域名,将 www.example.com
替换为您的 Web 服务器使用的域名。
frontend https bind 12.34.56.78:443 mode tcp tcp-request inspect-delay 5s tcp-request content accept if { req_ssl_hello_type 1 } use_backend ocserv if { req_ssl_sni -i vpn.example.com } use_backend apache if { req_ssl_sni -i www.example.com } use_backend apache if { req_ssl_sni -i example.com } default_backend ocserv backend ocserv mode tcp option ssl-hello-chk # pass requests to 127.0.0.1:443. Proxy protocol (v2) header is required by ocserv. server ocserv 127.0.0.1:443 send-proxy-v2 backend apache mode tcp option ssl-hello-chk server apache 127.0.0.2:443 check
保存并关闭文件。然后重新启动HAProxy。
sudo systemctl restart haproxy
在上面的配置中,我们利用 TLS 中的 SNI(服务器名称指示)功能来区分 VPN 流量和普通 HTTPS 流量。
-
当
vpn.example.com
位于 TLS Client Hello 中时,HAProxy 将流量重定向到 ocserv 后端。 -
当
www.example.com
位于 TLS Client Hello 中时,HAProxy 将流量重定向到 apache/nginx 后端。 -
如果客户端未在 TLS Client Hello 中指定服务器名称,则 HAproxy 将使用默认后端 (ocserv)。
您可以使用 openssl
工具测试此设置。首先,多次运行以下命令。
echo | openssl s_client -connect your-server-IP:443 | grep subject
我们在上面的命令中没有指定服务器名称,因此 HAproxy 始终会将请求传递到默认后端(ocserv),并且其证书将发送到客户端。接下来,运行以下两个命令。
echo | openssl s_client -servername www.example.com -connect your-server-IP:443 | grep subjectecho | openssl s_client -servername vpn.example.com -connect your-server-IP:443 | grep subject
现在我们在命令中指定了服务器名称,因此HAproxy将根据我们定义的SNI规则传递请求。请注意,Cisco AnyConnect 应用程序不支持 TLS SNI,因此最好在 HAProxy 配置文件中将 ocserv 设置为默认后端。
为您的网站续订 Let's Encrypt 证书时,建议您使用 http-01
质询而不是 tls-alpn-01
质询,因为 HAproxy 正在侦听 443 端口公共 IP 地址,因此它可能会干扰续订过程。
sudo certbot renew --preferred-challenges http-01
修复 HAproxy 错误
如果您的 Apache/Nginx 网站未显示在浏览器中,并且您在 haproxy 日志 (/var/log/haproxy.log
) 中看到以下消息
Server nginx/nginx is DOWN, reason: Socket error, info: "Connection reset by peer backend nginx has no server available! Layer6 invalid response
可能是您的后端 Nginx Web 服务器正在使用带有 OCSP 必须装订扩展名的 TLS 证书。 Nginx 不会在第一个 HTTP 请求上发送 OCSP 主要信息。为了使其正常工作,请务必在 Nginx 虚拟主机配置中添加解析器,如下所示。
{ .... ssl_trusted_certificate /etc/letsencrypt/live/www.example.com/chain.pem; ssl_stapling on; ssl_stapling_verify on; resolver 8.8.8.8; .... }
保存并关闭文件。然后重新启动Nginx。
sudo systemctl restart nginx
另外,请考虑删除 HAproxy 中后端服务器的健康检查。所以改变
server nginx 127.0.0.2:443 check
到
server nginx 127.0.0.2:443
保存并关闭文件。然后重新启动HAProxy。
sudo systemctl restart haproxy
如何使用 HAProxy 在 ocserv 中启用 IPv6
首先,在 DNS 区域编辑器中为 vpn.example.com
创建 AAAA 记录,因此当您在 ocserv 中完成 IPv6 设置后,DNS 记录应该传播到 Internet。
测试 IPv6 连接性
要使用 IPv6 协议建立 VPN 隧道,请确保 VPN 服务器具有公共 IPv6 地址。 (VPN 客户端不必具有公共 IPv6 地址。)要查找答案,请运行以下命令。
ip addr
找到主网络接口。如果您可以找到如下所示的 inet6 ....scope global
行,那么您就有了公共 IPv6 地址。带有范围链接
的inet6
地址是私有IPv6地址。
然后转到 https://test-ipv6.com/ 检查您的 IPv6 连接。如果 VPN 客户端具有公共 IPv6 地址,它可能会告诉您您的 VPN 仅保护一种协议,而不是同时保护两种协议。那是因为我们没有在 ocserv 中启用 IPv6。
在 ocserv 中启用 IPv6
要在 ocserv 中启用 IPv6,请编辑 ocserv 配置文件。
sudo nano /etc/ocserv/ocserv.conf
找到以下两行并取消注释,这样 VPN 客户端就会获得私有 IPv6 地址。
ipv6-network = fda9:4efe:7e3b:03ea::/48ipv6-subnet-prefix = 64
如果您看到以下行
ipv6-network = fda9:4efe:7e3b:03ea::/64
请更改为:
ipv6-network = fda9:4efe:7e3b:03ea::/48
保存并关闭文件。重新启动 ocserv 以使更改生效。
sudo systemctl restart ocserv
启用 IPv6 的 IP 转发
然后我们需要在Linux内核中启用IPv6的IP转发。编辑 sysctl.conf 文件。
sudo nano /etc/sysctl.conf
在此文件末尾添加以下行。
net.ipv6.conf.all.forwarding=1
保存并关闭文件。然后使用以下命令应用更改。
sudo sysctl -p
在防火墙中设置 IPv6(Debian、Ubuntu)
接下来,我们需要在UFW防火墙中设置IPv6伪装,使服务器成为VPN客户端的虚拟路由器。
sudo nano /etc/ufw/before6.rules
默认情况下,filter
表有一些规则。在此文件末尾添加以下行。将 ens3 替换为您自己的网络接口名称。在 Nano 文本编辑器中,您可以按 Ctrl+W
,然后按 Ctrl+V
转到文件末尾。
# NAT table rules*nat :POSTROUTING ACCEPT [0:0]-A POSTROUTING -o ens3 -j MASQUERADE # End each table with the 'COMMIT' line or these rules won't be processed COMMIT
缺省情况下,UFW 禁止报文转发。我们可以允许转发我们的私有 IPv6 网络。在此文件中找到 ufw6-before-forward 链,添加以下 3 行,如果源 IP 或目标 IP 在 fda9:4efe:7e3b:03ea 中,则将接受数据包转发::/48
范围。
# allow forwarding for VPN-A ufw6-before-forward -s fda9:4efe:7e3b:03ea::/48 -j ACCEPT-A ufw6-before-forward -d fda9:4efe:7e3b:03ea::/48 -j ACCEPT
保存并关闭文件。我们还需要在防火墙的 INPUT 链中允许 IPv6 VPN 客户端。
sudo ufw allow in from fda9:4efe:7e3b:03ea::/48
重新启动 UFW 以使更改生效。
sudo systemctl restart ufw
现在,如果您使用以下命令列出 NAT 表的 POSTROUTING 链中的规则:
sudo ip6tables -t nat -L POSTROUTING
你可以看到假面舞会规则。
断开当前的 VPN 连接,为 vpn.example.com
添加 AAAA 记录并重新建立 VPN 连接。然后转到 https://test-ipv6.com/ 检查您的 IPv6 连接。
在防火墙中设置 IPv6 (CentOS)
启用 IPv6 伪装。
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv6" source address="fda9:4efe:7e3b:03ea::/48" masquerade'
允许 INPUT 链中的 VPN 客户端。
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv6" source address="fda9:4efe:7e3b:03ea::/48" accept'
重新加载firewalld以使更改生效。
sudo systemctl reload firewalld
在 BIND 解析器中配置 IPv6
如果您在 VPN 服务器上运行自己的 BIND DNS 解析器,则可以在 /etc/ocserv/ocserv.conf
文件中添加以下行,将 VPN 服务器设置为 VPN 客户端的 DNS 解析器。
dns = fda9:4efe:7e3b::1
保存并关闭文件。要查询 IPv6 中的 DNS 名称,我们需要配置 BIND 以允许 IPv6 VPN 客户端。
Debian/Ubuntu
sudo nano /etc/bind/named.conf.options
找到 allow-recursion
参数并将其更改为:
allow-recursion { 127.0.0.1; 10.10.10.0/24; fda9:4efe:7e3b:03ea::/48; };
保存并关闭文件。重新启动 BIND9。
sudo systemctl restart bind9
中央操作系统
sudo nano /etc/named.conf
找到 allow-query
参数并将其更改为:
allow-query { 127.0.0.1; 10.10.10.0/24; fda9:4efe:7e3b:03ea::/48; };
保存并关闭文件。重新启动 BIND9。
sudo systemctl restart named
在 HAProxy 中设置 IPv6
编辑 HAProxy 配置文件。
sudo nano /etc/haproxy/haproxy.cfg
让 https
前端同时侦听 IPv4 和 IPv6 地址。显然您需要使用自己服务器的公共 IPv6 地址。
frontend https bind 12.34.56.78:443 bind 2607:f8b0:4006:810::200e:443 mode tcp tcp-request inspect-delay 5s tcp-request content accept if { req_ssl_hello_type 1 }
然后找到 ocserv 后端并添加 IPv6 服务器。
backend ocserv mode tcp option ssl-hello-chk server ocserv 127.0.0.1:443 send-proxy-v2 server ocserv6 [::1]:443 send-proxy-v2
保存并关闭文件。
要使 ocserv 同时侦听 127.0.0.1
和 ::1
,请编辑 /etc/hosts
文件。
sudo nano /etc/hosts
如下所示编辑 127.0.0.1
和 ::1
条目,以便可以将 vpn.example.com
主机名解析为这两个地址。
127.0.0.1 localhost vpn.example.com ::1 ip6-localhost ip6-loopback vpn.example.com
保存并关闭文件。然后编辑ocserv配置文件。
sudo nano /etc/ocserv/ocserv.conf
找到以下行。
listen-host = 127.0.0.1
将其更改为
listen-host = vpn.example.com
ocserv 将在 /etc/hosts
文件中查找 vpn.example.com
的 IPv4 和 IPv6 地址,并绑定到 127.0.0.1
和::1
地址。保存并关闭文件。然后重新启动ocserv和HAProxy
sudo systemctl restart ocserv sudo systemctl restart haproxy
现在运行以下命令来检查 ocserv 的监听状态。您将看到它正在监听 127.0.0.1
和 ::1
。
sudo ss -lnpt | grep ocserv
测试 IPv6 连接性
重新启动您的 VPN 客户端并转到 https://test-ipv6.com/ 检查您的 IPv6 连接。如果一切顺利,您应该在测试结果中看到 VPN 服务器的 IPv4 和 IPv6 地址。 “VPN 仅保护一种协议”的警告应该消失。
如果您在测试结果中没有看到 VPN 服务器的 IPv6 地址,也许您需要重新启动 VPN 客户端并重新建立 VPN 连接。
注意:VPN 客户端不必具有公共 IPv6 地址。它可以通过 IPv4 VPN 隧道使用 IPv6。
推荐本站淘宝优惠价购买喜欢的宝贝:
以下内容需要兑换:本文链接:https://hqyman.cn/post/8624.html 非本站原创文章欢迎转载,原创文章需保留本站地址!
休息一下~~