ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

离线环境Nginx部署全攻略:从源码编译到容器镜像

2026/10/3 20:55:38 拓冰建站 浏览量
离线环境Nginx部署全攻略:从源码编译到容器镜像 作为一个常年和服务器打交道的人我太清楚生产环境没网是什么滋味了。尤其是内网隔离的机房、银行证券类项目、或者某些政务云环境装个软件最头疼的不是东西本身多复杂而是根本拿不到安装包。Nginx 作为高频组件离线部署几乎是每个运维和开发都会遇到的必修课。这篇文章我就从实操角度把离线安装 Nginx 这件事完整拆一遍——从准备依赖、下载包、编译安装、到踩坑排错、再到后续的 SSL 证书配置和多站点部署一次性讲透。先说个总体判断离线安装 Nginx 本质上就两条路一是拿源码包到目标机器上编译二是把联网机器上装好的二进制或 RPM/DEB 包拷贝过去。后者省事但受限于 glibc 版本和系统发行版前者更通用但依赖一个个补齐。我个人的建议是能走容器镜像就走容器镜像不能走容器就优先 RPM/DEB 包最后再考虑源码编译——但这三条路的细节和坑完全不一样下面分开讲。1. 为什么脱离外网环境装 Nginx 反而容易出问题离线环境下装软件大家第一反应是把安装包拷进去就行实际操作却发现Nginx 虽然本身是一个可执行文件但它依赖一堆动态链接库和用户组、目录结构、甚至编译工具链。很多时候报错根本不是 Nginx 的问题而是 base 环境缺东西。一个典型的例子你在 CentOS 7.9 上想用yum localinstall装 Nginx 的 RPM 包结果提示缺少libpcre.so.1。这个东西在联网环境一条yum install pcre就解决了但断网环境下你得自己去找匹配版本的 pcre RPM 包还得连带处理它的依赖。如果版本不对比如装了 pcre2 而不是 pcreNginx 大概率会直接报libpcre.so.1: cannot open shared object file。离线安装的难点从来不是 Nginx 本身而是依赖链的完整性和系统环境的一致性。所以整个部署流程里第一步不是急着下载 Nginx而是先搞清楚目标机器的操作系统版本、架构、glibc 版本、以及已有的基础库。这里我建议你先做三项检查# 查看系统发行版不同发行版包管理器差异巨大 cat /etc/os-release # 查看系统架构x86_64 还是 aarch64下载包时选错架构哭都来不及 uname -m # 查看 glibc 版本源码编译时如果 glibc 太旧部分新模块可能编不过 ldd --version架构这个点尤其容易翻车。我见过不止一次有人在 x86 的机器上编译好二进制拷到 ARM 服务器上直接Exec format error。下载任何包之前先确认uname -m的输出。还有一点容易被忽略目标机器是否已经存在 nginx 用户和组。Nginx 编译安装时默认会创建nginx用户来运行 worker 进程如果你在编译参数里指定了--usernginx --groupnginx但系统里没有这个用户启动时会直接报错。离线环境没有外网查资料这些小细节一旦出问题排查起来非常耗时。2. 离线包准备的关键步骤先看依赖再想下载不管走哪条安装路径都需要先在能联网的机器上把东西准备好。这一步的核心是按依赖清单准备而不是随手找一个包就传。2.1 确认你的目标系统属于哪条依赖线Nginx 有几个硬依赖和软依赖列表如下依赖用途安装阶段缺失后果gcc / make / cmake源码编译工具链源码编译阶段直接无法 configurePCRE正则表达式支持rewrite 模块核心依赖编译时 / 运行时编译报错或启动报libpcre.so.1缺失zlibgzip 压缩模块依赖编译时 / 运行时编译报错或启动报libz.so.1缺失OpenSSLHTTPS / SSL 模块依赖编译时 / 运行时无法启用 SSL 功能GeoIP / gd / libxml2特定模块才需要按需只在启用对应模块时缺失才报错注意 PCRE 和 zlib 这两项很多时候系统自带的是基础版本比如 CentOS 自带 zlib但缺少 zlib-devel开发头文件。源码编译时 Nginx 会去找头文件找不到就报错。所以离线环境下最好把主流的依赖开发包都备齐了再动手。2.2 编译安装时下载哪些包如果你决定走源码编译路线在联网机器上下载这些# Nginx 主程序源码包选择 stable 稳定版不要选 mainline nginx-1.24.0.tar.gz # PCRE8.x 版本不要下 PCRE2Nginx 1.24 默认还不适配 PCRE2 pcre-8.45.tar.gz # zlib zlib-1.3.tar.gz # OpenSSL如果用系统自带的 libssl 且版本足够可以不单独下载 openssl-3.0.13.tar.gz把这些包统一放进一个目录比如/opt/nginx-offline-src/然后整个目录传到目标机器上。这里有个细节tar.gz 包比 zip 包在 Linux 下更省事因为解压后的文件权限保持得更好zip 解压经常需要重新 chmod。2.3 准备 RPM/DEB 包时的注意点如果你走包安装路线用联网机器上的包管理器下载离线包命令不完全一样For CentOS/RHEL 系:# 在联网机器上用 yumdownloader 或 repoquery 拉取 Nginx 及其全部依赖 yumdownloader --resolve nginx # 或者只下载不安装 yum install --downloadonly --downloaddir/opt/nginx-rpms nginxFor Debian/Ubuntu 系:# 在联网机器上 apt-get download nginx # 连带依赖一起下载 apt-get install --download-only nginx但这里有个很关键的坑--resolve或--downloadonly只能下载当前联网机器上软件源里的依赖版本。如果目标机器的操作系统版本和联网机器的版本不一致比如联网机器是 CentOS 7.6目标机器是 CentOS 7.9某些依赖可能版本对不上在内网装的时候 yum 本地源检测会卡住。尽量用同版本、同小版本的操作系统来做离线包准备这是最稳妥的。3. 源码编译安装流程拆解与常见误区源码编译是离线安装 Nginx 最通用的方案也是我推荐给大多数人的方案。因为它不受系统包管理器差异的影响只要把编译工具链和依赖库补齐任何 x86/ARM 的 Linux 都能跑起来。3.1 编译参数的正确选择我先给出一个我在生产环境常用的编译命令然后逐段解释为什么这么配# 假设所有源码包已解压到 /opt/src 目录 cd /opt/src/nginx-1.24.0 ./configure \ --prefix/usr/local/nginx \ --sbin-path/usr/local/nginx/sbin/nginx \ --conf-path/usr/local/nginx/conf/nginx.conf \ --pid-path/var/run/nginx.pid \ --lock-path/var/run/nginx.lock \ --with-http_ssl_module \ --with-http_v2_module \ --with-http_gzip_static_module \ --with-http_realip_module \ --with-http_stub_status_module \ --with-pcre/opt/src/pcre-8.45 \ --with-zlib/opt/src/zlib-1.3 \ --with-openssl/opt/src/openssl-3.0.13 \ --usernginx \ --groupnginx逐条解释--prefix和--sbin-path分开指定是为了把二进制文件单独拎出来后续如果要打包传到其他机器只拷sbin/nginx和conf/即可不用整目录搬。--with-pcre/opt/src/pcre-8.45表示让 Nginx 直接编译静态链接到指定的 PCRE 源码而不是依赖系统的动态库。这个参数在离线环境里简直是救命稻草——因为编译后拷贝到其他机器只要系统有匹配的 glibc就能直接跑不需要再带上 PCRE 和 zlib 的动态库。--with-openssl/opt/src/openssl-3.0.13同理静态链入 OpenSSL避免目标机器上 OpenSSL 版本过旧导致 TLS 1.3 不可用。--with-http_stub_status_module一定要加上它是 Nginx 监控指标的关键模块/nginx_status离线环境没有外部监控插件时页面监控就靠它输出连接数、请求数。如果目标是 ARM 机器比如鲲鹏、飞腾编译时建议额外加--with-cc-opt-O2 --with-ld-opt-Wl,-rpath,/usr/local/lib用于处理部分 ARM 交叉编译时的动态库搜索路径问题。3.2 编译过程中的典型报错与处理源码编译报错九成以上是缺少开发头文件。下面是我整理的最高频报错清单报错 1./configure: error: the HTTP rewrite module requires the PCRE library.这是最经典的一个。Nginx 的 rewrite 模块if、rewrite、location里的正则依赖 PCRE。报错不是系统没有 PCRE而是 configure 脚本找不到头文件。解决办法是我上面说的在 configure 命令里显式指定--with-pcre/opt/src/pcre-8.45而不是指望系统路径。报错 2make: *** No rule to make target build, needed by default. Stop.这个报错看起来很奇怪但实际原因是/usr/local/nginx/conf/nginx.conf在之前一次失败的编译中已经生成了残留文件干扰了 make 逻辑。处理方式很简单make clean rm -rf /usr/local/nginx ./configure --same-as-before make make install报错 3undefined reference to OSSL_HTTP_parse_url这个主要是 OpenSSL 版本与 Nginx 1.24 的兼容问题。Nginx 1.24 官方支持的 OpenSSL 最高到 3.0.x如果你下载了 OpenSSL 3.1 或 3.2部分 API 变了就会链接失败。解决办法是降到 OpenSSL 3.0.13 或直接使用系统自带的 openssl-devel。报错 4/usr/bin/ld: cannot find -lssl这个很直白——缺少 OpenSSL 开发库的符号链接。要么安装openssl-devel要么在 configure 的--with-ld-opt里显式指定库路径--with-ld-opt-L/opt/src/openssl-3.0.13 -Wl,-rpath,/opt/src/openssl-3.0.133.3 编译完之后的物尽其用源码编译的好处是你可以把编译好的整个 Nginx 目录打包直接拷到同架构的其他离线机器上使用。这个技巧在批量部署时特别省事。# 在一台机器上编译好后 cd /usr/local tar czf nginx-binary.tar.gz nginx/ # 在其他同架构、同 glibc 版本的机器上 tar xzf nginx-binary.tar.gz -C /usr/local这样其他机器连编译都不用直接就是完整可用的 Nginx。但要注意这种方式要求目标机器的 glibc 主版本一致。检查方法就是前文说的ldd --version比如编译机是 glibc 2.17目标是 glibc 2.28二进制很可能报version GLIBC_2.28 not found。4. RPM 与 DEB 包安装速度快但限制不少如果你觉得源码编译太麻烦或者目标机器上不想留编译工具链安全要求高的环境往往不允许机器上有 gcc那走包安装是更好的选择。4.1 走 RPM 的完整流程在 CentOS/RHEL 7 上安装本地 RPM 包的标准做法是# 目标机器上进入存放 RPM 包的目录 cd /opt/nginx-rpms # 使用 localinstall 或直接 rpm -ivh 安装 rpm -ivh nginx-*.rpm但 RPM 安装有个头疼的问题依赖解析不自动。如果 RPM 包还依赖pcre-devel、zlib-devel你得先把这些依赖 RPM 也放进同一目录并按顺序安装。为省事可以用一条命令解决# rpm 会尝试解析当前目录下所有 RPM 的依赖 yum localinstall *.rpm这条命令相当于让 yum 把当前目录当作一个本地软件源自动解析依赖并排列安装顺序。实测下来比rpm -ivh稳很多。4.2 走 DEB 包的流程Debian/Ubuntu 上同样有对应方案cd /opt/nginx-debs # 自动处理依赖 dpkg -i *.deb # 如果依赖缺失先补上下面这个命令 apt-get install -fapt-get install -f是 DEB 世界的修复依赖命令它会自动补装缺失的依赖。但在离线环境里它也会尝试从网络下载所以还是尽量把依赖 deb 包下载齐全。4.3 包安装的隐藏坑我遇到过最隐蔽的坑是Nginx 的官方 RPM 包默认配置里pid 文件路径是/run/nginx.pid但系统里没有/run目录或没有 nginx 用户。安装 RPM 包之后直接nginx启动报nginx: [emerg] mkdir() /var/lib/nginx/tmp/client_body failed (13: Permission denied)这个问题的根源是 RPM 包装出来的 Nginx 以nginx用户运行但它需要的临时目录/var/lib/nginx/tmp/创建时机在 post-install 脚本里如果脚本执行时权限不对比如打包时目录权限设成了 700 且属主不对就会启动失败。解决办法mkdir -p /var/lib/nginx/tmp chown -R nginx:nginx /var/lib/nginx另外一个包安装特有的问题是版本老旧。CentOS 7 自带的 nginx RPM 是 1.16 或 1.20HTTP/2 支持还在但缺少一些新特性比如ssl_early_data、http3。如果业务上需要较新的 TLS 特性还是走源码编译靠谱。5. 部署完之后的验证与基础配置检查装好 Nginx 只是第一步验证它真的能跑、配置真的生效才是离线环境里最不能省的部分。我每次装完都会按以下顺序检查一遍。5.1 启动前的环境检查先检查 nginx 用户是否存在如果编译时指定了该用户id nginx如果不存在手动创建useradd -r -s /sbin/nologin nginx再看关键目录权限ll /usr/local/nginx/ ll /var/run/nginx.pid ll /var/cache/nginx/如果/var/cache/nginx不存在启动时nginx -t虽然不报错但真正加载后会报临文件创建失败。5.2 配置语法校验在任何 Nginx 操作之前先跑语法校验这是离线环境排查问题最快的路径/usr/local/nginx/sbin/nginx -t输出示例nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful看到 syntax is ok 再启动。如果语法有错Nginx 会明确告诉你哪个文件第几行有问题比如nginx: [emerg] unknown directive ssl_certificate_key in /usr/local/nginx/conf/nginx.conf:18这个报错通常意味着你的 Nginx 编译时没带--with-http_ssl_module。国产离线系统上经常碰到这类问题因为默认发行版的 Nginx 不带 SSL 模块用 nginx -V 确认一下/usr/local/nginx/sbin/nginx -V如果没有--with-http_ssl_module就得回去重新编译。这也是我坚持源码编译的原因——参数一个都不能少。5.3 启动与进程检查启动命令/usr/local/nginx/sbin/nginx启动后检查ps -ef | grep nginx正常情况下会看到 master 进程和 nginx worker 进程root 12345 1 0 10:00 ? 00:00:00 nginx: master process /usr/local/nginx/sbin/nginx nginx 12346 12345 0 10:00 ? 00:00:00 nginx: worker process然后测试端口curl -I http://127.0.0.1/返回HTTP/1.1 200 OK就说明服务正常。如果 curl 不通下一步用ss -tlnp看端口是否监听ss -tlnp | grep 80所有检查都过了还没完——离线环境有防火墙和 SELinux 两座大山。# 如果开启 SELinux需要放行端口 setsebool -P httpd_can_network_connect 1 # 或者直接关闭安全要求不高时 setenforce 0SELinux 坑很多人到生产故障才想起它。Nginx 已经监听 80 了但 curl 报连接拒绝十有八九是 SELinux 拦截。内网环境宽容一点可以直接临时关闭setenforce 0但要永久关闭就得改/etc/selinux/config这个需要重启系统才生效别在生产环境随手改。6. 离线部署 SSL 证书时的坑从生成到替换离线环境下证书的事情比联网环境麻烦得多。委外项目或政务系统经常会遇到证书是用不联网的内部 CA 签发的或者证书从第三方平台导出的格式不认识这类问题。6.1 证书格式转换工具的准备如果你是在离线机器上需要转换证书格式比如从 JKS 或 PFX 转 PEM就得提前把 OpenSSL 装好。此时前文源码编译时静态链入的 OpenSSL 就派上用场了# 从 pfx 导出证书和私钥 openssl pkcs12 -in server.pfx -nocerts -out server.key.pem openssl pkcs12 -in server.pfx -clcerts -nokeys -out server.crt.pem # 如果私钥带密码去掉密码 openssl rsa -in server.key.pem -out server.key注意一个细节server.key的权限必须设为 600否则 Nginx 启动时会警告Permissions 0644 are too open。6.2 Nginx 配置 SSL 的离线建议SSL 配置里我最常碰到的离线问题是旧证书替换后不生效。很多人排查半天其实是忘了 reload 或者用了错误的证书路径。正确的证书替换流程将新证书文件上传并覆盖旧文件用nginx -t验证语法执行nginx -s reload让配置生效用openssl s_client -connect 127.0.0.1:443验证证书信息# 验证证书的到期时间 echo | openssl s_client -connect 127.0.0.1:443 2/dev/null | openssl x509 -noout -dates如果显示的日期还是旧证书说明 reload 没成功多半是 worker 进程没有完全退出此时需要# 强制重启而不是 reload /usr/local/nginx/sbin/nginx -s stop /usr/local/nginx/sbin/nginx还有一个特别容易踩的坑Nginx 的 reload 和证书软链。如果你用软链指向证书文件ssl_certificate /etc/nginx/certs/server.crt; ssl_certificate_key /etc/nginx/certs/server.key;且server.crt是指向/data/certs/2025/server.crt的软链那么替换逻辑要变成先把新证书写入/data/certs/2025/目录再替换软链指向。如果你直接把新内容覆盖到/etc/nginx/certs/server.crt这个软链目标上Nginx 的 worker 可能还在读旧 inode因为 reload 只会重新读取 master 进程打开的 fd。这个细节坑过很多人我写代码总结就是一句话证书文件只做完整替换不要原地修改。7. 容器环境下的离线安装能走镜像别走编译如果你的目标机器上已经装了 Docker或 containerd离线安装 Nginx 就又简单了一个量级——直接把镜像导入进去就行。这是目前我最推荐的离线方式因为它把 Nginx 和它的所有依赖库都封装在一个层里宿主机的 glibc、PCRE、OpenSSL 根本不参与。7.1 镜像的导出与导入在联网机器上操作# 拉取 Nginx 镜像挑一个符合需求的小版本比如 1.24.0-alpine docker pull nginx:1.24.0-alpine # 保存为 tar 文件 docker save -o nginx-1.24.0-alpine.tar nginx:1.24.0-alpine把 tar 文件传到目标机器后# 加载镜像 docker load -i nginx-1.24.0-alpine.tar # 运行容器 docker run -d \ --name nginx \ -p 80:80 -p 443:443 \ -v /data/nginx/conf:/etc/nginx/conf.d:ro \ -v /data/nginx/html:/usr/share/nginx/html:ro \ nginx:1.24.0-alpine7.2 容器方案的三个细节第一个细节容器镜像版本选择。官方nginx:latest是 mainline 版相当于开发版生产环境老老实实锁具体的 stable 版本号我常用1.24-alpine或1.26-alpine。alpine 后缀表示使用 Alpine Linux 基础镜像体积小约 25MB更适合离线传输。第二个细节docker save 出来的 tar 可能 100MB。如果目标机器的中转盘空间紧张可以先在联网机器上用docker image ls -a看看实际大小或者用--platform参数只拉对应架构的镜像。ARM 机器拉 amd64 镜像导入后在运行时会报exec format error所以拉取时必须带--platform linux/arm64。第三个细节也是最大的坑离线环境里容器内的时区和 DNS 配置。Nginx 容器默认没有/etc/resolv.conf之外的外部 DNS如果你的业务需要 Nginx 代理解析外部域名比如反代一个公网服务务必在运行参数里加上--dns 8.8.8.8 --dns 114.114.114.114否则容器内解析失败反代所有上游域名都 502。离线内网环境下一般用内网 DNS 地址即可。7.3 容器方式与编译方式的选择建议就我遇到的生产场景来看如果是批量部署、机器数量多、配置需要标准化推荐容器镜像方案一份镜像到处导入配置通过挂载目录统一管理。如果机器就是不能装 Docker很多存量服务器的安全策略不允许或者项目要求 Nginx 深度定制模块比如第三方 WAF 模块还是乖乖源码编译。如果只是临时起个 Nginx 来反向代理一下内部某个服务建议走 RPM/DEB 包最快。8. 我在离线环境实际操作中的两个体会和一条铁律离线安装 Nginx 做了这么多次之后我总结出了两个切身体会和一条铁律写出来供大家参考。第一个体会是提前把 nginx 用到的高频模块都编进去。离线环境最大的痛点是装好了之后发现少模块。比如你编译时没带--with-http_realip_module后面做负载均衡要拿真实客户端 IP 时就傻眼了——源码编译还简单重新 compile 一次就完但如果是 RPM 装的那基本只能换机重装。所以离线环境我宁可一次多编几个模块也不愿后面补。第二个体会是所有验证手段都要在离线环境里自包含。联网环境有问题可以上网搜、可以 yum install 一个工具来查离线环境里工具就那么几个curl、ss、openssl、strace是最核心的排查四件套。我每次去客户现场都会额外带一个静态编译好的strace和tcpdump二进制专门用来排查 Nginx 连接不上的问题。如果离线机器上没有这两个工具很多网络问题就只能靠猜了。一条铁律还是留给我踩过的坑的教训也顺带给各位提个醒备份 offline install 包时务必用sha256sum校验一遍再传到生产机器上。我记得有一年远程交付一个内网项目压缩包传了三次都失败到现场一比对明明是 tar.gz包却出现了传输中的长度错误。后来每次都先算 sha256再让现场执行sha256sum -c校验再也没出过这种低级事故。离线部署 Nginx方法不复杂但每一环都不能省。依赖理清了、架构选对了、模块编全了、配置校验一遍、进程确认无误、证书替换用完整覆盖而非原地修改——整套流程走下来内网环境跑个三五年基本不会出什么幺蛾子。如果你正在准备这类交付项目希望这篇文章能让你少走几段弯路。