本文档覆盖两种编译方式,每一部分都从下载讲到安装:
- 第一部分:静态编译 ------ 产出单一静态二进制,不依赖目标机任何库,可打包发给别人直接使用。
- 第二部分:动态编译 ------ 链接系统共享库,体积小、编起来快,但一般只在当前机器/同环境使用。
总览:静态 vs 动态
| 对比项 | 静态编译 | 动态编译 |
|---|---|---|
| 依赖 | 把 pcre/zlib/openssl/libc 全部编进二进制 | 运行时链接系统的 .so 共享库 |
| 产物体积 | 大(几 MB ~ 十几 MB) | 小(二进制本身几百 KB,库在系统里) |
| 跨机器可用性 | 可打包发给任意同架构 glibc 系 Linux 直接用 | 目标机必须有版本匹配的系统库,否则跑不了 |
| 编译复杂度 | 高(要拉依赖源码、强制静态链接、常踩 OpenSSL 坑) | 低(用系统库或包管理器一行装好) |
| 典型用途 | 一次性构建、跨发行版分发、Docker 基础镜像 | 在固定机器/CI 上部署,或就用发行版自带包 |
第一部分:静态编译(Statically Linked)
目标:把 nginx 编译成单一静态二进制 ,不依赖目标机的 pcre / zlib / openssl / libc
共享库,可直接拷贝到任意同架构 Linux(CentOS、Ubuntu 等)上运行。
1.1 下载并解压源码
静态编译需要 PCRE、zlib(以及可选的 OpenSSL)的源码包 ,nginx 在编译时把它们一起编进二进制。
在 nginx 源码目录的同级下载并解压:
bash
cd ~
# nginx 本体
wget https://nginx.org/download/nginx-1.30.4.tar.gz
# 经典 PCRE 8.x(与 nginx --with-pcre 兼容性最好)
wget https://downloads.sourceforge.net/project/pcre/pcre/8.45/pcre-8.45.tar.gz
# zlib(注意:官网没有 1.3.1,当前稳定版是 1.3.2)
wget https://zlib.net/zlib-1.3.2.tar.gz
# OpenSSL(仅当需要使用 HTTPS 时;纯 HTTP 反代可不要)
wget https://www.openssl.org/source/openssl-3.2.1.tar.gz
tar -xzf nginx-1.30.4.tar.gz
tar -xzf pcre-8.45.tar.gz
tar -xzf zlib-1.3.2.tar.gz
tar -xzf openssl-3.2.1.tar.gz
cd nginx-1.30.4
目录结构(关键:依赖源码与 nginx 源码平级):
~/build/ ├── nginx-1.30.4/ # 进入此目录执行 ./configure ├── pcre-8.45/ ├── zlib-1.3.2/ └── openssl-3.2.1/
1.2 清理旧配置(如已 configure 过)
如果之前跑过普通 ./configure(比如提示 "using system PCRE library"),必须先清掉,否则新配置不生效:
bash
cd nginx-1.30.4
rm -rf objs Makefile
1.3 静态 configure
nginx 没有 --enable-static 开关,需要手动把依赖源码编进去并强制静态链接。按是否需要 HTTPS 选方案。
方案 A:纯 HTTP 反代(推荐,最稳)
当前用途是 HTTP 反向代理,proxy_pass http://127.0.0.1:8000,不需要 SSL ;
不带 OpenSSL 可避免静态链接 OpenSSL 的各种麻烦:
bash
cd nginx-1.30.4
./configure \
--prefix=$(pwd)/../nginx_static_dist \
--with-pcre=../pcre-8.45 \
--with-zlib=../zlib-1.3.2 \
--with-cc-opt="-static" \
--with-ld-opt="-static -lpthread"
方案 B:带 HTTPS(SSL)
如需要 443 / SSL,加入 OpenSSL 源码与模块。OpenSSL 静态链接在 glibc 下偶尔挑剔,必要时补 -ldl:
bash
cd nginx-1.30.4
./configure \
--prefix=$(pwd)/../nginx_static_dist \
--with-pcre=../pcre-8.45 \
--with-zlib=../zlib-1.3.2 \
--with-openssl=../openssl-3.2.1 \
--with-http_ssl_module \
--with-http_v2_module \
--with-cc-opt="-static" \
--with-ld-opt="-static -lpthread -ldl"
若链接阶段报 OpenSSL 相关错误,最省事的办法是暂时不带 SSL (用方案 A)。
想彻底避开 glibc 的静态链接坑,见 1.7 节 musl 方案。
⚠️ 特殊说明:CentOS 7 上编 OpenSSL 3.x 极易失败(务必先读)
环境特征 :CentOS 7.x 自带 gcc 4.8.5 (2015 年,Red Hat 4.8.5-44),系统 Perl 也偏旧。
用它去编 OpenSSL 3.2.1(方案 B) 时,
./configure能过(它只检测能否找到 OpenSSL 源码,不真正编译),但
make阶段会踩坑,常见两类报错:坑 1:缺 Perl 模块
IPC::Cmd(最先撞到)
Can't locate IPC/Cmd.pm in @INC ... BEGIN failed--compilation aborted at .../openssl-3.2.1/Configure line 23. make[1]: *** [.../openssl-3.2.1/.openssl/include/openssl/ssl.h] Error 2 make: *** [build] Error 2OpenSSL 3.x 的
Configure脚本依赖 Perl 的IPC::Cmd,CentOS 7 默认不带 → 直接中断。坑 2:即使补上 Perl 模块,gcc 4.8.5 仍可能编不过 OpenSSL 3.2 的 C 代码(版本过老)。
判断依据 :若
make日志里 PCRE、zlib 都已编译成功 (pcre 打印 configuration summary、zlib 生成
libz.a),只在 OpenSSL 处Error 2中断,即是此坑。✅ 推荐解决:方案 A(去掉 OpenSSL,只编 HTTP 反代)
纯 HTTP 反向代理(
proxy_pass http://127.0.0.1:8000)根本用不到 HTTPS ,OpenSSL 纯属多余。重配一次即可绕开全部 OpenSSL 问题(PCRE / zlib 会自动重编,很快):
bashcd nginx-1.30.4 rm -rf objs Makefile ./configure --prefix=$(pwd)/../nginx_static_dist \ --with-pcre=../pcre-8.45 \ --with-zlib=../zlib-1.3.2 \ --with-cc-opt="-static" \ --with-ld-opt="-static -lpthread" make -j$(nproc) make install # root 用户无需 sudo仅当确实需要 HTTPS 时(不推荐在 CentOS 7 硬编)
- 先补 Perl 模块:
yum install -y perl-IPC-Cmd(base 源没有可试 EPEL 或cpan IPC::Cmd);- 再升级编译器:
scl enable devtoolset-9 bash把 gcc 升到 9 后重新make;- 或退回 OpenSSL 1.1.1(已 EOL,有安全隐患,不建议)。
结论 :在 CentOS 7 上做静态编译,优先用方案 A(无 SSL) ,最稳、一次过;
需要 HTTPS 再按上面升级 gcc + 补 Perl 模块,或改用 1.7 节的 Alpine/musl 路线。
1.4 编译并安装
bash
make -j$(nproc)
make install # root 用户直接运行;prefix 指向系统目录(如 /usr/local)时才需 sudo
安装位置(由 --prefix=$(pwd)/../nginx_static_dist 决定,即 nginx 源码同级 的
nginx_static_dist 目录,与源码分开、便于打包):
- 二进制:
../nginx_static_dist/sbin/nginx - 配置:
../nginx_static_dist/conf/nginx.conf - pid / 日志:
../nginx_static_dist/logs/
以上为相对
nginx-1.30.4目录的路径;make install后回到上一级ls就能看到新出现的
nginx_static_dist/。绝对路径示例:/root/nginx_static_build/nginx_static_dist/sbin/nginx。
源码编译版不在 apt/dnf 管理内,nginx不在 PATH,需用全路径
.../nginx_static_dist/sbin/nginx运行,或自行ln -s到/usr/local/bin。
1.5 验证是静态的
bash
ldd ../nginx_static_dist/sbin/nginx
# 期望输出:'not a dynamic executable'
file ../nginx_static_dist/sbin/nginx
# 期望包含:'statically linked'
看到 statically linked 即成功,该二进制可拷到 CentOS / Ubuntu 直接运行。
1.6 ★ 打包分发给他人(静态编译专属)
静态编译的最大价值就在这里:对方机器不需要装任何依赖,拿到包解压即跑。
步骤 1:在你的编译机上打包整个安装目录
因为 --prefix=$(pwd)/../nginx_static_dist 已经把成品装到了一个独立目录 (与源码分开、便于打包),
直接打包这个目录即可,干净利落:
bash
# 回到安装目录的父目录(即源码同级)
cd ..
tar -czf nginx_static_dist.tar.gz nginx_static_dist
包名与目录名一致,便于识别。如需区分不同系统编的产物,可在打包时自行加后缀,例如
nginx_static_dist_centos-7.tar.gz、nginx_static_dist_ubuntu-22.04.tar.gz。
步骤 2:对方解压并运行
bash
# 解压到任意目录,例如 /opt(目录名同名落位即可直接运行;否则用 -p 指定运行前缀,见步骤 3)
tar -xzf nginx_static_dist.tar.gz -C /opt/
# 解压到与编译时同名目录时可直接运行;否则用 -p 指定运行前缀(见步骤 3)
/opt/nginx_static_dist/sbin/nginx
步骤 3:为什么建议用 -p
--prefix 路径(.../nginx_static_dist 的绝对路径)被写死进了二进制 。对方解压到别的位置时,
若直接裸跑 sbin/nginx,它会按编译机那个绝对路径去找 conf/logs 而失败。用 -p 覆盖前缀即可:
bash
/opt/nginx_static_dist/sbin/nginx \
-p /opt/nginx_static_dist \
-c /opt/nginx_static_dist/conf/nginx.conf
-p 覆盖前缀(配置/日志/临时目录都按它找),-c 指定配置文件,这样二进制放哪都能跑。
必须确认的两个前提
- CPU 架构必须一致:x86_64 编的不能给 ARM(aarch64)机器跑。静态只解决"库依赖",不解决"架构"。
- glibc 静态的 DNS 限制 :静态链接 glibc 后,域名解析(NSS)是动态加载的、用不了,会导致
proxy_pass/upstream里用主机名 时在启动时报host not found。
因此给对方的那份nginx.conf一律写 IP 字面量 (如127.0.0.1),不要写主机名。
对方机器自检(可选但建议)
bash
ldd /opt/nginx_static_dist/sbin/nginx # 换成对方实际解压路径
# 显示 not a dynamic executable → 说明不依赖任何 .so,能跑
只要显示 not a dynamic executable,对方无需装 pcre/zlib/openssl/glibc 任何东西。
1.7 备选:用 musl 编译(最干净的可移植静态二进制)
(musl 产物本身已高度可移植,可直接打包分发,无需额外系统标识;如确需区分,自行在包名加后缀即可。)
glibc 静态总有 NSS / TLS 等历史包袱。社区做"一个二进制通吃所有 Linux"通常用
musl libc 编译 nginx(Alpine 系,或 musl-gcc 工具链),产出的静态二进制无 glibc
依赖、DNS 也正常。若需频繁跨发行版分发,这条路线更彻底。
1.7.1 方式 A:在 Ubuntu / Debian 上用 musl-gcc 直接编
bash
sudo apt update
sudo apt install -y musl-tools gcc make # musl-tools 提供 /usr/bin/musl-gcc
cd nginx-1.30.4
CC=/usr/bin/musl-gcc ./configure \
--prefix=/usr/local/nginx \
--with-pcre=../pcre-8.45 \
--with-zlib=../zlib-1.3.2 \
--with-cc-opt="-static" \
--with-ld-opt="-static"
make -j$(nproc)
sudo make install
说明:
- musl 自带 pthread,无需
-lpthread;通常也不需要-ldl。 - musl 静态二进制 DNS 正常(用 musl 自带解析器,无 NSS 动态加载问题),比 glibc 静态更省心。
- 若要带 HTTPS,加
--with-openssl=../openssl-3.2.1 --with-http_ssl_module --with-http_v2_module;
musl 下静态链 OpenSSL 比 glibc 顺利,但若链接报错,可先不带 SSL 跑通流程。
1.7.2 方式 B:在 Alpine 容器里编(最推荐,宿主零污染)
bash
# 宿主机执行:把当前目录(含 nginx / pcre / zlib 源码)挂进容器
docker run --rm -it -v "$PWD":/work -w /work alpine:latest sh
# 容器内:
apk add --no-cache build-base wget
cd nginx-1.30.4
./configure \
--prefix=/usr/local/nginx \
--with-pcre=../pcre-8.45 \
--with-zlib=../zlib-1.3.2 \
--with-openssl=../openssl-3.2.1 \
--with-http_ssl_module --with-http_v2_module \
--with-cc-opt="-static" --with-ld-opt="-static"
make -j$(nproc)
make install
# 产物 /usr/local/nginx/sbin/nginx 即 musl 静态二进制,拷出容器可在任意 Linux 直接运行
注意:Alpine 默认 musl 环境。若链接阶段报缺 libssl.a / libcrypto.a,在容器内
先 apk add --no-cache openssl-libs-static。纯 HTTP 反代可去掉 --with-openssl 三段,最干净。
第二部分:动态编译(Dynamically Linked)
目标:编出的 nginx 链接系统的共享库 (libpcre / libssl / libc 等),
体积孝编译快,但通常只在当前机器 / 同环境使用,不适合随便发给别人。
动态编译有两种做法:
- 做法一(推荐):直接用发行版包管理器装,得到的就是动态链接的 nginx,一行搞定。
- 做法二:从源码动态链接编译(链接系统库,而非把依赖编进二进制)。
2.1 下载与准备(仅做法二需要)
做法一只用包管理器,无需下载源码。做法二需要从源码编,先装好构建依赖 (系统开发库),
再下载解压 nginx 源码(依赖用系统的,不必下载 pcre/zlib/openssl 源码):
bash
# Ubuntu / Debian
sudo apt update
sudo apt install -y build-essential libpcre3-dev zlib1g-dev libssl-dev wget
# CentOS / RHEL / Fedora
sudo dnf install -y gcc make pcre-devel zlib-devel openssl-devel wget
# 下载并解压 nginx 源码
cd ~
wget https://nginx.org/download/nginx-1.30.4.tar.gz
tar -xzf nginx-1.30.4.tar.gz
cd nginx-1.30.4
2.2 做法一:包管理器安装(最推荐)
绝大多数情况下,动态编译 = 直接用系统包。无需下载、无需编译、自动注册服务、自动升级:
bash
# Ubuntu / Debian(含 WSL)
sudo apt update && sudo apt install -y nginx
# CentOS / RHEL / Fedora
sudo dnf install -y nginx
安装位置(发行版约定,非源码前缀):
- 二进制:
/usr/sbin/nginx - 配置:
/etc/nginx/ - 服务:
systemctl start nginx/systemctl enable nginx
装好即是一个动态链接的 nginx,可直接用。
2.3 做法二:源码动态编译
从源码编但不静态链接 :不传 --with-*-opt="-static",也不传 --with-pcre/zlib/openssl 的
源码路径(让 nginx 使用 2.1 装好的系统开发库):
bash
cd nginx-1.30.4
./configure \
--prefix=/usr/local/nginx \
--with-http_ssl_module \
--with-http_v2_module
make -j$(nproc)
sudo make install
要点:
- 没写
--with-pcre=../pcre-8.45这类源码路径 → nginx 改用系统的 PCRE / zlib / OpenSSL 开发库。 - 没写
--with-cc-opt="-static"/--with-ld-opt="-static"→ 最终二进制动态链接系统库。 - 若
./configure报缺 PCRE / SSL,说明 2.1 的开发库没装全,回去补libpcre3-dev/libssl-dev。
2.4 验证是动态的
bash
ldd /usr/local/nginx/sbin/nginx
# 会列出一堆 .so,例如 libpcre.so、libssl.so、libc.so → 说明是动态链接
动态二进制依赖目标机存在版本兼容的这些 .so,这正是它不适合随意分发的原因。
2.5 动态编译的产物能打包给别人吗
一般不能像静态那样直接发。 动态二进制在对方机器上运行时,必须能找到版本匹配 的
libpcre / libssl / libc 等 .so;对方发行版/版本不同就跑不起来。
可行的分发方式:
- 对方也用同发行版同版本 → 让对方同样
apt/dnf install nginx(或你发的是相同环境的包)。 - 跨环境分发 → 改用 1.6 节的静态编译,或把 nginx 连同运行环境一起用 Docker 镜像 分发
(FROM基础镜像里带好库,最稳)。
附录 A:常用命令速查
下面用
/usr/local/nginx作示例路径;若你按第一部分把--prefix设到了其他目录,请把路径换成你的实际安装目录(或分发后用-p指定的目录)。
bash
# 启动
sudo /usr/local/nginx/sbin/nginx
# 停止(快速)
sudo /usr/local/nginx/sbin/nginx -s stop
# 优雅停止
sudo /usr/local/nginx/sbin/nginx -s quit
# 改配置后热重载
sudo /usr/local/nginx/sbin/nginx -s reload
# 验证静态 / 动态
ldd /usr/local/nginx/sbin/nginx
附录 B:示例 nginx.conf(HTTP 反代,IP 字面量)
nginx
worker_processes 1;
events {
worker_connections 1024;
# use poll; # Windows 版才需要;Linux 原生用 epoll,无需此行
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 8001;
server_name _;
location / {
proxy_pass http://127.0.0.1:8000;
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;
}
}
server {
listen 8081;
server_name _;
location / {
proxy_pass http://127.0.0.1:8082;
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;
}
}
}
注意:
listen侧可用0.0.0.0(绑定所有网卡),但proxy_pass/ upstream的目标必须是
127.0.0.1这类具体可达地址,不能写0.0.0.0。静态编译分发时尤其要坚持写 IP 字面量,规避 glibc 静态的 DNS 限制。