28
2024
11
10:49:13

使用 HAProxy 在同一台机器上运行 OpenConnect VPN 服务器和 Apache/Nginx

本教程将向您展示如何使用 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。




推荐本站淘宝优惠价购买喜欢的宝贝:

image.png

以下内容需要兑换:

本文链接:https://www.hqyman.cn/post/8624.html 非本站原创文章欢迎转载,原创文章需保留本站地址!

分享到:
打赏





休息一下~~


« 上一篇 下一篇 »

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

请先 登录 再评论,若不是会员请先 注册

您的IP地址是: