跳转到内容
搜索 RunEntLinux 文档

仅搜索 RunEntLinux 通用文档,各发行版文档使用各自的搜索入口。

    浏览当前文档目录

    Nginx 应用部署实战

    本文提供一份完整的 Nginx 应用部署手册,涵盖从安装 Nginx 到配置反向代理、SSL 证书、SELinux 策略和日志轮转的全过程。适用于将 Nginx 作为前端代理转发到 Node.js、Python (Gunicorn/uWSGI) 或 PHP-FPM 后端的典型场景。

    • 服务器已完成 新机上线基线清单
    • 已有域名并解析到服务器 IP
    • 后端应用已部署并可在本地端口(如 127.0.0.1:3000)上运行
    Terminal window
    dnf install -y nginx

    使用 Nginx 官方仓库(推荐获取最新稳定版)

    Section titled “使用 Nginx 官方仓库(推荐获取最新稳定版)”
    Terminal window
    cat > /etc/yum.repos.d/nginx.repo << 'EOF'
    [nginx-stable]
    name=nginx stable repo
    baseurl=https://nginx.org/packages/centos/$releasever/$basearch/
    gpgcheck=1
    enabled=1
    gpgkey=https://nginx.org/keys/nginx_signing.key
    module_hotfixes=true
    EOF
    dnf install -y nginx

    启动并启用服务:

    Terminal window
    systemctl enable --now nginx
    # 验证
    systemctl status nginx
    curl -I http://localhost

    移除默认配置并创建应用专属配置:

    Terminal window
    # 备份默认配置
    mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak

    创建应用配置文件 /etc/nginx/conf.d/myapp.conf:

    # 上游后端定义
    upstream myapp_backend {
    server 127.0.0.1:3000;
    keepalive 32;
    }
    server {
    listen 80;
    server_name example.com www.example.com;
    # 访问日志与错误日志
    access_log /var/log/nginx/myapp_access.log;
    error_log /var/log/nginx/myapp_error.log;
    # 安全头
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    # 静态文件(如果有)
    location /static/ {
    alias /var/www/myapp/static/;
    expires 30d;
    add_header Cache-Control "public, immutable";
    }
    # 反向代理到后端
    location / {
    proxy_pass http://myapp_backend;
    proxy_http_version 1.1;
    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_set_header Connection "";
    # 超时设置
    proxy_connect_timeout 60s;
    proxy_send_timeout 60s;
    proxy_read_timeout 60s;
    }
    # 健康检查端点
    location /health {
    proxy_pass http://myapp_backend/health;
    access_log off;
    }
    }

    PHP-FPM 后端:

    upstream php_backend {
    server unix:/run/php-fpm/www.sock;
    }
    location ~ \.php$ {
    fastcgi_pass php_backend;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
    }

    Python (Gunicorn) 后端:

    upstream gunicorn_backend {
    server unix:/run/gunicorn/myapp.sock;
    }
    location / {
    proxy_pass http://gunicorn_backend;
    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;
    }

    测试并重载配置:

    Terminal window
    nginx -t
    systemctl reload nginx

    第 3 步:SSL 证书(Let’s Encrypt + Certbot)

    Section titled “第 3 步:SSL 证书(Let’s Encrypt + Certbot)”
    Terminal window
    dnf install -y epel-release
    dnf install -y certbot python3-certbot-nginx
    Terminal window
    certbot --nginx -d example.com -d www.example.com

    Certbot 会自动修改 Nginx 配置以启用 SSL。验证生成的配置:

    Terminal window
    nginx -t

    Certbot 安装后会自动创建 systemd timer:

    Terminal window
    # 查看续期定时器
    systemctl list-timers | grep certbot
    # 手动测试续期(dry-run)
    certbot renew --dry-run

    在 /etc/nginx/conf.d/ssl-params.conf 中添加全局 SSL 优化:

    # SSL 协议和密码套件
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
    ssl_prefer_server_ciphers on;
    # SSL 会话缓存
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;
    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 1.1.1.1 valid=300s;
    resolver_timeout 5s;
    # HSTS
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;

    SELinux 默认不允许 Nginx 向网络后端发起连接。必须配置相应布尔值:

    Terminal window
    # 允许 Nginx 连接到网络后端
    setsebool -P httpd_can_network_connect 1
    # 如果 Nginx 需要访问用户主目录下的内容
    setsebool -P httpd_enable_homedirs 1
    # 如果 Nginx 需要连接数据库
    setsebool -P httpd_can_network_connect_db 1

    如果静态文件位于非标准路径,需要设置 SELinux 上下文:

    Terminal window
    # 设置 Web 内容标签
    semanage fcontext -a -t httpd_sys_content_t "/var/www/myapp(/.*)?"
    restorecon -Rv /var/www/myapp

    如果 Nginx 监听非标准端口:

    Terminal window
    # 添加端口标签(例如端口 8080)
    semanage port -a -t http_port_t -p tcp 8080

    排查 SELinux 拒绝日志:

    Terminal window
    # 查看拒绝记录
    ausearch -m AVC -ts recent
    # 自动生成策略建议
    audit2why < /var/log/audit/audit.log
    Terminal window
    # 开放 HTTP 和 HTTPS
    firewall-cmd --permanent --add-service=http
    firewall-cmd --permanent --add-service=https
    # 重新加载
    firewall-cmd --reload
    # 验证
    firewall-cmd --list-services

    第 6 步:后端应用的 Systemd 服务

    Section titled “第 6 步:后端应用的 Systemd 服务”

    为后端应用创建 systemd 服务单元,以 Node.js 应用为例:

    Terminal window
    cat > /etc/systemd/system/myapp.service << 'EOF'
    [Unit]
    Description=My Application
    Documentation=https://example.com/docs
    After=network-online.target
    Wants=network-online.target
    [Service]
    Type=simple
    User=appuser
    Group=appuser
    WorkingDirectory=/opt/myapp
    ExecStart=/usr/bin/node /opt/myapp/server.js
    Restart=on-failure
    RestartSec=5
    StartLimitInterval=60
    StartLimitBurst=3
    # 环境变量
    Environment=NODE_ENV=production
    Environment=PORT=3000
    EnvironmentFile=-/opt/myapp/.env
    # 安全加固
    NoNewPrivileges=true
    ProtectSystem=strict
    ProtectHome=true
    ReadWritePaths=/opt/myapp/data /var/log/myapp
    PrivateTmp=true
    # 资源限制:MemoryMax 是运维参数,按实测常驻内存设定(示例 1G,不是最低要求)
    LimitNOFILE=65536
    MemoryMax=1G
    # 日志
    StandardOutput=journal
    StandardError=journal
    SyslogIdentifier=myapp
    [Install]
    WantedBy=multi-user.target
    EOF

    Gunicorn 示例:

    Terminal window
    cat > /etc/systemd/system/myapp.service << 'EOF'
    [Unit]
    Description=Gunicorn Application Server
    After=network-online.target
    [Service]
    Type=notify
    User=appuser
    Group=appuser
    WorkingDirectory=/opt/myapp
    ExecStart=/opt/myapp/venv/bin/gunicorn \
    --workers 4 \
    --bind unix:/run/gunicorn/myapp.sock \
    --access-logfile /var/log/myapp/access.log \
    --error-logfile /var/log/myapp/error.log \
    wsgi:app
    ExecReload=/bin/kill -s HUP $MAINPID
    Restart=on-failure
    RuntimeDirectory=gunicorn
    [Install]
    WantedBy=multi-user.target
    EOF

    启动服务:

    Terminal window
    # 创建应用用户
    useradd -r -s /sbin/nologin appuser
    # 设置目录权限
    chown -R appuser:appuser /opt/myapp
    systemctl daemon-reload
    systemctl enable --now myapp
    # 验证
    systemctl status myapp
    curl http://127.0.0.1:3000/health

    确保后端应用实现了 /health 端点,返回当前服务状态。最小示例(Node.js):

    app.get('/health', (req, res) => {
    res.status(200).json({
    status: 'ok',
    uptime: process.uptime(),
    timestamp: Date.now()
    });
    });

    创建一个简单的健康检查脚本:

    cat > /usr/local/bin/health-check.sh << 'SCRIPT'
    #!/bin/bash
    URL="http://127.0.0.1/health"
    HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$URL" --max-time 5)
    if [ "$HTTP_CODE" != "200" ]; then
    echo "[$(date)] Health check failed: HTTP $HTTP_CODE" >> /var/log/health-check.log
    systemctl restart myapp
    systemctl reload nginx
    fi
    SCRIPT
    chmod +x /usr/local/bin/health-check.sh

    添加定时检查:

    Terminal window
    cat > /etc/cron.d/health-check << 'EOF'
    */5 * * * * root /usr/local/bin/health-check.sh
    EOF

    部署完成后,进行完整的端到端测试:

    Terminal window
    # HTTP 到 HTTPS 重定向
    curl -I http://example.com
    # HTTPS 正常响应
    curl -I https://example.com
    # 后端健康检查
    curl https://example.com/health
    # SSL 证书信息
    echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates

    Nginx 的默认日志轮转通常已配置。为应用自定义日志添加规则:

    Terminal window
    cat > /etc/logrotate.d/myapp << 'EOF'
    /var/log/myapp/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 appuser appuser
    sharedscripts
    postrotate
    /bin/systemctl reload myapp > /dev/null 2>&1 || true
    endscript
    }
    /var/log/nginx/myapp_*.log {
    daily
    missingok
    rotate 30
    compress
    delaycompress
    notifempty
    create 0640 nginx adm
    sharedscripts
    postrotate
    /bin/kill -USR1 $(cat /run/nginx.pid 2>/dev/null) 2>/dev/null || true
    endscript
    }
    EOF

    测试配置:

    Terminal window
    logrotate -d /etc/logrotate.d/myapp
    序号检查项验证命令预期结果
    1Nginx 运行systemctl status nginxactive
    2配置语法nginx -tsyntax is ok
    3SSL 证书certbot certificates有效且未过期
    4SELinux 布尔值getsebool httpd_can_network_connecton
    5防火墙firewall-cmd --list-serviceshttp https
    6后端服务systemctl status myappactive
    7健康检查curl http://127.0.0.1/health200 OK
    8HTTPS 访问curl -I https://example.com200 OK
    9日志轮转logrotate -d /etc/logrotate.d/myapp无错误
    问题排查步骤
    502 Bad Gateway检查后端服务是否运行;检查 SELinux httpd_can_network_connect;查看 /var/log/nginx/myapp_error.log
    403 Forbidden检查文件权限;检查 SELinux 上下文 ls -Z;运行 restorecon
    SSL 证书过期运行 certbot renew;检查 systemd timer systemctl status certbot-renew.timer
    连接被拒检查 firewall-cmd --list-all;确认 Nginx 监听正确端口 ss -tlnp