简介:面向无外网或网络受限环境下的Linux服务器运维人员,这份资源提供了一套完整的nginx离线部署方案,重点解决内网数据中心无法在线拉取依赖的安装难题。压缩包共4个文件,以gz压缩包为主体,分别承载nginx源码、gcc编译环境及nginx运行所需的rpm依赖集合,另附一份html格式的安装说明文档,整体约62.15MB,便于一次性拷贝至目标服务器使用。资源将编译工具链与Web服务器依赖打包整合,读者可据此在断网条件下完成gcc环境准备、nginx安装与配置启动,避免逐一下载依赖造成的版本冲突与时间损耗。目前已有1683人学习下载,适合需要在内网快速搭建静态文件服务、反向代理或负载均衡环境的中初级运维与开发人员参考实践。
1. 内网机器装 nginx,为什么我宁可背一包 rpm 进去
上周又碰到一台生产环境的 CentOS 7 机器,网卡是通的,但只放行了内网端口,yum install nginx直接卡在Could not resolve host: mirrorlist.centos.org。这种场景在金融、制造、能源的隔离区里太常见了:机器能 SSH,能传文件,就是不能出网。你要装个 nginx 做反向代理或者静态资源服务,结果第一步./configure就报C compiler cc is not found,因为最小化安装的系统连 gcc 都没带。
这份资源就是为这种局面准备的:一个 nginx 离线安装包,里面把 gcc 编译工具链和 nginx 运行所需的 rpm 依赖一起打进去了。它解决的不是"怎么学 nginx",而是"在一台完全断网的 Linux 上,怎么把 nginx 从零装起来并且能跑"。适合谁?做内网部署的运维、交付工程师、以及被派去客户机房装中间件的后端。如果你平时机器能联网,yum一把梭就行,这份包对你价值不大;但只要你有一次要在无外网环境装 nginx,它就是能救命的后悔药。
我见过太多人栽在"以为只差一个 nginx rpm"上。实际上 nginx 依赖 pcre、zlib、openssl,编译安装还要 gcc、make、glibc-headers,这些依赖之间还有版本咬合关系。离线包的价值不在于文件多,而在于它把这条依赖链一次性锁死了。
2. 先搞清楚包里有什么:依赖链与安装路径的选择
2.1 为什么是 rpm 集合而不是单个二进制
nginx 的安装方式大致三种:源码编译、官方预编译包、系统包管理器。离线环境下,源码编译最灵活但最吃依赖,你得先有 gcc 和一堆-devel包;官方预编译包体积小,但版本和系统 ABI 要对得上;rpm 集合则是把"系统包管理器能认的依赖"全部备齐,用rpm -ivh或本地 yum 源的方式灌进去。
这份资源走的是第三条路,核心逻辑是:先把编译/运行依赖用 rpm 补齐,再装 nginx 本体。为什么不用源码编译?因为隔离区机器往往连make都没有,你传一个 tar.gz 进去照样卡在编译阶段。rpm 的好处是安装即生效,不需要现场编译,失败时rpm -qa能立刻看出哪个包没进去。
常见做法是建一个本地 yum 仓库,让yum自己去解依赖,而不是一个个rpm -ivh硬装——后者遇到依赖顺序问题会反复报Failed dependencies,非常折磨人。
2.2 依赖清单与版本咬合
一个典型的 nginx 离线依赖集合,按用途可以分成四组。下面这张表是我按实际拆包经验整理的,具体包名以你拿到的资源为准,但分组逻辑是通用的:
| 分组 | 典型包 | 作用 | 缺失后的现象 |
|---|---|---|---|
| 编译工具链 | gcc、gcc-c++、make、glibc-devel | 源码编译或部分模块构建 | C compiler cc is not found |
| 正则库 | pcre、pcre-devel | rewrite、location 正则匹配 | 编译报 pcre 找不到,或启动后 rewrite 失效 |
| 压缩库 | zlib、zlib-devel | gzip 静态压缩 | the HTTP gzip module requires the zlib library |
| SSL 库 | openssl、openssl-devel | HTTPS、TLS | SSL modules require the OpenSSL library |
这里有个血泪经验:pcre和pcre-devel是两个包,前者是运行库,后者是头文件。只装前者,nginx 能跑但编译不过;只装后者,编译过了运行可能缺 so。离线包里如果只给了一个,你得自己判断当前是编译场景还是运行场景。
版本咬合是另一个坑。CentOS 7 自带 openssl 1.0.2,如果你拿到的 nginx 包是针对 openssl 1.1 编译的,装上去启动就报libssl.so.1.1: cannot open shared object file。所以拿到资源第一件事不是急着装,而是先核对目标系统的发行版和 glibc 版本。
# 先摸清目标机器的底细,再决定装哪套包 cat /etc/redhat-release # 确认是 CentOS 7 还是 8,决定 rpm 的 el7/el8 后缀 ldd --version | head -1 # 看 glibc 版本,低于包要求会直接段错误 uname -m # x86_64 还是 aarch64,架构不对 rpm 直接拒装 rpm -qa | grep -E 'pcre|zlib|openssl' # 看系统已有哪些库,避免重复装冲突这段命令的逻辑是"先侦察后动手"。/etc/redhat-release决定你选el7还是el8的包;ldd --version看 glibc,因为 rpm 包的依赖里常带glibc >= 2.17这类硬约束;uname -m防止把 x86 包传到 ARM 机器上;最后一条是查已有库,避免你装的 openssl 和系统自带的打架。参数上没什么可调的,关键是养成"装之前先跑一遍"的习惯。
2.3 两种落地路径:本地 yum 源 vs 直接 rpm
拿到 rpm 集合后,有两条路。第一条是直接rpm -ivh *.rpm,简单粗暴,但依赖顺序错了会连环报错,而且--nodeps强装是给自己埋雷。第二条是搭本地 yum 源,让 yum 解依赖,稳得多。
我一般推荐第二条,尤其是包数量超过十个的时候。搭源只需要createrepo,如果目标机连这个都没有,可以在有网的机器上先createrepo生成好repodata目录,整个文件夹拷过去即可。
# 路径一:本地 yum 源(推荐,依赖自动解) mkdir -p /opt/localrepo cp /path/to/rpms/*.rpm /opt/localrepo/ createrepo /opt/localrepo # 生成 repodata 元数据,没网机器可提前在有网机器做 cat > /etc/yum.repos.d/local.repo <<'EOF' [local] name=Local Offline Repo baseurl=file:///opt/localrepo enabled=1 gpgcheck=0 EOF yum clean all && yum makecache yum install -y nginx # 让 yum 自己按依赖顺序装# 路径二:直接 rpm 硬装(包少时用,注意顺序) cd /path/to/rpms rpm -ivh pcre-*.rpm zlib-*.rpm openssl-*.rpm # 先装基础库 rpm -ivh gcc-*.rpm make-*.rpm glibc-devel-*.rpm # 再装编译链 rpm -ivh nginx-*.rpm # 最后装本体路径一的关键在baseurl=file://,三个斜杠不能少,少一个 yum 就找不到源;gpgcheck=0是因为离线包的签名你没法验证,生产环境如果在意完整性,应该在内网自建签名而不是关校验。路径二的顺序不是随便排的:基础库在前,编译链在中,nginx 本体在后,因为 rpm 安装时会检查依赖是否已满足,顺序反了就得反复--nodeps。rpm -ivh的-i是安装、-v显示过程、-h打进度条,这三个字母组合是肌肉记忆,但真正决定成败的是包顺序而不是参数。
3. 装完不等于能用:配置、启动与验证的完整闭环
3.1 安装后的目录结构与关键路径
rpm 方式装的 nginx,路径和源码编译不一样,很多人第一次找配置文件找半天。典型布局是:二进制在/usr/sbin/nginx,主配置在/etc/nginx/nginx.conf,站点配置在/etc/nginx/conf.d/,日志在/var/log/nginx/,默认站点根目录在/usr/share/nginx/html。源码编译默认是/usr/local/nginx/,两者别搞混。
先验证二进制和版本,再看配置语法,最后才启动。这个顺序能帮你把问题挡在启动之前。
/usr/sbin/nginx -v # 看版本,确认装的是预期的那份 /usr/sbin/nginx -V # 大写 V 看编译参数,重点看 --with-http_ssl_module 在不在 /usr/sbin/nginx -t # 测配置语法,改完配置必跑-t这条是保命命令。我见过有人改完nginx.conf直接systemctl restart,结果配置里少个分号,nginx 起不来,线上服务直接断。-t会在不重启的前提下把配置解析一遍,报错会精确到行号。-V的大写很关键,小写-v只给版本号,大写才吐编译参数——你要确认 HTTPS 支持、gzip 模块这些是否编进去了,全靠它。
3.2 最小可用配置与启动方式
装完默认配置通常能跑,但生产上你至少要改监听端口、站点根目录和日志格式。下面是一个能直接抄的最小反向代理配置,放在/etc/nginx/conf.d/app.conf:
server { listen 8080; # 避开 80,防止和已有服务冲突 server_name _; # 下划线表示匹配任意 Host access_log /var/log/nginx/app_access.log; error_log /var/log/nginx/app_error.log warn; location / { proxy_pass http://127.0.0.1:9000; # 后端真实服务地址 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_connect_timeout 5s; # 后端连不上时快速失败,别让客户端干等 proxy_read_timeout 30s; } }这段配置的逻辑:listen 8080先避开 80 端口,因为隔离区机器上 80 很可能被别的老服务占着;proxy_set_header那三行是把真实客户端信息透传给后端,不设的话后端日志里全是127.0.0.1,排查问题时等于黑匣子;两个 timeout 是防止后端挂掉时 nginx 一直挂着连接,proxy_connect_timeout 5s让失败快速暴露。参数怎么调?后端是内网低延迟服务,5s 连接超时足够;如果是跨机房,可以放到 10s,但别超过 30s,否则故障时客户端体验极差。
启动用 systemd 最稳,rpm 包一般自带 unit 文件:
systemctl start nginx systemctl enable nginx # 开机自启,隔离区机器重启后不用人工拉 systemctl status nginx # 看 active (running) 才算成 ss -lntp | grep 8080 # 确认端口真的在监听,而不是进程活着但没绑上 curl -I http://127.0.0.1:8080 # 本机自测,看返回码ss -lntp这条容易被忽略。systemctl status显示 running 不代表端口绑成功了,有可能配置里 listen 写错或者被 SELinux 拦了。ss直接看内核的监听表,-l是 listening、-n是数字端口、-t是 TCP、-p显示进程,一眼就能确认 nginx 到底有没有在 8080 上等连接。curl -I只取响应头,快且不拉全量内容,适合做连通性冒烟测试。
3.3 用 java 侧做一次端到端验证
关键词里有 java,实际交付场景里 nginx 前面挂的经常是 Java 后端。装完 nginx 别只在本机 curl,最好从应用侧验证一次转发链路是否通。假设后端是个 Spring Boot 服务跑在 9000,可以用一段极简的 Java 代码打一次请求,确认经过 nginx 后X-Forwarded-For头有没有正确带上。
import java.net.HttpURLConnection; import java.net.URL; public class ProxyCheck { public static void main(String[] args) throws Exception { // 请求打到 nginx 的 8080,而不是后端 9000,验证的是代理链路 URL url = new URL("http://127.0.0.1:8080/health"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(3000); // 连接超时,和 nginx 的 proxy_connect_timeout 呼应 conn.setReadTimeout(5000); // 读超时,略大于后端处理时间 int code = conn.getResponseCode(); System.out.println("status=" + code); // 后端若把请求头回显,这里能看到 X-Forwarded-For 是否被 nginx 注入 System.out.println("xff=" + conn.getHeaderField("X-Forwarded-For")); conn.disconnect(); } }这段代码的价值在于"从消费方视角验证"。setConnectTimeout(3000)比 nginx 的 5s 略短,是为了在 nginx 还没放弃时 Java 侧先报错,方便定位是代理层还是后端层的问题;getHeaderField("X-Forwarded-For")读的是响应头,前提是后端把这个请求头回显出来,如果没有回显,就改成在后端日志里查。参数上,超时值要和 nginx 的 timeout 形成梯度,否则两边同时超时,你根本分不清是谁先挂的。
4. 离线安装的避坑清单:五个真实翻车现场
4.1 现象:rpm -ivh报一堆 Failed dependencies,越装越乱
原因几乎总是依赖顺序错或者缺包。rpm 不像 yum 会自己排序,它要求你装的包在装的那一刻依赖已满足。有人图省事加--nodeps强装,结果 nginx 起来了但一访问就 500,因为 pcre 的 so 根本没链上。
解决:优先走本地 yum 源那条路,让 yum 解依赖。实在要硬装,先rpm -qpR nginx-*.rpm把 nginx 的依赖列出来,逐个确认系统里有没有,缺的补进去再装。已经用--nodeps装坏的,rpm -e卸掉重来,别在坏地基上继续盖。
4.2 现象:nginx 启动报libssl.so.1.1: cannot open shared object file
原因是 nginx 二进制编译时链接的 openssl 版本和系统里的不一致。CentOS 7 默认 openssl 1.0.2,而你拿到的包可能是针对 1.1 编的。这不是配置问题,是 ABI 不匹配。
解决:ldd /usr/sbin/nginx | grep ssl看它到底找哪个 so。要么换一份匹配系统 openssl 的 nginx 包,要么把对应版本的 openssl 库一起离线装进去。别想着软链接糊弄,ln -s一个版本号对不上的 so,大概率段错误。
4.3 现象:systemctl start nginx成功,但curl连接被拒
原因通常是端口没绑上,常见于三种情况:配置里 listen 的端口被占用、SELinux 拦了非标准端口、或者 nginx 实际读的不是你改的那个配置文件。systemctl status显示 running 只说明主进程活着。
解决:ss -lntp | grep nginx看真实监听端口;getenforce看 SELinux 状态,如果是 Enforcing 且你用了 8080 这类非默认端口,需要semanage port -a -t http_port_t -p tcp 8080;最后nginx -T(大写 T)把最终生效的完整配置打出来,确认你改的文件真的被 include 了。
4.4 现象:配置改完nginx -t通过,重启后仍旧是旧行为
原因是改了conf.d/下的文件但主配置没 include,或者改的是/usr/local/nginx/conf/而实际运行的是/etc/nginx/。源码编译和 rpm 安装的路径不同,这是高频混淆点。
解决:nginx -T输出里搜你的 server_name 或 listen 端口,看它到底加载了哪些文件。养成改完配置先-t再-T确认生效范围的习惯,比重启后抓瞎强。
4.5 现象:离线装完 gcc,编译某个模块仍报头文件找不到
原因是只装了gcc没装glibc-devel或对应的-devel包。gcc 是编译器前端,头文件在-devel包里,两者是分开的。离线包如果只打了 gcc,编译任何带系统调用的代码都会缺stdio.h之类。
解决:rpm -qa | grep devel查已装的开发包,缺什么补什么。判断方法很直接:报错里出现xxx.h: No such file,就去装提供这个头文件的-devel包。这也是为什么依赖清单里编译工具链那一组要整组备齐,而不是只给一个 gcc。
5. 把离线包变成可复用资产:校验、归档与一次装对的习惯
装完一台机器不算完,真正省事的是把这套流程沉淀成可复用的东西。我现在的做法是:每拿到一份离线包,先做完整性校验,再按"系统版本 + 架构"归档,最后写一个幂等的安装脚本。这样下次换一台同型号机器,一条命令跑完,不用再回忆上次踩了哪个坑。
校验这一步很多人跳过,但离线包在拷贝、U 盘传递过程中损坏是常事。rpm 自带校验能力:
# 校验每个 rpm 包的完整性,损坏的包会在输出里标出来 for f in /opt/localrepo/*.rpm; do rpm -K "$f" || echo "BROKEN: $f" done # 装完后统一核对关键包是否都在 rpm -qa | grep -E '^(nginx|gcc|make|pcre|zlib|openssl)' | sortrpm -K做的是签名和摘要校验,输出digests OK才算过;循环里用||把坏包单独打出来,避免一屏输出里漏看。第二条rpm -qa是装后对账,把关键包列出来排序,和你的清单逐行比对,少一个都能立刻发现。这两条命令我一般写进安装脚本的开头和结尾,形成"装前校验、装后对账"的闭环。
归档命名我固定用nginx-offline-<发行版>-<架构>-<日期>这种格式,比如nginx-offline-el7-x86_64-202406,目录里再放一个MANIFEST.txt记录每个包的版本和用途。别小看这个习惯,半年后你再翻出来,没有 manifest 的包等于一堆无名 rpm,根本不敢往生产上装。
最后是一个幂等脚本的骨架,核心是"已装则跳过、未装则装、装完必验":
#!/bin/bash set -e # 任何一步失败立即退出,避免半装状态继续往下跑 REPO=/opt/localrepo rpm -q nginx >/dev/null 2>&1 && { echo "nginx already installed"; exit 0; } # 本地源方式安装,yum 负责解依赖 yum install -y --disablerepo='*' --enablerepo=local nginx # 装完立刻验证三件事:语法、端口、进程 nginx -t systemctl enable --now nginx ss -lntp | grep -q nginx && echo "OK: nginx listening" || { echo "FAIL: not listening"; exit 1; }set -e是这类脚本的底线,没有它,中间某步失败脚本还会继续跑,最后给你一个"看起来成功"的假象。--disablerepo='*' --enablerepo=local是强制只用本地源,防止脚本在能联网的机器上偷偷去拉外网包,导致行为和离线环境不一致。最后那条ss | grep -q把"进程活着"升级成"端口真的在听",这才是可交付的验证标准。
从那以后我每次交付离线环境,都强制走一遍"校验 → 装 → 对账 → 端口验证"这四步,哪怕时间再紧也不省。因为省下的那五分钟,往往会在客户现场用两小时来还。希望这套流程帮到你,下次再面对一台断网机器时,心里有底。
本文还有配套的精品资源,点击获取