• 运行Apache、Nginx和HAProxy在同一台服务器上(Debian、Ubuntu、CentOS)

    如果你是一名服务器管理员,你可能会选择像Apache或Nginx这样的web服务器。自20世纪90年代以来,Apache是一款知名的web服务器。Nginx最早是在2004年开发的,由于其轻量级的内存占用和对静态HTML文件的快速处理速度,它很快获得了广泛关注。 Apache和Nginx都支持虚拟主机,这意味着您可以在同一台服务器上托管多个网站或web应用程序。但是,您会遇到这样的情况:现有的web服务器正在运行,但特定的web应用程序需要使用不同的web服务器。公共IP地址上的端口80或443只能由一个进程使用。如果Apache正在使用该端口,那么Nginx无法使用(或绑定)它。那你能做什么? 您可以将Nginx配置为Apache的反向代理,这样Nginx就可以将HTTP请求重定向到Apache。根据我的经验,我发现这并不总是最好的方法,因为它曾经导致我无法解决的奇怪问题。相反,我更喜欢使用HAProxy作为Nginx和Apache的反向代理。HAProxy是一款免费、开源的高可用性负载均衡器和代理服务器,适用于基于TCP和HTTP的应用程序。 在同一台服务器上运行Apache、Nginx和HAProxy 下面是它的工作原理。 Nginx监听127.0.0.1:80和127.0.0.1:443 Apache监听127.0.0.2:80和127.0.0.2:443 HAProxy监听公共IP地址的端口80和443。它将端口80上的HTTP请求重定向到端口443。当请求到达端口443时,它将通过分析HTTPS请求中的SNI(服务器名称指示)头,在Nginx和Apache后端之间进行选择。 实际上,Cloudflare(CDN提供商)也在使用SNI头来确定如何将HTTPS请求路由到源服务器。 第一步:停止Nginx和Apache 要在Debian、Ubuntu和CentOS上停止Nginx,请运行 sudo systemctl stop nginx 要在Debian/Ubuntu上停止Apache,请运行 sudo systemctl stop apache2 要在CentOS上停止Apache,请运行 sudo systemctl stop httpd 步骤2:更改Nginx中的侦听端口 我们需要让Nginx收听127.0.0.1:80。在/etc/Nginx/conf.d/或/etc/Nginx/sites enabled/中打开Nginx配置文件,并找到以下行。 listen 80; 换成 listen 127.0.0.1:80; 如果在Nginx服务器块上启用了https,则还可以查找 listen 443 ssl; 把它改成 listen 127.0.0.1:443 ssl; Nginx主配置文件/etc/Nginx/Nginx。conf可能包含一个默认的虚拟主机,监听端口80或443,所以您可能也需要编辑这个文件。 重新启动Nginx以使更改生效。 sudo systemctl restart nginx 第3步:更改Apache中的侦听端口 我们需要让Apache监听127.0.0.2:80。 Debian/Ubuntu 在Debian和Ubuntu上,编辑/etc/apache2/ports。conf文件。 sudo nano /etc/apache2/ports.conf 改变 Listen 80 Listen 443 到 Listen 127.0.0.2:80 Listen 127.0.0.2:443 保存并关闭文件。也可以转到/etc/apache2/sites enabled/目录,编辑虚拟主机文件。改变 <VirtualHost *:80> 到 <VirtualHost 127.0.0.2:80> 如果有SSL虚拟主机,那么也要更改 <VirtualHost *:443> 到 <VirtualHost 127.0.0.2:443> 重启Apache。 sudo systemctl restart apache2 森托斯 在CentOS上,编辑/etc/httpd/conf/httpd。conf文件。 sudo nano /etc/httpd/conf/httpd.conf 发现 Listen 80 换成 Listen 127.0.0.2:80 保存并关闭文件。然后转到/etc/httpd/conf.d/目录,编辑虚拟主机文件。改变 <VirtualHost *:80> 到 <VirtualHost 127.0.0.2:80> 如果有SSL虚拟主机,那么也要更改 <VirtualHost *:443> 到 <VirtualHost 127.0.0.2:443> 在/etc/httpd/conf.d/ssl文件中。档案里有 Listen 443 https 将其更改为: Listen 127.0.0.2:443 https 保存并关闭文件。重新启动Apache以使更改生效。 sudo systemctl restart httpd 第4步:配置HAProxy 在发行版上安装HAProxy。 Debian/Ubuntu sudo apt install haproxy 森托斯 sudo dnf install haproxy 编辑HAProxy配置文件。 sudo nano /etc/haproxy/haproxy.cfg 在文件末尾添加以下代码段,这将使HAPorxy侦听公共IP地址的端口80,并将端口80上的HTTP请求重定向到端口443。将12.34.56.78替换为服务器的公共IP地址。 frontend http bind 12.34.56.78:80 mode http redirect scheme https code 301 现在我们还需要添加一个HTTPS前端。 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 } 然后定义Nginx和Apache后端。check参数告诉HAProxy通过发送TCP数据包在后端执行健康检查。 backend nginx mode tcp option ssl-hello-chk server nginx 127.0.0.1:443 check backend apache mode tcp option ssl-hello-chk server apache 127.0.0.2:443 check 您可以使用以下选项定义默认后端: default_backend nginx 我们将在HTTPS请求中使用SNI头重定向到正确的后端。例如,如果Nginx服务于domain1。com和Apache正在为domain2提供服务。com,然后添加以下两行。你也可以使用子域,只要它们不同。 use_backend nginx if { req_ssl_sni -i domain1.com } use_backend apache if { req_ssl_sni -i domain2.com } 请注意,默认的_backend和use_backend指令应该放在后端定义之上。 frontend http bind 12.34.56.78:80 mode http redirect scheme https code 301 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 } default_backend nginx use_backend nginx if { req_ssl_sni -i domain1.com } use_backend apache if { req_ssl_sni -i domain2.com } backend nginx mode tcp option ssl-hello-chk server nginx 127.0.0.1:443 check backend apache mode tcp option ssl-hello-chk server apache 127.0.0.2:443 check 在上面的配置中,我们利用TLS中的SNI(服务器名称指示)功能来区分HTTPS流量。 当域名1。com位于TLS客户端Hello,HAProxy将流量重定向到nginx后端。 当域名2。com位于TLS客户端Hello中,HAProxy将流量重定向到apache后端。 如果客户端没有在TLS client Hello中指定服务器名称,那么HAproxy将使用默认后端(nginx)。 保存并关闭文件。然后重启HAproxy。 sudo systemctl restart haproxy 现在Apache、Nginx和HAProxy可以在同一台服务器上运行。 如何将客户端的IP地址转发到后端 默认情况下,Apache和Nginx只能看到HAProxy的IP地址。要获取客户端的真实IP地址,请确保在HAProxy的后端定义中添加了send-proxy-v2选项,如下所示。 backend nginx mode tcp option ssl-hello-chk server nginx 127.0.0.1:443 send-proxy-v2 check backend apache mode tcp option ssl-hello-chk server apache 127.0.0.2:443 send-proxy-v2 check 我们还需要在Nginx和Apache中添加一些配置以使其工作,否则您的网站将无法访问。 Nginx 在Nginx listen指令中添加proxy_协议,如下所示。 listen 127.0.0.2:443 ssl http2 proxy_protocol; 然后在/etc/Nginx/Nginx中的Nginx http{}块中添加以下两条指令。conf文件。 set_real_ip_from 127.0.0.1; real_ip_header proxy_protocol; 保存并关闭文件。然后重新加载Nginx。 sudo systemctl reload nginx 注意:如果您的网站运行Cloudflare CDN,那么您应该更改real_ip_头代理_协议;到连接ip的实际ip头CF;以显示客户端的真实IP地址。您还可以将这个real_ip_头指令添加到单个服务器块文件中,以覆盖/etc/nginx/nginx中的全局配置。conf文件。 最后,重启HAProxy。 sudo systemctl restart haproxy 阿帕奇 如果在Debian/Ubuntu上使用Apache,则需要启用remoteip模块。(默认情况下,此模块在CentOS上启用。) sudo a2enmod remoteip 然后在Apache虚拟主机配置文件中添加以下三行代码。 RemoteIPProxyProtocol On RemoteIPHeader X-Forwarded-For RemoteIPTrustedProxy 127.0.0.1 这样地。 <VirtualHost 127.0.0.2:443> ServerName www.example.com RemoteIPProxyProtocol On RemoteIPHeader X-Forwarded-For RemoteIPTrustedProxy 127.0.0.1 保存并关闭文件。然后我们还需要更改组合日志格式。编辑Apache主配置文件。 sudo nano /etc/apache2/apache2.conf 或 sudo nano /etc/httpd/conf/httpd.conf 找到下面这行。 LogFormat "%h %l %u %t /"%r/" %>s %O /"%{Referer}i/" /"%{User-Agent}i/"" combined 替换为: LogFormat "%a %l %u %t /"%r/" %>s %O /"%{Referer}i/" /"%{User-Agent}i/"" combined 保存并关闭文件。然后重启Apache,使更改生效。 sudo systemctl restart apache2 或 sudo systemctl restart httpd 请注意,RemoteIPProxyProtocol On指令仅在Apache 2.4.31及更新版本中可用。要检查Apache版本,请运行 sudo apache2 -v 或 sudo httpd -v Ubuntu 18.04附带Apache 2.4.29。如果您的Apache版本不满足此要求,则应删除HAProxy后端定义中的send-proxy-v2。CentOS 8搭载Apache 2.4.37。 最后,重启HAProxy。 sudo systemctl restart haproxy 如何添加新的虚拟主机 如果您有Apache和Nginx web服务器,那么您只需要两个后端:一个用于Apache,一个用于Nginx。 当您需要添加另一个域(或子域)时,不需要在HAProxy中添加新的后端。相反,您应该在Apache或Nginx中为新域(或子域)创建一个新的虚拟主机,然后使用HAProxy中的use_backend指令将流量重定向到正确的后端。 frontend http bind 12.34.56.78:80 mode http redirect scheme https code 301 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 } default_backend nginx use_backend nginx if { req_ssl_sni -i domain1.com } use_backend nginx if { req_ssl_sni -i sub.domain1.com } use_backend apache if { req_ssl_sni -i domain2.com } use_backend apache if { req_ssl_sni -i sub.domain2.com } backend nginx mode tcp option ssl-hello-chk server nginx 127.0.0.1:443 check backend apache mode tcp option ssl-hello-chk server apache 127.0.0.2:443 check 我建议使用apache和nginx作为上述代码中的后端名称,这样您就可以知道哪个web服务器承载哪个应用程序。 获取新的SSL证书 http-01挑战 首先,您需要了解如何使用Certbot apache和nginx验证器来获取TLS证书。 正确地在Apache上启用HTTPS,让我们在Ubuntu上加密 在Nginx上正确启用HTTPS,让我们在Ubuntu上加密 Certbot apache和nginx验证器使用http-01质询,该质询可在TCP端口80上工作。因为HAProxy使用的是TCP端口80,所以Certbot http-01挑战可能会失败。但是,您可以使用以下方法使其工作。 使用自签名证书或另一个域的证书在Apache或Nginx中启用SSL主机。 然后像往常一样使用Certbot apache和nginx验证器。 此方法之所以有效,是因为Certbot http-01质询可以从TCP端口80重定向到TCP端口443,并且Certbot接受端口443上的无效证书。 dns-01挑战 您还可以使用certbot dns-01挑战,它通过为您的域创建一个临时TXT记录来证明您实际拥有该域,因此它可以绕过TCP端口80和TCP端口443。这种方法的缺点是并非所有的域注册器都受支持。 首先,你需要安装Certbot DNS插件。它们是Debian和Ubuntu软件库中提供的几个DNS插件,您可以通过 apt search python3-certbot-dns 输出: python3-certbot-dns-cloudflare/bionic,bionic 0.23.0-1 all Cloudflare DNS plugin for Certbot python3-certbot-dns-digitalocean/bionic,bionic 0.23.0-1 all DigitalOcean DNS plugin for Certbot python3-certbot-dns-dnsimple/bionic,bionic 0.23.0-1 all DNSimple DNS plugin for Certbot python3-certbot-dns-google/bionic,bionic 0.23.0-1 all Google DNS plugin for Certbot python3-certbot-dns-rfc2136/bionic,bionic 0.23.0-1 all RFC 2136 DNS plugin for Certbot python3-certbot-dns-route53/bionic,bionic 0.23.0-1 all Route53 DNS plugin for Certbot 在CentOS 8上,您可以从EPEL存储库中找到Certbot DNS插件。请注意,您需要从默认的CentOS存储库安装Certbot。 sudo dnf install certbot 从EPEL存储库中查找DNS插件。 sudo dnf install epel-release dnf search certbot-dns 输出: python3-certbot-dns-ovh.noarch : OVH DNS Authenticator plugin for Certbot python3-certbot-dns-nsone.noarch : NS1 DNS Authenticator plugin for Certbot python3-certbot-dns-gehirn.noarch : Gehirn Infrastructure Service DNS Authenticator plugin for Certbot python3-certbot-dns-google.noarch : Google Cloud DNS Authenticator plugin for Certbot python3-certbot-dns-linode.noarch : Linode DNS Authenticator plugin for Certbot python3-certbot-dns-luadns.noarch : LuaDNS Authenticator plugin for Certbot python3-certbot-dns-rfc2136.noarch : RFC 2136 DNS Authenticator plugin for Certbot python3-certbot-dns-route53.noarch : Route53 DNS Authenticator plugin for Certbot python3-certbot-dns-cloudxns.noarch : CloudXNS DNS Authenticator plugin for Certbot python3-certbot-dns-dnsimple.noarch : DNSimple DNS Authenticator plugin for Certbot python3-certbot-dns-cloudflare.noarch : Cloudflare DNS Authenticator plugin for Certbot python3-certbot-dns-cloudflare.noarch : Cloudflare DNS Authenticator plugin for Certbot python3-certbot-dns-dnsmadeeasy.noarch : DNS Made Easy DNS Authenticator plugin for Certbot python3-certbot-dns-sakuracloud.noarch : Sakura Cloud DNS Authenticator plugin for Certbot 根据您使用的DNS托管服务安装其中一个插件。我使用的是Cloudflare,所以我将以Cloudflare为例。运行以下命令在Debian/Ubuntu上安装python3 certbot dns cloudflare包。 sudo apt install python3-certbot-dns-cloudflare 然后为Cloudflare创建一个配置文件。 sudo nano /etc/letsencrypt/cloudflare.ini 我们需要在此文件中添加Cloudflare帐户电子邮件地址和API密钥。 # Cloudflare API credentials used by Certbot dns_cloudflare_email = [email protected] dns_cloudflare_api_key = 0123456789abcdef0123456789abcdef01234567 您可以在以下位置找到Cloudflare API密钥:https://dash.cloudflare.com/profile.请注意,Certbot Cloudflare插件目前不支持Cloudflare的“API令牌”,因此请确保使用“全局API密钥”进行身份验证。 保存并关闭文件。API密钥绕过Cloudflare的双因素身份验证,因此您应该只允许root用户读取此文件。 sudo chmod 600 /etc/letsencrypt/cloudflare.ini 现在运行certbot。 sudo certbot --agree-tos -a dns-cloudflare -i nginx --redirect --hsts --staple-ocsp --email [email protected] -d www.your-domain.com,your-domain.com 在上面的命令中,我们指定将使用dns cloudflare作为身份验证程序来获取新的TLS证书,并使用nginx插件来创建HTTPS服务器块。如果您使用Apache,那么用Apache替换nginx。 此命令将要求您输入的路径。ini文件,所以输入/etc/letsencrypt/cloudflare。ini,然后按回车键。 获取SSL证书并将其安装到web服务器配置文件后。你需要让它听127.0.0.1:443或127.0.0.2:443。例如,如果使用Nginx,则查找 listen 443 ssl 把它改成 listen 127.0.0.1:443 ssl http2 另外,将端口80更改为 listen 127.0.0.1:80; 保存并关闭文件。然后重新启动web服务器。 常见错误 1错误的域名 如果您在一台服务器上有多个Nginx虚拟主机,并且当您键入一个域名时,web浏览器会将您带到同一台服务器上托管的另一个域名,则可能是您的一个Nginx虚拟主机文件名没有以结尾。conf文件扩展名,所以Nginx没有加载这个虚拟主机。也可能是您为域名设置了AAAA记录,但没有将Nginx配置为在IPv6中提供域名服务。 以上内容也适用于Apache web服务器。 2违反网络协议 如果您在HAProxy中设置了send-proxy-v2头,但没有在Nginx或Apache中启用proxy_协议,那么您的网站将显示以下错误。 The site  has experienced a network protocol violation that cannot be repaired. 请记住在更改配置文件后重新启动Nginx/Apache。 3连接复位错误 如果您在Nginx或Apache中启用了proxy_协议,但没有在HAProxy中设置send-proxy-v2头,那么您的网站将显示此错误。 secure connection failed. PR_CONNECT_RESET_ERROR 您将在Nginx或Apache错误日志中找到以下错误消息。 broken header while reading PROXY protocol 请记住在更改配置文件后重新启动Nginx/Apache。 还请注意,如果在一个Apache/Nginx虚拟主机文件中启用代理协议,那么它也会隐式地为所有其他虚拟主机启用。我还没有找到一种方法来禁用单个虚拟主机的proxy_协议。由于您在同一台服务器上运行Apache和Nginx,解决方法是只在Nginx中启用代理协议,而不在Apache中启用代理协议。如果虚拟主机不需要获取客户端的真实IP地址,请将其配置为使用Apache。 更新:我突然想到,您可以在另一个环回地址(如127.0.0.4)上设置一个新的Apache/Nginx虚拟主机。这样,新的虚拟主机就不会启用代理协议。 4 PRU文件的结束错误 如果在Apache/Nginx中启用了代理协议,但试图直接访问虚拟主机(绕过HAProxy),则会看到以下错误。 PR_END_OF_FILE_ERROR 5 SSL_错误_系统调用 如果使用curl命令: curl -I https://example.com 您会遇到以下错误 curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to example.com:443 这可能是因为您没有为此域设置后端定义。 收尾 我希望本教程能帮助您在同一台服务器上运行Apache、Nginx和HAProxy。和往常一样,如果你觉得这篇文章很有用,那么订阅我们的免费时事通讯以获得更多提示和窍门。当心?

    2022.03.24 浏览:584