使用子目录使用HAPROXY的反向代理设置



我在使用 ubuntu 16 上运行的 haproxy 1.6.3 让我的反向代理设置工作时遇到问题。 这是我想要实现的目标:

  • 在我的主机上,我有一个 Web 应用程序,其中 Apache 在 https://bar.com 下运行,它使用 mod_rewrite 进行路由
  • 各种内部服务器(机器 1..n)通过 VPN 链接到主机,所有服务器都只公开一个 HTTP 接口,在 VPN 适配器的端口 8081 上支持 Websocket
  • 我希望内部机器可以通过主机的子部分访问,例如。 对于机器 1 我想通过 https://bar.com/machine1 访问其网页 - 内部流量为 http,从主机到访问者的流量由主机的 SSL 证书保护
  • 所有其他与/machine1 不匹配的流量不应受到影响,应像以前一样由主机 apache 提供服务
  • 机器 1..n 转发的 Web 界面上的路径不是问题,因为它们能够通过以下配置中的标头指令(Orig-Path 和 X-Script-Path)动态修改其路径
  • 主机上的 Apache2 配置为仅侦听具有Listen 127.0.0.1的本地主机,并且所有到主站点的流量都由 Haproxy 通过默认后端处理

以下是相关配置:

  • 主站的 apache .htaccess (不包括相关子目录)

    # Exclude machine1 subdirectory from rewrite
    RewriteRule ^(machine1)($|/) - [L]
    RewriteCond %{REQUEST_URI} !^/index.php
    RewriteCond %{SCRIPT_FILENAME} !-f
    RewriteCond %{SCRIPT_FILENAME} !-d
    RewriteRule .* index.php [L]
    
  • ha代理设置

    frontend http-in
    bind <external-ip>:80
    mode tcp
    option tcplog
    acl machine1 path_beg /machine1
    use_backend machine1-backend if machine1
    default_backend default-backend-http
    frontend https-in
    bind <external-ip>:80
    mode tcp
    option tcplog
    default_backend default-backend-https
    backend machine1-backend
    reqrep ^([^ :]*) /machine1/(.*)  1 /2
    http-request set-header Orig-Path /machine1/
    http-request set-header X-Script-Path /machine1/
    http-request set-header Host bar.com
    option http-server-close  
    server m1 10.0.0.4:8081
    backend default-backend-https
    server main 127.0.0.1:443
    mode tcp
    backend default-backend-http
    server main 127.0.0.1
    mode tcp
    

我目前遇到的问题/问题:

  • 访问未加密的变体 (http://bar.com/machine1)有时会为 machine1 提供正确的页面,但大多数时候,我从主机 Apache 得到 404 - 我认为这可以通过选项 http-server-close 来解决,但事实并非如此 - 有人可以指出我在这里缺少什么吗?我在极少数有效响应的情况下验证了路径是否使用/machine1 正确扩展 - 例如/machine1/css/main.css对于 css 包括 - 但即使在从机器 1 进行可疑的初始拉取之后 - 脚本、图像和 css 的所有后续提取再次返回 404

  • 我无法弄清楚如何正确设置 SSL 以在/machine1 请求上使用 haproxy 处理 https->http 流量转换,因此 SSL 部分目前不包括路由 - 我需要如何扩展配置以使它适用于 https://bar.com/machine1?(假设/etc/keys/web.pem 下存在的 bar.com 有效证书)

奖励问题:

  • 是否有机会使此配置动态化? 例如,从数据库中提取相关信息(服务器 IP、子目录名称)/在此处使用某种逻辑,因为机器 1...n 链接将在运行时发生变化(新机器连接,其他机器断开连接,并且可能的计算机数量相当大)
  • 在使用/machine1 之前是否有验证用户的选项?主 Web 应用程序进行用户管理,所以我最好在允许访问/machine1 之前检查用户是否经过身份验证 - 可以这样做吗?

在这里回答我自己的问题: 经过一些研究,问题是此用例的配置中tcp错误的模式,可以通过将前端和后端的模式切换到http来轻松解决。 从文档中

  • mode tcp

在这种模式下,HAProxy 不会解密流量。它只是打开一个 客户端和服务器之间的TCP隧道,并让它们在一起 协商和处理 TLS 流量。

使用此模式时,HAProxy 不会评估数据包中的 HTTP 标头。在这种情况下,人们无法选择区分 http 特定标头(如 uri)上的后端,这就是初始配置不起作用的原因。

  • mode http

在此模式下,HAProxy 解密客户端上的流量和 在服务器端重新加密它。它可以访问的内容 请求和响应,并通过 交通。

在这种情况下,所有 http 标头字段都可供 haproxy 进行后端选择。

这当然对 ssl 有影响 - 此设置有多种变体,我选择使用 SSL/TLS 卸载,让 HAProxy 破译客户端的流量并明确连接到内部服务器。

这使得运行 haproxy 的计算机成为 sslendpoint,并且需要在此处而不是在 Web 服务器上设置 ssl 证书。此外,通过此设置,运行 Web 应用程序的 Web 服务器可以完全隔离,仅在 haproxy 计算机内部提供页面。这也回答了问题2。

最后,对于奖励问题:

  • 我已经通过 shell 脚本进行了"动态"配置,当新机器与数据库中的信息连接时,这些脚本会即时修改 haproxy 配置,使更改与service haproxy reload(ubuntu) 一起生效 - 这似乎工作得很好。
  • 对于用户身份验证,我设置了后端计算机现在查询主 Web 应用程序以获取授权,并在授权被拒绝时重定向到主 Web 应用程序。为了进行验证,使用了 Cookie(或没有 Cookie)。我目前正在测试此设置,但现在看起来这将起作用。

最后,我拥有的结果(工作)配置(请注意,我也在 haproxy 上将 http 添加到 https 重定向):

frontend http-in
bind <external-ip>:80
bind <external-ip>:443 ssl crt /path/to/cert/cert.pem
acl machine1 path_beg /machine1
reqadd X-Forwarded-Proto: https
mode http
option httplog
use_backend machine1-backend if machine1
default_backend default-backend
backend default-backend
redirect scheme https if !{ ssl_fc }
server main 127.0.0.1:80
mode http
backend machine1-backend
http-request set-header Orig-Path /machine1/
http-request set-header X-Script-Path /machine1/
http-request set-header Host bar.com
reqirep ^([^ :]*) /machine1/(.*)  1 /2
server m1 10.0.0.4:8081

最新更新