Contents

运维架构师笔记:Nginx 源码编译安装与生产级高阶配置实战

前言:为什么放弃 apt install 选择源码编译?

在日常开发和测试环境中,我们往往习惯于一条 apt install nginxyum install nginx 解决问题。但在真正的高并发生产环境中,包管理工具提供的预编译版本往往显得“捉襟见肘”。

作为运维架构师,我们坚持源码编译 Nginx,通常基于以下几个核心痛点:

  1. 模块按需定制:官方包往往不包含特定业务需要的第三方模块(如特定版本的 SSL/TLS、GeoIP、四层 Stream 代理等),源码编译能做到“要什么装什么”,保持极简。
  2. 性能深度压榨:可以通过编译参数和特定硬件架构(如开启 CPU 优化指令集)深度结合,最大化吞吐量。
  3. 安全与合规把控:隐藏真实版本号、统一公司内部的 FHS(文件系统层次结构)目录规范、避免冗余依赖带来的 CVE 漏洞风险。

本文将以 Debian 12 为例,带你完整走一遍 Nginx 1.28 的生产级源码编译与配置流程。


实验环境准备

服务商 数据中心 产品名称 服务器规格 操作系统
搬瓦工 洛杉矶 20G KVM - PROMO VPS 2C/1G/20G Debian 12.9

💡 提示:此教程同样适用于 Ubuntu 全系以及大部分基于 Debian 的 Linux 发行版。如果是 RHEL/CentOS 系,仅需将下文的 apt 替换为 yum/dnf 并修改对应的依赖包名即可。


🚀 源码编译安装 Nginx 步骤

1. 安装底层编译依赖

无论你是做 Web 代理还是流媒体分发,基础的依赖库是必不可少的。

sudo apt update -y
# 安装 gcc、pcre (正则路由)、zlib (gzip压缩)、openssl (https) 等核心依赖
sudo apt install -y build-essential libpcre3-dev zlib1g-dev libssl-dev \
    libxslt1-dev libgd-dev libgeoip-dev libgoogle-perftools-dev

2. 构建符合 FHS 标准的目录结构

不要让你的 Nginx 配置文件散落在系统各处!提前建立清晰的目录结构,是日后不被接手同事“问候”的基础。

# 1. 核心配置与站点目录
mkdir -p /etc/nginx/{conf.d,sites-available,sites-enabled,ssl}

# 2. 业务日志独立目录
mkdir -p /var/log/nginx

# 3. 运行时临时文件目录
mkdir -p /var/lib/nginx/{client_body,proxy,fastcgi,uwsgi,scgi}

# 4. 权限收紧
chown -R www-data:root /var/log/nginx /var/lib/nginx
chmod -R 700 /var/lib/nginx

3. 下载源码并执行 Configure (编译参数解析)

进入源码目录,下载目前较新的 1.28.2 版本。

Nginx 官方网站,一定要选择 Stable version 版本

cd /usr/src

wget https://nginx.org/download/nginx-1.28.2.tar.gz

cd /usr/src/nginx-1.28.2

./configure \
    --prefix=/usr/share/nginx \
    --sbin-path=/usr/sbin/nginx \
    --modules-path=/usr/lib/nginx/modules \
    --conf-path=/etc/nginx/nginx.conf \
    --error-log-path=/var/log/nginx/error.log \
    --http-log-path=/var/log/nginx/access.log \
    --pid-path=/run/nginx.pid \
    --lock-path=/run/nginx.lock \
    --http-client-body-temp-path=/var/lib/nginx/client_body \
    --http-proxy-temp-path=/var/lib/nginx/proxy \
    --http-fastcgi-temp-path=/var/lib/nginx/fastcgi \
    --http-uwsgi-temp-path=/var/lib/nginx/uwsgi \
    --http-scgi-temp-path=/var/lib/nginx/scgi \
    --user=www-data \
    --group=www-data \
    --with-poll_module \
    --with-threads \
    --with-file-aio \
    --with-http_ssl_module \
    --with-http_v2_module \
    --with-http_realip_module \
    --with-http_xslt_module \
    --with-http_image_filter_module \
    --with-http_geoip_module \
    --with-http_sub_module \
    --with-http_dav_module \
    --with-http_flv_module \
    --with-http_mp4_module \
    --with-http_gunzip_module \
    --with-http_gzip_static_module \
    --with-http_auth_request_module \
    --with-http_random_index_module \
    --with-http_secure_link_module \
    --with-http_degradation_module \
    --with-http_slice_module \
    --with-http_stub_status_module \
    --with-mail \
    --with-stream \
    --with-stream_ssl_module \
    --with-stream_ssl_preread_module \
    --with-stream_realip_module \
    --with-stream_geoip_module \
    --with-google_perftools_module \
    --with-pcre

# 多核并行编译并安装,大幅缩短等待时间
make -j$(nproc) && make install

4. 编写生产级主配置文件 (nginx.conf)

编译完成后,我们需要一套开箱即用的配置文件。这套配置中,我特别加入了 基于 SNI 的 443 端口复用分流(Stream 模块) 以及 JSON 格式的日志输出,极其适合现代化日志收集平台(如 ELK / Loki)。

# 生成主配置文件
cat > /etc/nginx/nginx.conf << 'EOF'
# =====================================================
# Main Nginx configuration file (FHS Standard)
# =====================================================

user www-data;
worker_processes auto;
pid /run/nginx.pid;

events {
    # 允许一个 worker 同时接受多个连接,提升并发
    worker_connections 1024;
    multi_accept on;
}

# =====================================================
# TCP 四层:基于 SNI 的 443 端口复用分流
# 适用场景:同一个 443 端口,既跑 Web,又跑探针、反代图床
# =====================================================
stream {
    map $ssl_preread_server_name $backend {
        probe.test.com        probe;
        blog.test.com         blog;
        filebox.test.com      filebox;
        default               blog;
    }

    upstream probe { server 127.0.0.1:10001; }
    upstream blog { server 127.0.0.1:10002; }
    upstream filebox { server 127.0.0.1:10003; }

    server {
        listen 443 reuseport;
        listen [::]:443 reuseport;
        proxy_protocol on;     # 获取真实客户端 IP
        ssl_preread on;        # 开启 SNI 预读
        proxy_pass $backend;
    }
}

# =====================================================
# HTTP 七层配置
# =====================================================
http {
    # 信任代理 IP,获取真实 User IP
    set_real_ip_from 127.0.0.1;
    set_real_ip_from ::1;
    real_ip_header proxy_protocol;
    real_ip_recursive on;

    server_tokens off; # 隐藏 Nginx 版本号,提升安全性
    sendfile on;

    # 将日志改成 JSON 格式,方便 ELK/Loki 采集分析
    log_format json escape=json '{'
        '"time_local":"$time_local",'
        '"remote_addr":"$remote_addr",'
        '"request":"$request",'
        '"status":$status,'
        '"body_bytes_sent":$body_bytes_sent,'
        '"http_referer":"$http_referer",'
        '"http_user_agent":"$http_user_agent",'
        '"request_time":$request_time,'
        '"upstream_response_time":"$upstream_response_time"'
    '}';

    access_log /var/log/nginx/access.log json;
    error_log /var/log/nginx/error.log;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    # Gzip 压缩优化
    gzip on;
    gzip_comp_level 6;
    gzip_min_length 1k;
    gzip_types text/plain application/xml text/css application/javascript application/json;

    # 包含子配置文件
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*.conf;
}
EOF
# 创建软链接
for conf in /etc/nginx/sites-available/*.conf; do
    ln -s "$conf" /etc/nginx/sites-enabled/
done

5. 注册 Systemd 服务与平滑接管

使用 Systemd 管理编译安装的 Nginx 服务

cat > /etc/systemd/system/nginx.service << 'EOF'
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -c /etc/nginx/nginx.conf
ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target
EOF

配置验证与启动:

# 1. 验证配置是否有语法错误
/usr/sbin/nginx -t

# 2. 重新加载 systemd 并设置开机自启
systemctl daemon-reload
systemctl enable --now nginx

# 3. 查看运行状态,确保 Active: active (running)
systemctl status nginx

至此,一个部署路径规范、支持 443 端口复用且受 Systemd 优雅管理的 Nginx 就完成了!