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

本教程将向您展示如何使用HAProxy在同一盒上运行OpenConnect VPN服务器(ocserv)和Apache / Nginx。 OpenConnect(ocserv)是Cisco AnyConnect VPN协议的开源实现。

先决条件

为了遵循本教程,假定您已经使用“让我们加密TLS”服务器证书设置了OpenConnect VPN服务器。 如果没有,请按照以下教程之一进行操作。

  • 使用Let’s Encrypt在Ubuntu 20.04上设置OpenConnect VPN服务器(ocserv)
  • 使用Let’s Encrypt在Ubuntu 16.04 / 18.04上设置OpenConnect VPN服务器(ocserv)
  • 让我们加密在Debian 10 Buster上设置OpenConnect VPN服务器(ocserv)
  • 使用“让我们加密”在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配置

首先,编辑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服务器仅在localhost上侦听,而不是在公共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配置

如果使用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占用。 保存并关闭文件。

然后编辑 /etc/apache2/ports.conf Debian / Ubuntu上的文件。

sudo nano /etc/apache2/ports.conf

编辑/etc/httpd/conf.d/ssl.conf CentOS / RHEL上的文件。

sudo nano /etc/httpd/conf.d/ssl.conf

更改

Listen 443

Listen 127.0.0.2:443

保存并关闭文件。 重新启动Apache。

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
   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
   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客户端Hello中,HAProxy将流量重定向到ocserv后端。
  • 什么时候 www.example.com 在TLS客户端Hello中,HAProxy将流量重定向到apache / nginx后端。
  • 如果客户端未在TLS客户端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 subject

echo | openssl s_client -servername vpn.example.com -connect your-server-IP:443 | grep subject

现在我们在命令中指定了服务器名称,因此HAproxy将根据我们定义的SNI规则传递请求。 请注意,Cisco AnyConnect应用程序不支持TLS SNI,因此最好进行设置 ocserv 作为HAProxy配置文件中的默认后端。

为您的网站续订“让我们加密”证书时,建议您使用 http-01 挑战而不是 tls-alpn-01 挑战,因为HAproxy正在侦听公共IP地址的端口443,因此它可能会干扰续订过程。

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服务器正在将TLS证书与OCSP一起使用时必须使用扩展名。 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

包起来

我希望本教程可以帮助您在同一机器上运行OpenConnect VPN服务器和Apache / Nginx。 与往常一样,如果您发现这篇文章很有用,请订阅我们的免费新闻通讯以获取更多提示和技巧。 保重🙂

本教程将向您展示如何使用HAProxy在同一盒上运行OpenConnect VPN服务器(ocserv)和Apache / Nginx。 OpenConnect(ocserv)是Cisco AnyConnect VPN协议的开源实现。

ocserv-apache-nginx-haproxy

Sidebar