# 使用 Apache 在 Linux 上托管 SS CMS

使用本指南,了解如何在 CentOS 7 上将 Apache 设置为反向代理服务器,以将 HTTP 流量重定向到 SS CMS 系统。 Ubuntu 以及其他版本的 Linux 操作系统的部署流程与本文类似。

# 安装 Apache

将 CentOS 包更新为其最新稳定版本:

sudo yum update -y

使用单个 yum 命令在 CentOS 上安装 Apache Web 服务器:

sudo yum -y install httpd mod_ssl

运行该命令后的示例输出:

Downloading packages:
httpd-2.4.6-40.el7.centos.4.x86_64.rpm               | 2.7 MB  00:00:01
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Installing : httpd-2.4.6-40.el7.centos.4.x86_64      1/1 
Verifying  : httpd-2.4.6-40.el7.centos.4.x86_64      1/1 

Installed:
httpd.x86_64 0:2.4.6-40.el7.centos.4

Complete!

注意

在此示例中,输出反映了 httpd.86_64,因为 CentOS 7 版本是 64 位的。 若要验证 Apache 的安装位置,请从命令提示符运行 whereis httpd

# 配置 Apache

Apache 的配置文件位于 /etc/httpd/conf.d/ 目录内。 除了 /etc/httpd/conf.modules.d/ 中的模块配置文件外(其中包含加载模块所需的任何配置文件),将对任何带 .conf 扩展名的文件按字母顺序进行处理。

为应用创建名为 sscms.conf 的配置文件:

<VirtualHost *:*>
    RequestHeader set "X-Forwarded-Proto" expr=%{REQUEST_SCHEME}
</VirtualHost>

<VirtualHost *:80>
    ProxyPreserveHost On
    ProxyPass / http://127.0.0.1:5000/
    ProxyPassReverse / http://127.0.0.1:5000/
    ServerName www.example.com
    ServerAlias *.example.com
    ErrorLog ${APACHE_LOG_DIR}sscms-error.log
    CustomLog ${APACHE_LOG_DIR}sscms-access.log common
</VirtualHost>

VirtualHost 块可以在服务器上的一个或多个文件中多次出现。 在前面的配置文件中,Apache 接受端口 80 上的公共流量。 正在向域 www.example.com 提供服务,*.example.com 别名解析为同一网站。 有关详细信息,请参阅基于名称的虚拟主机支持。 请求会通过代理从根位置转到 127.0.0.1 处的服务器的端口 5000。 对于双向通信,需要 ProxyPassProxyPassReverse。 若要更改 SS CMS 的 IP/端口,请参阅 访问地址配置

注意

未能指定 VirtualHost 块中的正确 ServerName 指令会公开应用的安全漏洞。 如果可控制整个父域(区别于易受攻击的 *.com),则子域通配符绑定(例如,*.example.com)不具有此安全风险。 有关详细信息,请参阅 rfc7230 第 5.4 条

可以使用 ErrorLogCustomLog 指令配置每个 VirtualHost 的日志记录。 ErrorLog 是服务器记录错误的位置,CustomLog 则设置文件名和日志文件的格式。 在这种情况下,这是记录请求信息的位置。 每个请求将各占一行。

保存文件,并测试配置。 如果一切正常,响应应为 Syntax [OK]

sudo service httpd configtest

重新启动 Apache:

sudo systemctl restart httpd
sudo systemctl enable httpd

# 监视应用

Apache 现在已设置为将对 http://localhost:80 发起的请求转发到运行在 http://127.0.0.1:5000 处的 SS CMS 系统。 但是,未将 Apache 设置为管理 SS CMS 进程。 使用 systemd ,并创建服务文件以启动和监视基础 Web 应用。 systemd 是一个 init 系统,可以提供用于启动、停止和管理进程的许多强大的功能。

# 创建服务文件

创建服务定义文件:

sudo nano /etc/systemd/system/sscms.service

应用的一个示例服务文件:

[Unit]
Description=Example SS CMS App running on CentOS 7

[Service]
WorkingDirectory=/var/www
ExecStart=/var/www/sscms
Restart=always
# Restart service after 10 seconds if the sscms service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=sscms-example
User=apache

[Install]
WantedBy=multi-user.target

在前面的示例中,管理服务的用户由 User 选项指定。 用户 (apache) 必须存在并且拥有正确应用文件的所有权。

使用 TimeoutStopSec 配置在收到初始中断信号后等待应用程序关闭的持续时间。 如果应用程序在此时间段内未关闭,则将发出 SIGKILL 以终止该应用程序。 提供作为无单位秒数的值(例如,150)、时间跨度值(例如,2min 30s)或 infinity 以禁用超时。 TimeoutStopSec 默认为管理器配置文件(systemd-system.confsystem.conf.dsystemd-user.confuser.conf.d)中 DefaultTimeoutStopSec 的值。 大多数分发版的默认超时时间为 90 秒。

# The default value is 90 seconds for most distributions.
TimeoutStopSec=90

保存该文件并启用该服务:

sudo systemctl enable sscms.service

启动该服务,并确认它正在运行:

sudo systemctl start sscms.service
sudo systemctl status sscms.service

● sscms.service - Example SS CMS App running on CentOS 7
    Loaded: loaded (/etc/systemd/system/sscms.service; enabled)
    Active: active (running) since Thu 2016-10-18 04:09:35 NZDT; 35s ago
Main PID: 9021 (dotnet)
    CGroup: /system.slice/sscms.service
            └─9021 /var/www/sscms

在配置了反向代理并通过 systemd 管理 SS CMS 后,Web 应用现已完全配置,并能在本地计算机上的浏览器中从 http://localhost 进行访问。 检查响应标头,服务器 标头表示 SS CMS 应用由 Kestrel 提供服务:

HTTP/1.1 200 OK
Date: Tue, 11 Oct 2016 16:22:23 GMT
Server: Kestrel
Keep-Alive: timeout=5, max=98
Connection: Keep-Alive
Transfer-Encoding: chunked

# 查看日志

由于使用 SS CMS 的 Web 应用是通过 systemd 进行管理的,因此事件和进程将记录到集中日志。 但是,此日志包含由 systemd 管理的所有服务和进程的条目。 若要查看特定于 sscms.service 的项,请使用以下命令:

sudo journalctl -fu sscms.service

若要进行时间筛选,请使用命令指定时间选项。 例如,使用 --since today 筛选出当天或 --until 1 hour ago 来查看前一小时的条目。 有关详细信息,请参阅 journalctl 手册页

sudo journalctl -fu sscms.service --since "2016-10-18" --until "2016-10-18 04:00"

# 保护应用

# 配置防火墙

Firewalld 是管理防火墙的动态守护程序,支持网络区域。 仍可以使用 iptable 管理端口和数据包筛选。 默认情况下应安装 Firewalldyum 可用于安装包或验证是否已安装。

sudo yum install firewalld -y

使用 firewalld 仅打开应用所需的端口。 在此示例中,使用的是端口 80 和 443。 以下命令将端口 80 和 443 永久设置为打开:

sudo firewall-cmd --add-port=80/tcp --permanent
sudo firewall-cmd --add-port=443/tcp --permanent

重新加载防火墙设置。 检查默认区域中可用的服务和端口。 通过检查 firewall-cmd -h 获取可用选项。

sudo firewall-cmd --reload
sudo firewall-cmd --list-all
public (default, active)
interfaces: eth0
sources: 
services: dhcpv6-client
ports: 443/tcp 80/tcp
masquerade: no
forward-ports: 
icmp-blocks: 
rich rules: 

# HTTPS 配置

配置反向代理,以便进行安全 (HTTPS) 客户端连接

若要为 Apache 配置 HTTPS,请使用 mod_ssl 模块。 安装了 httpd 模块时,也会安装了 mod_ssl 模块。 如果未安装,请使用 yum 将其添加到配置。

sudo yum install mod_ssl

若要强制使用 HTTPS,请安装 mod_rewrite 模块以启用 URL 重写:

sudo yum install mod_rewrite

修改 sscms.conf 文件以启用 URL 重写和端口 443 上的安全通信:

<VirtualHost *:*>
    RequestHeader set "X-Forwarded-Proto" expr=%{REQUEST_SCHEME}
</VirtualHost>

<VirtualHost *:80>
    RewriteEngine On
    RewriteCond %{HTTPS} !=on
    RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L]
</VirtualHost>

<VirtualHost *:443>
    ProxyPreserveHost On
    ProxyPass / http://127.0.0.1:5000/
    ProxyPassReverse / http://127.0.0.1:5000/
    ErrorLog /var/log/httpd/sscms-error.log
    CustomLog /var/log/httpd/sscms-access.log common
    SSLEngine on
    SSLProtocol all -SSLv2
    SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:!RC4+RSA:+HIGH:+MEDIUM:!LOW:!RC4
    SSLCertificateFile /etc/pki/tls/certs/localhost.crt
    SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
</VirtualHost>

注意

此示例中使用了本地生成的证书。 SSLCertificateFile 应为域名的主证书文件。 SSLCertificateKeyFile 应为创建 CSR 时生成的密钥文件。 SSLCertificateChainFile 应为证书颁发机构提供的中间证书文件(如有)。

保存文件,并测试配置:

sudo service httpd configtest

重新启动 Apache:

sudo systemctl restart httpd

# 其他 Apache 建议

# 其他标头

为了防止恶意攻击,应对一些标头进行修改或添加一些标头。 确保已安装 mod_headers 模块:

sudo yum install mod_headers

# 保护 Apache 免受点击劫持攻击

点击劫持(也称为 UI 伪装攻击)是一种恶意攻击,其中网站访问者会上当受骗,从而导致在与当前要访问的页面不同的页面上单击链接或按钮。 使用 X-FRAME-OPTIONS 可保护网站。

缓解点击劫持攻击:

  1. 编辑 httpd.conf 文件:

    sudo nano /etc/httpd/conf/httpd.conf
    

    添加行 Header append X-FRAME-OPTIONS "SAMEORIGIN"

  2. 保存该文件。

  3. 重启 Apache。

# MIME 类型探查

X-Content-Type-Options 标头阻止 Internet Explorer 进行 MIME 探查(从文件内容中确定文件的 Content-Type)。 如果服务器通过设置 nosniff 选项将 Content-Type 标头设置为 text/html,则不管文件内容为何,Internet Explorer 都会将内容呈现为 text/html

编辑 httpd.conf 文件:

sudo nano /etc/httpd/conf/httpd.conf

添加行 Header set X-Content-Type-Options "nosniff"。 保存该文件。 重启 Apache。

# 负载平衡

此示例演示如何在同一实例计算机上的 CentOS 7 和 Kestrel 上设置和配置 Apache。 为了不出现单一故障点;使用 mod_proxy_balancer 并修改 VirtualHost 可实现在 Apache 代理服务器后方管理 Web 应用的多个实例。

sudo yum install mod_proxy_balancer

在下面所示的配置文件中,sscms 的其他实例设置为在端口 5001 上运行。 “代理” 部分设置了具有两个成员的均衡器配置,以便对 byrequests 进行负载均衡。

<VirtualHost *:*>
    RequestHeader set "X-Forwarded-Proto" expr=%{REQUEST_SCHEME}
</VirtualHost>

<VirtualHost *:80>
    RewriteEngine On
    RewriteCond %{HTTPS} !=on
    RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L]
</VirtualHost>

<VirtualHost *:443>
    ProxyPass / balancer://mycluster/ 

    ProxyPassReverse / http://127.0.0.1:5000/
    ProxyPassReverse / http://127.0.0.1:5001/

    <Proxy balancer://mycluster>
        BalancerMember http://127.0.0.1:5000
        BalancerMember http://127.0.0.1:5001 
        ProxySet lbmethod=byrequests
    </Proxy>

    <Location />
        SetHandler balancer
    </Location>
    ErrorLog /var/log/httpd/sscms-error.log
    CustomLog /var/log/httpd/sscms-access.log common
    SSLEngine on
    SSLProtocol all -SSLv2
    SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:!RC4+RSA:+HIGH:+MEDIUM:!LOW:!RC4
    SSLCertificateFile /etc/pki/tls/certs/localhost.crt
    SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
</VirtualHost>

# 速率限制

使用 httpd 模块中包含的 mod_ratelimit ,客户端的带宽可以限制为:

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

示例文件将根位置下的带宽限制为 600 KB/秒:

<IfModule mod_ratelimit.c>
    <Location />
        SetOutputFilter RATE_LIMIT
        SetEnv rate-limit 600
    </Location>
</IfModule>

# 较长的请求标头字段

代理服务器默认设置通常将请求标头字段限制为 8190 字节。 如果需要更长的字段,则代理服务器的 LimitRequestFieldSize 指令需要进行调整。 要应用的值具体取决于方案。 有关详细信息,请参见服务器文档。

注意

除非必要,否则不要提高 LimitRequestFieldSize 的默认值。 提高该值将增加缓冲区溢出的风险和恶意用户的拒绝服务 (DoS) 攻击风险。

上次更新: 2020-5-24 11:33:43