使用 haproxy 使用子目录的反向代理设置
reverse proxy setup using subdirs using haproxy
我在 ubuntu 16 上使用 haproxy 1.6.3 运行 让我的反向代理设置工作时遇到问题。
这是我想要实现的目标:
- 在我的主机上,我在 https://bar.com 下有一个带有 apache 运行 的网络应用程序,它使用 mod_rewrite 进行路由
- 各种内部服务器(机器 1..n)通过 vpn 链接到主机,所有这些都仅在 vpn 适配器的端口 8081 上公开带有 websocket 支持的 http 接口
- 我希望可以通过主机的子目录访问内部机器,例如。对于机器 1,我想通过 https://bar.com/machine1 访问其网页 - 内部流量为 http,从主机到访问者的流量由主机的 ssl 证书保护
- 与 /machine1 不匹配的所有其他流量不应受到影响,并且应像以前一样由主计算机 apache 提供服务
- 机器 1..n 的转发 Web 界面上的路径不是问题,因为它们能够通过 header 指令(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]
haproxy 设置
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/(.*) \ /
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
我目前的issues/questions:
访问未加密的变体 (http://bar.com/machine1) 有时 服务于 machine1 的正确页面,但大多数时候,我从主要机器 apache - 我认为这可以通过选项 http-server-close 解决,但事实并非如此 - 有人可以指出我在这里缺少的东西吗?我在极少数有效响应的情况下验证了路径已使用 /machine1 正确扩展 - 例如/machine1/css/main.css for css 包括 - 但即使在从 machine1 成功初始拉取之后 - 所有后续的脚本、图像和 css return 再次提取 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
很容易解决。
来自 docs
mode tcp
:
In this mode, HAProxy doesn’t decipher the traffic. It just opens a
TCP tunnel between the client and the server and let them together
negotiate and handle the TLS traffic.
使用此模式时,HAProxy 不会评估数据包中的 HTTP headers。在这种情况下,显然没有选项可以区分 uri 等 http 特定 header 的后端,这就是初始配置不起作用的原因。
mode http
:
In this mode, HAProxy decipher the traffic on the client side and
re-encrypt it on the server side. It can access to the content of the
request and the response and perform advanced processing over the
traffic.
在这种情况下,所有 http header 字段都可供 haproxy 用于后端选择。
这当然对 ssl 有影响 - 此设置有多种变体,我选择使用 SSL/TLS 卸载并让 HAProxy 在客户端解密流量并以明文方式连接到内部服务器.
这使得机器 运行 成为 sslendpoint 的 haproxy,并且需要在此处而不是在网络服务器上设置 ssl 证书。此外,通过此设置,网络服务器 运行 网络应用程序可以完全隔离,仅在内部为 haproxy 机器提供页面。这也回答了问题 2。
最后,对于奖金问题:
- 我已经通过 shell 脚本实现 'dynamic' 配置,当新机器连接到数据库中的信息时,这些脚本会即时修改 haproxy 配置,使更改生效
service haproxy reload
(ubuntu) - 这似乎工作得很好。
- 对于用户身份验证,我已将其设置为后端机器现在查询主 Web 应用程序以获取授权并在授权被拒绝时重定向到主 Web 应用程序。为了验证,使用 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/(.*) \ /
server m1 10.0.0.4:8081
我在 ubuntu 16 上使用 haproxy 1.6.3 运行 让我的反向代理设置工作时遇到问题。 这是我想要实现的目标:
- 在我的主机上,我在 https://bar.com 下有一个带有 apache 运行 的网络应用程序,它使用 mod_rewrite 进行路由
- 各种内部服务器(机器 1..n)通过 vpn 链接到主机,所有这些都仅在 vpn 适配器的端口 8081 上公开带有 websocket 支持的 http 接口
- 我希望可以通过主机的子目录访问内部机器,例如。对于机器 1,我想通过 https://bar.com/machine1 访问其网页 - 内部流量为 http,从主机到访问者的流量由主机的 ssl 证书保护
- 与 /machine1 不匹配的所有其他流量不应受到影响,并且应像以前一样由主计算机 apache 提供服务
- 机器 1..n 的转发 Web 界面上的路径不是问题,因为它们能够通过 header 指令(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]
haproxy 设置
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/(.*) \ / 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
我目前的issues/questions:
访问未加密的变体 (http://bar.com/machine1) 有时 服务于 machine1 的正确页面,但大多数时候,我从主要机器 apache - 我认为这可以通过选项 http-server-close 解决,但事实并非如此 - 有人可以指出我在这里缺少的东西吗?我在极少数有效响应的情况下验证了路径已使用 /machine1 正确扩展 - 例如/machine1/css/main.css for css 包括 - 但即使在从 machine1 成功初始拉取之后 - 所有后续的脚本、图像和 css return 再次提取 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
很容易解决。
来自 docs
mode tcp
:
In this mode, HAProxy doesn’t decipher the traffic. It just opens a TCP tunnel between the client and the server and let them together negotiate and handle the TLS traffic.
使用此模式时,HAProxy 不会评估数据包中的 HTTP headers。在这种情况下,显然没有选项可以区分 uri 等 http 特定 header 的后端,这就是初始配置不起作用的原因。
mode http
:
In this mode, HAProxy decipher the traffic on the client side and re-encrypt it on the server side. It can access to the content of the request and the response and perform advanced processing over the traffic.
在这种情况下,所有 http header 字段都可供 haproxy 用于后端选择。
这当然对 ssl 有影响 - 此设置有多种变体,我选择使用 SSL/TLS 卸载并让 HAProxy 在客户端解密流量并以明文方式连接到内部服务器.
这使得机器 运行 成为 sslendpoint 的 haproxy,并且需要在此处而不是在网络服务器上设置 ssl 证书。此外,通过此设置,网络服务器 运行 网络应用程序可以完全隔离,仅在内部为 haproxy 机器提供页面。这也回答了问题 2。
最后,对于奖金问题:
- 我已经通过 shell 脚本实现 'dynamic' 配置,当新机器连接到数据库中的信息时,这些脚本会即时修改 haproxy 配置,使更改生效
service haproxy reload
(ubuntu) - 这似乎工作得很好。 - 对于用户身份验证,我已将其设置为后端机器现在查询主 Web 应用程序以获取授权并在授权被拒绝时重定向到主 Web 应用程序。为了验证,使用 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/(.*) \ /
server m1 10.0.0.4:8081