跳转至

20. Web 服务配置

本章介绍 RHEL 9 上 Apache(httpd)和 Nginx 两大主流 Web 服务器的安装与核心配置:虚拟主机、HTTPS、反向代理与负载均衡。Web 服务是业务应用层的入口,也是第 21 章数据库和后续服务集成的前端层。


20.1 前提条件

  • 已完成第三阶段全部配置(第 15–19 章)。
  • 通过 SecureCRT(SSH 端口 2222)以 ops 用户、密钥认证方式登录 192.168.1.100,执行 sudo -i 切换至 root 环境。
  • SELinux 处于 Enforcing 模式,firewalld 已启用(第 12 章)。
  • 官方仓库和 EPEL 仓库已启用(第 7 章)。

本章全局参数

参数
主机名 / IP linuxdc / 192.168.1.100
虚拟主机域名 site1.linuxdc.local
反向代理后端 192.168.1.101:8080
负载均衡后端池 192.168.1.101:80192.168.1.102:80

Apache 与 Nginx 端口冲突

Apache 和 Nginx 默认均监听 80/443 端口,不能同时绑定同一端口。本章先完整配置 Apache,再停止 Apache 后演示 Nginx 配置,避免端口冲突。


20.2 Apache 配置

20.2.1 安装与启动

dnf install -y httpd mod_ssl
systemctl enable --now httpd
systemctl status httpd

开放防火墙:

firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload

创建默认测试页面:

echo "<h1>Hello from Apache on linuxdc</h1>" > /var/www/html/index.html

# 修复 SELinux 上下文
restorecon -Rv /var/www/html/

验证:

curl http://localhost
curl http://192.168.1.100

检查点

curl http://192.168.1.100 返回 Hello from Apache on linuxdc

20.2.2 配置虚拟主机

虚拟主机使单台服务器托管多个域名站点,是企业多站点部署的标准方式。

# 创建站点目录
mkdir -p /var/www/site1/html
echo "<h1>Site1 - linuxdc</h1>" > /var/www/site1/html/index.html

# 设置目录所有者与 SELinux 上下文
chown -R apache:apache /var/www/site1/
semanage fcontext -a -t httpd_sys_content_t "/var/www/site1(/.*)?"
restorecon -Rv /var/www/site1/

创建虚拟主机配置文件:

tee /etc/httpd/conf.d/site1.conf << 'EOF'
<VirtualHost *:80>
    ServerName  site1.linuxdc.local
    ServerAlias www.site1.linuxdc.local
    DocumentRoot /var/www/site1/html

    <Directory /var/www/site1/html>
        Options -Indexes +FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>

    ErrorLog  /var/log/httpd/site1-error.log
    CustomLog /var/log/httpd/site1-access.log combined
</VirtualHost>
EOF

# 验证配置语法(有错误时会报告具体行号)
apachectl configtest

systemctl reload httpd

添加本地 DNS 解析并验证:

echo "192.168.1.100 site1.linuxdc.local" >> /etc/hosts
curl http://site1.linuxdc.local

检查点

curl http://site1.linuxdc.local 返回 Site1 - linuxdc

20.2.3 配置 HTTPS

自签名证书(实验环境):

# 生成 RSA 2048 位自签名证书(有效期 365 天)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout /etc/pki/tls/private/linuxdc.key \
  -out /etc/pki/tls/certs/linuxdc.crt \
  -subj "/CN=site1.linuxdc.local/O=linuxdc/C=CN"

# 设置私钥权限
chmod 600 /etc/pki/tls/private/linuxdc.key

创建 SSL 虚拟主机配置:

tee /etc/httpd/conf.d/site1-ssl.conf << 'EOF'
<VirtualHost *:443>
    ServerName site1.linuxdc.local
    DocumentRoot /var/www/site1/html

    SSLEngine on
    SSLCertificateFile    /etc/pki/tls/certs/linuxdc.crt
    SSLCertificateKeyFile /etc/pki/tls/private/linuxdc.key

    # 安全加固:禁用不安全协议和弱密码套件
    SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
    SSLCipherSuite HIGH:!aNULL:!MD5:!3DES

    <Directory /var/www/site1/html>
        Require all granted
    </Directory>

    ErrorLog  /var/log/httpd/site1-ssl-error.log
    CustomLog /var/log/httpd/site1-ssl-access.log combined
</VirtualHost>
EOF

apachectl configtest && systemctl reload httpd

# -k 参数跳过自签名证书验证
curl -k https://site1.linuxdc.local

生产环境:Let's Encrypt 免费证书

生产环境(需公网域名和 80/443 可达):

dnf install -y certbot python3-certbot-apache
certbot --apache -d your-domain.com
systemctl enable --now certbot-renew.timer

certbot-renew.timer 每天自动检查并在到期前 30 天续期,实现证书免运维管理。

20.2.4 HTTP 强制跳转 HTTPS

生产环境中,所有 HTTP 请求应自动重定向到 HTTPS:

# 修改 site1.conf,在 <VirtualHost *:80> 内添加重定向
tee /etc/httpd/conf.d/site1.conf << 'EOF'
<VirtualHost *:80>
    ServerName  site1.linuxdc.local
    ServerAlias www.site1.linuxdc.local

    # 永久重定向(301)到 HTTPS
    RewriteEngine on
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</VirtualHost>
EOF

apachectl configtest && systemctl reload httpd

验证重定向:

# -L 跟随重定向,-I 只显示响应头
curl -LI http://site1.linuxdc.local 2>&1 | grep -E "HTTP|Location"

20.3 Nginx 配置

20.3.1 安装与启动

停止 Apache 以释放 80/443 端口:

systemctl stop httpd
systemctl disable httpd

安装并启动 Nginx:

dnf install -y nginx
systemctl enable --now nginx
systemctl status nginx

创建测试页面:

echo "<h1>Hello from Nginx on linuxdc</h1>" > /usr/share/nginx/html/index.html
restorecon -Rv /usr/share/nginx/html/

# 验证配置语法
nginx -t

curl http://localhost

检查点

nginx -t 输出 syntax is oktest is successfulcurl http://localhost 返回正确内容。

20.3.2 配置反向代理

将外部请求转发至后端应用服务器(192.168.1.101:8080):

tee /etc/nginx/conf.d/proxy.conf << 'EOF'
server {
    listen 80;
    server_name proxy.linuxdc.local;

    location / {
        proxy_pass            http://192.168.1.101:8080;
        proxy_set_header      Host              $host;
        proxy_set_header      X-Real-IP         $remote_addr;
        proxy_set_header      X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header      X-Forwarded-Proto $scheme;
        proxy_connect_timeout 10s;
        proxy_read_timeout    30s;
        proxy_send_timeout    30s;
    }
}
EOF

nginx -t && systemctl reload nginx

SELinux 允许 Nginx 发起出站网络连接(反向代理必须配置):

setsebool -P httpd_can_network_connect on

# 验证布尔值已设置
getsebool httpd_can_network_connect

20.3.3 配置负载均衡

tee /etc/nginx/conf.d/lb.conf << 'EOF'
upstream backend_pool {
    least_conn;                        # 最少连接算法(默认 round-robin)
    server 192.168.1.101:80 weight=2;  # 权重 2,承载更多流量
    server 192.168.1.102:80 weight=1;
    keepalive 16;                      # 保持后端长连接,减少握手开销
}

server {
    listen 80;
    server_name lb.linuxdc.local;

    location / {
        proxy_pass            http://backend_pool;
        proxy_set_header      Host              $host;
        proxy_set_header      X-Real-IP         $remote_addr;
        proxy_set_header      X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_http_version    1.1;
        proxy_set_header      Connection        "";  # keepalive 必须清空 Connection 头
    }
}
EOF

nginx -t && systemctl reload nginx

Nginx 负载均衡算法说明:

算法 指令 适用场景
轮询(默认) 无需指定 各后端处理能力相近
权重轮询 weight=N 后端服务器性能差异明显
最少连接 least_conn 请求处理时间差异大
IP 哈希 ip_hash 需要会话粘滞(同一 IP 固定后端)

20.4 常见问题与排查

问题现象 排查步骤
httpd / nginx 启动失败 apachectl configtestnginx -tjournalctl -u httpd -n 30
80 端口被占用 ss -tulnp | grep :80 找出占用进程
访问返回 403 Forbidden 检查目录权限;ls -lZ /var/www/restorecon -Rv 修复 SELinux 上下文
SELinux 阻止反向代理连接 setsebool -P httpd_can_network_connect on
虚拟主机配置未生效 apachectl -S 查看虚拟主机解析结果;确认 DNS 或 /etc/hosts 解析正确
HTTPS 证书错误 确认证书路径正确;openssl x509 -in /etc/pki/tls/certs/linuxdc.crt -text -noout 查看证书信息
# Apache 综合诊断
apachectl -S                        # 虚拟主机解析情况
tail -f /var/log/httpd/error_log    # 错误日志实时追踪

# Nginx 综合诊断
journalctl -u nginx -f              # 系统日志实时追踪
tail -f /var/log/nginx/error.log    # Nginx 错误日志

20.5 实践任务

  1. 登录 linuxdc(SecureCRT 端口 2222,ops 用户,密钥认证,sudo -i 切换 root)。
  2. 安装 Apache,创建测试页面,验证 curl http://192.168.1.100 返回正确内容。
  3. 配置虚拟主机 site1.linuxdc.local,添加 /etc/hosts 解析,验证访问。
  4. 配置自签名 HTTPS,验证 curl -k https://site1.linuxdc.local 正常返回。
  5. 配置 HTTP → HTTPS 重定向,用 curl -LI 验证 301 跳转。
  6. 停止 Apache,安装 Nginx,配置反向代理,执行 nginx -t 验证语法。
  7. 配置 upstream 负载均衡块,执行 nginx -t 确认语法无误。

20.6 自测问题

Q1:Apache 配置修改后,应使用 reload 还是 restart

配置修改后优先使用 systemctl reload httpd(等同于 apachectl graceful)。reload 让主进程重读配置并通知工作进程在处理完当前请求后平滑替换,不中断已有连接,业务零感知。restart 先停止再启动进程,所有正在处理的请求会被强制中断。生产环境应始终优先使用 reloadrestart 仅用于需要重新加载共享库(如安装 mod_ssl)等特殊场景。

Q2:Nginx 反向代理为何必须执行 setsebool -P httpd_can_network_connect on

SELinux 默认不允许 httpd_t 类型进程(含 Nginx)主动发起对外网络连接,此限制可防止被攻陷的 Web 进程横向扩展。反向代理需要 Nginx 主动连接后端服务器,属于出站连接,必须通过此布尔值显式授权。未设置时,连接被 SELinux 静默拒绝,/var/log/audit/audit.log 中出现 avc: denied 记录,但错误页面仅显示 502 Bad Gateway,排查时容易误认为是网络问题。

Q3:Nginx upstream 中 least_conn 与默认 round-robin 的本质区别是什么?

round-robin 按顺序轮流分发请求,不考虑后端当前的连接负载,适合请求处理时间相近的场景;least_conn 将新请求发往当前活跃连接数最少的后端,适合请求处理时间差异大的场景(如大文件下载与普通 API 混合),能更均衡地利用后端资源,避免慢请求堆积在某台后端导致过载。


20.7 章节总结

本章完成了 RHEL 9 上 Apache 和 Nginx 的核心配置:虚拟主机(多站点托管)、HTTPS(自签名证书与 Let's Encrypt 自动续期)、HTTP 强制跳转 HTTPS(301 重定向)、Nginx 反向代理(含 SELinux 授权)与加权负载均衡(least_conn 算法)。重点强调了每次配置变更后使用 apachectl configtest / nginx -t 验证语法,以及优先使用 reload 而非 restart 的生产最佳实践。