本文档覆盖两种编译方式,每一部分都从下载讲到安装:
- 第一部分:静态编译 —— 产出单一静态二进制,不依赖目标机任何库,可打包发给别人直接使用。
- 第二部分:动态编译 —— 链接系统共享库,体积小、编起来快,但一般只在当前机器/同环境使用。
总览:静态 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 源码目录的同级下载并解压:
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”),必须先清掉,否则新配置不生效:
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 的各种麻烦:
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:
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 2
openssl 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 会自动重编,很快):
cd 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 编译并安装
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 验证是静态的
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 已经把成品装到了一个独立目录(与源码分开、便于打包),
直接打包这个目录即可,干净利落:
# 回到安装目录的父目录(即源码同级) 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:对方解压并运行
# 解压到任意目录,例如 /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 覆盖前缀即可:
/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),不要写主机名。
对方机器自检(可选但建议)
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 直接编
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 容器里编(最推荐,宿主零污染)
# 宿主机执行:把当前目录(含 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 源码):
# 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 做法一:包管理器安装(最推荐)
绝大多数情况下,动态编译 = 直接用系统包。无需下载、无需编译、自动注册服务、自动升级:
# 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 装好的系统开发库):
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 验证是动态的
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指定的目录)。
# 启动 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 字面量)
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 限制。
到此这篇关于nginx 编译指南之静态编译 + 动态编译详解的文章就介绍到这了,更多相关nginx静态编译、动态编译内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论