架构师实战:Nginx 生产级源码部署与内部可信自签证书全指南

/ 默认分类 / 没有评论 / 4浏览

前言

在内部开发、测试或预生产环境中,我们经常需要快速部署 HTTPS 服务,但又无法为每个内部域名或 IP 申请公共 CA 签发的证书。同时,使用系统包管理器(如 yum install nginx)虽然便捷,但往往版本滞后,且难以定制编译模块。

本文将从架构师视角,完整记录如何在 CentOS 7/8 类环境中,通过源码编译安装 Nginx(便于定制模块和优化路径),并结合 mkcert 工具,实现全链路可信的自签证书方案。该方案的核心价值在于:

  1. 源码可控:自主选择版本和编译模块,避免操作系统依赖。
  2. 权限最小化:使用 setcap 赋予 Nginx 绑定特权端口能力,无需以 root 运行进程。
  3. 证书信任闭环:通过 mkcert 统一管理根证书,解决浏览器“不安全”警告问题,提升内部体验。

第一部分:Nginx 生产级源码安装

1. 环境准备与依赖安装

生产环境建议预先安装编译工具链和必需的开发库。

bash

# 安装编译器和基础库 (gcc, pcre, zlib, openssl)
sudo yum install gcc pcre-devel zlib-devel openssl-devel make -y

2. 下载与解压

选择稳定的主线版本或稳定版。以 1.30.0 为例:

bash

wget https://nginx.org/download/nginx-1.30.0.tar.gz
tar -zxvf nginx-1.30.0.tar.gz
cd nginx-1.30.0

3. 编译配置(架构关键点)

此处根据生产需求,启用 http_ssl_module(HTTPS)、http_v2_module(HTTP/2)、http_gzip_static_module(静态压缩)。并设定规范安装路径 /usr/local/nginx

bash

./configure --prefix=/usr/local/nginx \
            --with-http_ssl_module \
            --with-http_v2_module \
            --with-http_gzip_static_module

# 并行编译并安装 (make -j 可利用多核)
make -j $(nproc)
sudo make install

4. 配置 systemd 服务(标准运维)

创建系统服务文件,实现标准化启停和开机自启。

bash

sudo vi /etc/systemd/system/nginx.service

填入以下内容(注意根据实际路径修改 PIDFile 及配置路径):

ini

[Unit]
Description=nginx - high performance web server
Documentation=http://nginx.org/en/docs/
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

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

[Install]
WantedBy=multi-user.target

启动与管理:

bash

sudo systemctl daemon-reload
sudo systemctl start nginx
sudo systemctl enable nginx
sudo systemctl status nginx

5. 权限最小化实践(架构亮点)

默认 Nginx 需要以 root 启动才能绑定 80/443 端口。生产环境建议使用普通用户运行,并通过 setcap 赋予二进制文件绑定特权端口的能力。

bash

# 假设运行用户为 nginx (需预先创建)
# 赋予 cap_net_bind_service 能力
sudo setcap 'cap_net_bind_service=+ep' /usr/local/nginx/sbin/nginx

# 验证能力已设置
getcap /usr/local/nginx/sbin/nginx

此后,可以在 nginx.conf 中设置 user nginx;,并以非 root 用户运行 master 进程,提升安全性。


第二部分:内部可信自签证书(mkcert 方案)

传统 openssl 生成的自签证书会导致浏览器出现无法消除的安全警告。mkcert 通过本地安装根 CA,实现了完整的信任链,非常适合内部网络环境

1. 安装 mkcert

bash

# 安装依赖
sudo yum install nss-tools -y

# 下载最新版 (建议从 GitHub 获取最新版本号)
wget https://github.com/FiloSottile/mkcert/releases/download/v1.4.4/mkcert-v1.4.4-linux-amd64

chmod +x mkcert-v1.4.4-linux-amd64
sudo mv mkcert-v1.4.4-linux-amd64 /usr/local/bin/mkcert

# 验证
mkcert -version

2. 初始化本地 CA 并生成证书

bash

# 将根 CA 安装到系统信任库 (需要 sudo)
mkcert -install

# 生成包含 localhost、127.0.0.1、内网IP、IPv6 的证书
# 请将 192.168.1.100 替换为服务器的真实内网 IP
mkcert localhost 127.0.0.1 192.168.1.100 ::1

# 执行后生成类似 localhost+2.pem 和 localhost+2-key.pem 的文件

3. 配置 Nginx 使用证书

创建证书存放目录并复制文件。

bash

# 创建证书目录
mkdir -p /usr/local/nginx/ssl
# 复制并重命名为规范名称
cp localhost+2.pem /usr/local/nginx/ssl/server.crt
cp localhost+2-key.pem /usr/local/nginx/ssl/server.key

配置 Nginx (/usr/local/nginx/conf/nginx.conf)

以下是一个完整的 HTTPS server 配置示例:

nginx

server {
    listen 443 ssl;
    http2 on;   # 启用 HTTP/2
    server_name 192.168.1.100 localhost;  # 替换为你的实际 IP/域名

    # 证书路径
    ssl_certificate     /usr/local/nginx/ssl/server.crt;
    ssl_certificate_key /usr/local/nginx/ssl/server.key;

    # 现代 SSL 配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    # 可选: 增强安全性 (HSTS)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    location / {
        root   html;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }
}

4. 重载 Nginx 配置

bash

# 检查配置文件语法
/usr/local/nginx/sbin/nginx -t

# 平滑重载
/usr/local/nginx/sbin/nginx -s reload
# 或使用 systemctl: sudo systemctl reload nginx

第三部分:客户端信任根证书(实现零警告的关键)

要让浏览器完全信任该自签证书,必须在每台访问设备的系统中安装 mkcert 生成的根证书。这是本方案与普通自签证书的本质区别。

1. 导出根证书

在服务器上执行,获取根证书位置:

bash

mkcert -CAROOT
# 输出示例: /home/youruser/.local/share/mkcert
# 进入该目录,找到 rootCA.pem 文件

rootCA.pem 安全分发到客户端(通过内部 Wiki、对象存储、或一次性 HTTP 下载)。

2. 各操作系统安装指南

完成上述操作后,浏览器访问 https://你的服务器IP 将不再出现安全警告,地址栏显示安全锁图标。


总结

本文档提供了两套紧密结合的实践:

  1. 源码编译 Nginx:确保了对版本、模块和安装路径的完全控制,结合 setcap 实现了非 root 运行,符合安全基线。
  2. mkcert 自签证书:解决了传统自签证书不受浏览器信任的痛点,通过分发根 CA,在内部环境中实现了“类生产”的 HTTPS 体验。

作为架构师,建议将此流程固化为内部运维文档或自动化脚本(如 Ansible role),以便在服务器批量部署和证书轮换时做到高效、一致。