ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Linux 下用 yum/apt 在线安装 Nginx 完整指南与避坑

Linux 下用 yum/apt 在线安装 Nginx 完整指南与避坑

装个 Nginx 而已,我见过太多人卡在第一步:一台刚交付的机器,系统装完,SSH 进去,nginx -v报 command not found,然后开始搜"nginx 安装教程",翻到一篇让下载.tar.gz编译的,跟着./configure敲了半小时,最后卡在pcre.h not found或者openssl version mismatch上,一整天没了。其实绝大多数场景根本用不着编译,用系统自带的软件包管理器在线安装就够了——CentOS 系一条yum install nginx,Ubuntu 系一条apt install nginx,两分钟出结果,还自带 systemd 单元、日志轮转、默认配置文件,卸载也干净。

这篇写的就是这条路:yum/apt 在线安装 Nginx 的完整过程,从仓库来源判断、版本取舍,到安装后的验证、端口放行、最小可用配置,再到我这些年踩过的坑。适合刚接手服务器的新手,也适合那些装了几十次但每次换发行版还得重新查一遍的老手——后半部分的仓库优先级、版本锁定、SELinux 权限这几块,估计能帮你省掉一次线上事故。全文以实际能复现为准,命令都是可以直接粘贴跑的。

1. 在线安装之前,先想清楚你要哪个版本的 Nginx

很多人跳过这一步直接开装,装完发现版本是 1.18 甚至 1.16,用不了stream模块的新特性,或者某个proxy_cache参数不认,回头再折腾升级,成本比一开始选对高得多。在线安装的核心分歧不在命令,在"包从哪个仓库来"。

1.1 三种安装方式的取舍逻辑

先把选项摆开,说清楚为什么日常场景我更推荐包管理器。

方式典型做法优点代价适用场景
发行版仓库yum install nginx/apt install nginx一条命令、依赖自动处理、systemd 集成、卸载干净版本偏旧,模块固定绝大多数业务前置、内网服务、测试环境
官方仓库添加 nginx.org 的 repo 后安装版本新、可选 stable/mainline、编译选项官方调好需手动加源和签名 key,存在与系统包冲突风险需要较新特性、需要官方编译参数一致
源码编译./configure && make完全可控,可裁剪模块、指定路径依赖手工解决、升级要重来、无包管理记录需要第三方模块、定制编译参数

选包管理器的核心理由很实在:运维的可维护性。一年后你或者接手的人想知道这台机器装了什么、版本多少、配置在哪、怎么升,rpm -qi nginx或dpkg -l | grep nginx一行就出来了。源码编译装的东西,全靠当时那个人留下的笔记,人一走就成了黑盒。

那什么时候必须走官方仓库?我的判断线是:发行版自带版本落后超过两个大版本,且你确实要用到新版本才有的指令。比如 Ubuntu 22.04 自带的是 1.18.x,而你配置里要用http2 on;这种 1.25.1 之后才支持的写法,那就得加官方源。反之,只是做反向代理、静态资源、常规 HTTPS,1.18 完全够用,没必要为了版本号折腾。

提示:不要为了"版本新"而升级生产环境的 Nginx。包管理器升级是原地替换二进制,配置文件不兼容时的报错往往在重启那一刻才暴露。

1.2 在线安装真正解决的三个问题

第一是依赖地狱。Nginx 依赖 PCRE(正则)、zlib(gzip)、OpenSSL(HTTPS),源码编译最烦的就是这几个库的版本匹配,尤其 OpenSSL 1.1 和 3.x 混装的环境。包管理器里这些是声明式依赖,装 Nginx 的时候自动带上,版本一定是这套系统验证过的组合。

第二是服务集成。在线安装会自动创建nginx用户(Ubuntu 系是www-data)、生成/usr/lib/systemd/system/nginx.service、配置/etc/logrotate.d/nginx日志切割。这些看起来是小事,但日志不切割的机器,半年后/var/log/nginx/access.log涨到几个 G,磁盘告警的时候你就知道痛了。

第三是升级路径。yum update nginx或apt upgrade就能拿到安全补丁,配合版本锁定还能精确控制。源码编译的升级等于重装一遍,还得祈祷新的编译参数和旧的配置文件对得上。

1.3 装机前的三项体检

动手之前花三十秒确认三件事,能避开后面 80% 的意外。

# 1. 确认发行版和版本号 cat /etc/os-release # 2. 确认 80/443 端口没被占用 ss -lntp | grep -E ':(80|443)\s' # 3. 确认是否已经装过 nginx(哪怕是别的途径装的) which nginx; nginx -v 2>&1; rpm -q nginx 2>/dev/null; dpkg -l | grep -w nginx

端口占用这条最容易忽略。我遇到过一次,机器上预装了某个面板自带的 Web 服务占着 80,yum install nginx装完systemctl start nginx直接失败,报Address already in use,日志里一行bind() to 0.0.0.0:80 failed。新手看到这个第一反应是重装 Nginx,其实跟 Nginx 一点关系没有。

体检里第三条也有价值:如果which nginx有输出但rpm -q nginx查不到,说明是源码装的。这时候再走包管理器安装,两套文件会打架——包管理器把二进制放到/usr/sbin/nginx,而你 PATH 里优先命中的可能是/usr/local/nginx/sbin/nginx,你以为重启生效了,其实跑的还是老进程。

2. 两套包管理体系的差异,决定了命令怎么写

CentOS 和 Ubuntu 的安装命令长得像,底层模型完全不同。搞清楚这个,遇到报错才不会瞎猜。

2.1 yum/dnf 与 apt 的仓库模型对比

维度CentOS / RHEL 系Ubuntu / Debian 系
包格式.rpm.deb
包管理器yum(CentOS 7)/ dnf(8 及以上)apt / apt-get
仓库定义位置/etc/yum.repos.d/*.repo/etc/apt/sources.list与/etc/apt/sources.list.d/*.list
元数据缓存/var/cache/dnf/,默认过期时间较短/var/lib/apt/lists/,需手动apt update
签名校验gpgcheck=1+gpgkey=signed-by=指向 keyring 文件
查询已装包rpm -q nginx、dnf list installed nginxdpkg -l nginx、apt list --installed
文件归属查询rpm -ql nginxdpkg -L nginx
仓库优先级priority插件 /--enablerepo/etc/apt/preferences.d/里的 Pin

两套体系最本质的区别是元数据的刷新时机。yum/dnf 每次执行命令前会检查缓存是否过期,过期就自动拉取;apt 不是,apt install用的是上次apt update时的索引,如果源地址改过但没更新,会直接报Unable to locate package。这是从 CentOS 转 Ubuntu 的人最常踩的第一坑。

2.2 版本来源的三层结构

不管哪套系统,Nginx 的包都可能有三个来源,装之前必须知道自己拿到的是哪一层。

第一层:系统基础仓库。CentOS 7 的基础仓库里没有 nginx,得开 EPEL;CentOS 8 及之后的 Stream 版本,nginx 在 AppStream 仓库里,开箱即用。Ubuntu 的universe组件里有 nginx,但默认镜像的精简安装可能没启用 universe,需要先add-apt-repository universe或确认 sources 里有这一项。

第二层:第三方扩展仓库。CentOS 7 时代 EPEL 是标配,yum install epel-release之后才有 nginx。EPEL 里的版本通常是"够用但不新",好处是经过大量验证。

第三层:软件官方仓库。提供 stable 和 mainline 两条线。stable 是偶数版本号(1.24.x、1.26.x),只修 bug 不加功能;mainline 是奇数版本号(1.25.x、1.27.x),新功能先进这里。生产环境我一般选 stable,除非需要某个只有 mainline 才有的模块。

注意:同一台机器上不要混用多层来源。系统仓库装过 nginx,再加官方仓库装一次,会出现两个包都认为自己是"nginx"的尴尬局面,dnf 会报冲突,或者更糟——静默替换掉二进制但配置文件路径没变。

2.3 网络不通时的仓库排查顺序

国内环境拉取海外源经常超时,报错形式五花八门,按这个顺序查基本都能定位。

# 第一步:DNS 能不能解析 getent hosts nginx.org # 或 dig +short nginx.org # 第二步:HTTP 层能不能通(注意有些源只开 https) curl -I --connect-timeout 5 https://nginx.org/packages/ # 第三步:仓库配置里的 baseurl 是否拼错 dnf repolist -v 2>/dev/null | head -40 grep -r "baseurl\|deb " /etc/yum.repos.d/ /etc/apt/sources.list.d/ 2>/dev/null # 第四步:清缓存重来 dnf clean all && dnf makecache apt clean && apt update

如果确认是网络慢,可以把源地址换成国内公共镜像站提供的同路径镜像。判断标准很简单:镜像站上必须能访问到与原站完全一致的目录结构和签名 key,否则不要换——只改 baseurl 不换 key,gpgcheck一定失败。

3. CentOS 系:yum/dnf 安装的完整流程

分三种情况写,对照自己的系统版本选一条走。

3.1 CentOS 7:EPEL 是绕不开的前置

CentOS 7 基础仓库确实没有 nginx,必须开 EPEL。标准动作是两步:

# 安装 EPEL 仓库配置包 yum install -y epel-release # 装 nginx yum install -y nginx

-y的意思是所有确认自动回答 yes,批量脚本里必带,手工操作时建议第一遍不加,看清楚它准备装哪些包、占多少空间,心里有数再确认。我第一次装的时候没看,结果发现它顺带装了一堆gd、GeoIP之类的东西,磁盘小的机器上值得留意。

装完验证:

rpm -qi nginx | head -20 nginx -v systemctl enable --now nginx systemctl status nginx --no-pager

systemctl enable --now这一条同时做了开机自启和立即启动,比先enable再start少敲一次。CentOS 7 上如果status显示active (running)但curl不通,八成是 firewalld 拦着,后面第 5 章细说。

值得单独提一句 CentOS 7 的现状:这个版本已经停止维护,官方仓库地址迁移到了归档源。新机器上直接用yum install epel-release大概率报Could not resolve host或 404。真要在这种机器上装,得先把/etc/yum.repos.d/里的 baseurl 全部改成归档地址。这是个临时方案,长期看还是建议迁移系统版本,别在生产上硬撑。

3.2 CentOS 8 / Stream:AppStream 直装

CentOS 8 及之后的版本,nginx 在 AppStream 仓库里,不需要 EPEL,一条命令:

dnf install -y nginx # CentOS 8 早期也可以继续用 yum,它是 dnf 的软链

想确认包来自哪个仓库,装之前先查:

dnf info nginx # 输出里 Repository 一行会写 AppStream dnf repoquery --location nginx

AppStream 的模块化机制有个坑:某些版本里 nginx 是以 module 形式提供的,多版本共存时需要用dnf module list nginx看有哪些流可用。如果你需要特定小版本,可能要dnf module enable nginx:1.20先切流再装。模块化这套东西设计初衷是好的,实际用起来容易糊,我一般直接dnf module list nginx看清楚当前启用的是哪个流,避免装出来和预期不符。

dnf module list nginx # 输出里 [e] 表示已启用,[d] 是默认,[x] 是禁用

3.3 需要新版本时:加官方仓库

要 1.24 以上或者要用 stable 主线,就得加官方仓库。整个流程四个动作:写 repo 文件、导入 key、验证、安装。

# 1. 写入仓库配置(stable 线) cat > /etc/yum.repos.d/nginx.repo <<'EOF' [nginx-stable] name=nginx stable repo baseurl=http://nginx.org/packages/centos/$releasever/$basearch/ gpgcheck=1 enabled=1 gpgkey=https://nginx.org/keys/nginx_signing.key module_hotfixes=true EOF # 2. 导入签名 key(部分版本需要手动导入) rpm --import https://nginx.org/keys/nginx_signing.key # 3. 验证仓库可用且签名正常 dnf repolist | grep nginx dnf info nginx # 4. 安装 dnf install -y nginx

几个细节值得展开。$releasever和$basearch是 yum 的内置变量,分别代表系统主版本号和 CPU 架构,写成变量而不是写死8或x86_64,好处是同一份配置文件能跨机器复用,升级系统大版本时不用改。

module_hotfixes=true这个是给 CentOS 8 及以上用的。原因是模块化仓库里也有一个 nginx 的 module,加了这行才能让官方仓库的包优先,否则 dnf 会坚持用 AppStream 的 module 版本,你加了源也没用,装出来还是老版本。这个坑我踩过一次,dnf info nginx明明显示官方仓库有 1.26,装完nginx -v还是 1.20,查了半天才发现是 module 的锅。

gpgcheck=1千万别图省事改成 0。签名校验是软件包完整性的最后一道防线,关掉它等于允许任何人往仓库里塞一个改过的包。真遇到 key 过期之类的报错,正确做法是更新 key 或者联系镜像站,不是关校验。

要 mainline 线,把上面文件里的[nginx-stable]改成[nginx-mainline],baseurl 里的路径一样,只是包的内容不同。两条线可以配在同一个 repo 文件里,靠enabled控制启用哪条,但同时启用会冲突,只能留一个。

3.4 装完发现缺 module:三种补救方式

在线安装的包是按官方默认参数编译的,绝大多数模块都带,但少数需要额外装包。比如你要做 HTTPS 的证书动态加载或者地理信息判断,可能需要:

# 查当前编译带了哪些模块 nginx -V 2>&1 | tr ' ' '\n' | grep with- # 常见的补充包(视版本而定) dnf install -y nginx-mod-stream dnf install -y nginx-mod-http-perl

如果需要的模块在仓库里压根没有,只剩两条路:换官方 mainline 仓库看看有没有,或者源码编译。这就是第 1 章说的取舍点——只有在模块层面无解的时候,才值得付出源码编译的代价。

4. Ubuntu / Debian 系:apt 安装的完整流程

apt 这边整体更顺,但仓库和版本控制的细节比 yum 多。

4.1 universe 源与默认版本

Ubuntu 的标准安装默认启用了main和universe,nginx 就在 universe 里,直接装:

apt update apt install -y nginx

apt update不能省。这不是习惯问题,apt 的包索引是本地文件,源列表变了、镜像站换了、甚至隔了几天没用,索引都可能和实际不同步,不 update 直接 install,轻则装到旧版本,重则Unable to locate package nginx。

装完看版本:

dpkg -l | grep -w nginx nginx -v apt-cache policy nginx

apt-cache policy这条命令输出信息量最大,会列出已装版本、候选版本,以及每个候选来自哪个源。判断"我装的到底是不是官方仓库的包",看这里最准:

nginx: Installed: 1.18.0-6ubuntu14.4 Candidate: 1.18.0-6ubuntu14.4 Version table: *** 1.18.0-6ubuntu14.4 500 500 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 Packages 100 /var/lib/dpkg/status

500那个数字是优先级,来自哪个源一眼看穿。

4.2 加官方仓库拿新版本

Ubuntu 上加官方源比 CentOS 多几步,核心是 keyring 的处理。现代 apt 要求用signed-by显式指定 key 文件,不再往全局 keyring 里塞。

# 1. 准备工具(精简系统可能缺 gnupg) apt install -y curl gnupg2 ca-certificates lsb-release # 2. 下载签名 key 并转成二进制 keyring 格式 curl -fsSL https://nginx.org/keys/nginx_signing.key \ | gpg --dearmor -o /usr/share/keyrings/nginx-archive-keyring.gpg # 3. 写入源配置,注意用 signed-by 指向上面的文件 echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" \ > /etc/apt/sources.list.d/nginx.list # 4. 更新并安装 apt update apt install -y nginx

gpg --dearmor这一步是关键。下载下来的 key 是 ASCII armor 格式(-----BEGIN PGP PUBLIC KEY BLOCK-----开头),apt 需要的是二进制格式。忘了这一步,apt update会报NO_PUBKEY或者 key 格式无效。我自己习惯把 key 放在/usr/share/keyrings/,这是约定的系统级位置,比放/etc/apt/keyrings/兼容性更好,老版本 apt 也认。

$(lsb_release -cs)返回的是发行版代号,22.04 是jammy,24.04 是noble,20.04 是focal。用命令替换而不是写死代号,脚本换个系统也能跑。但要注意:官方仓库不一定支持所有代号,比如刚发布的新版本,官方源可能还没跟上,这时apt update会报 404,先去仓库目录看一眼有没有对应的子目录,别硬写。

4.3 版本锁定:防止一次 upgrade 打回原形

这是 apt 一个非常实际的问题。你千辛万苦加了官方源,装上了 1.26,某天例行apt upgrade,系统仓库里更新了一个1.18.0-6ubuntu14.5的安全补丁,apt 一比较,觉得"版本号变了,该升",于是把 1.26 降回了 1.18。业务配置里用着 1.25+ 的语法,重启直接报错。

解决办法是 apt pinning,告诉 apt"这个包只从指定源来"。

cat > /etc/apt/preferences.d/99nginx <<'EOF' Package: * Pin: origin nginx.org Pin-Priority: 900 EOF

Pin-Priority的规则是数字越大优先级越高,系统默认源一般是 500。设成 900,官方源就永远压过系统源。如果只想锁版本不换源:

apt-mark hold nginx nginx-common nginx-core apt-mark showhold # 解锁用 apt-mark unhold nginx

hold更粗暴,连官方源的更新也不装,适合"这个版本很稳,别动它"的场景。两种方式可以叠加用。CentOS 那边对应的工具是dnf versionlock插件:

dnf install -y 'dnf-command(versionlock)' dnf versionlock add nginx dnf versionlock list

4.4 目录结构差异:从 CentOS 转过来最容易晕的地方

Ubuntu 系的文件布局和 CentOS 不一样,配置写错位置是高频事故。

项目CentOS 系Ubuntu 系
主配置/etc/nginx/nginx.conf/etc/nginx/nginx.conf
站点配置目录/etc/nginx/conf.d/*.conf/etc/nginx/sites-available/+sites-enabled/软链
默认站点根目录/usr/share/nginx/html/var/www/html
运行用户nginxwww-data
默认日志/var/log/nginx/access.log/var/log/nginx/access.log(同名)
二进制路径/usr/sbin/nginx/usr/sbin/nginx

关键在站点配置。CentOS 的nginx.conf里有一行include /etc/nginx/conf.d/*.conf;,所以你往conf.d/丢.conf文件就生效。Ubuntu 的nginx.conf里是include /etc/nginx/sites-enabled/*;,而sites-enabled/里放的是指向sites-available/的软链接。

有人从 CentOS 拷了一份conf.d/xxx.conf到 Ubuntu,发现不生效,因为 Ubuntu 默认不 includeconf.d。要么在nginx.conf的http{}块里补一行include /etc/nginx/conf.d/*.conf;,要么老实按 Ubuntu 的规矩放sites-available再ln -s。这两种做法都行,但一个环境下最好统一,别一半一半,后面排查起来找文件都找不到。

提示:改完配置务必先nginx -t再systemctl reload nginx。-t只检查语法不加载,reload才是平滑生效。顺序反了,配置有错的情况下 reload 会失败,但老进程还在跑,你可能以为已经生效了。

5. 装完不是结束:验证、放行与最小可用配置

systemctl status显示 running,不代表外网能访问。这一段是做完整安装的收尾,也是新手最常断链的地方。

5.1 五步验证法

按这个顺序查,每一步失败都能精确定位到层次。

# 第一步:二进制在不在,版本对不对 nginx -v nginx -V 2>&1 | head -3 # 第二步:配置语法有没有问题 nginx -t # 第三步:进程在不在,谁在监听 systemctl is-active nginx ss -lntp | grep :80 # 第四步:本机能不能通(绕过防火墙) curl -I http://127.0.0.1 # 第五步:本机 IP 能不能通(验证监听地址) curl -I http://$(hostname -I | awk '{print $1}')

第三步如果ss输出里监听的是127.0.0.1:80而不是0.0.0.0:80,说明配置里listen写成了本地回环,外部当然访问不了。第四步通、第五步不通,问题在防火墙或者listen地址;第四步就不通,问题在 Nginx 本身或者配置。

nginx -V的输出值得留意,里面包含编译参数和--with-开头的模块列表。判断某个功能能不能用,看这个比查文档快。

5.2 防火墙与 SELinux 放行

CentOS 系默认开 firewalld:

firewall-cmd --permanent --add-service=http firewall-cmd --permanent --add-service=https firewall-cmd --reload firewall-cmd --list-services

Ubuntu 系默认是 ufw,但很多云镜像没启用,先看状态:

ufw status verbose # 如果是 inactive,说明防火墙没开,可以跳过 # 如果 active,放行: ufw allow 80/tcp ufw allow 443/tcp ufw reload

CentOS 上还有 SELinux 这个隐形杀手。默认策略下,Nginx 只能读/usr/share/nginx/html和/var/www这类标记为httpd_sys_content_t的目录。你把站点根目录改成/data/www,浏览器直接 403,error.log里一行:

Permission denied: [client ...] AH00035/nginx: access forbidden by rule

或者/var/log/nginx/error.log里什么都没有,只有403 Forbidden。这时候查 SELinux:

getenforce # Enforcing 就说明是它 # 让新目录获得正确的安全上下文 semanage fcontext -a -t httpd_sys_content_t "/data/www(/.*)?" restorecon -Rv /data/www # 如果 Nginx 要反向代理到后端(需要主动发起连接) setsebool -P httpd_can_network_connect 1 # 临时验证是不是 SELinux 的锅(不建议长期关) setenforce 0

semanage命令来自policycoreutils-python-utils包,精简系统可能没装,先dnf install -y policycoreutils-python-utils。restorecon是让之前的 fcontext 规则生效,两个命令要配对用,只跑第一个不跑第二个,权限不会变。

注意:setenforce 0只是把当前状态切到宽容模式,重启后恢复。它适合用来确认问题根源,不适合当解决方案。生产上关 SELinux 是在给自己埋雷,正确的做法是打标签。

5.3 一份可以直接抄的最小可用配置

装完之后系统会带一个默认站点,指向默认目录。想换成自己的,按下面这套来,CentOS 和 Ubuntu 都能用,区别只在运行用户。

# 1. 建目录和测试页 mkdir -p /var/www/demo cat > /var/www/demo/index.html <<'EOF' <!DOCTYPE html> <html><head><meta charset="utf-8"><title>demo</title></head> <body><h1>nginx is running</h1></body></html> EOF # 2. 权限:CentOS 用 nginx 用户,Ubuntu 用 www-data chown -R nginx:nginx /var/www/demo # Ubuntu 改成 www-data:www-data chmod 755 /var/www/demo chmod 644 /var/www/demo/index.html

配置文件放的位置按发行版来:CentOS 写/etc/nginx/conf.d/demo.conf,Ubuntu 写/etc/nginx/sites-available/demo然后ln -s到sites-enabled/。

server { listen 80; server_name _; root /var/www/demo; index index.html; access_log /var/log/nginx/demo.access.log; error_log /var/log/nginx/demo.error.log warn; location / { try_files $uri $uri/ =404; } location = /healthz { access_log off; return 200 "ok\n"; add_header Content-Type text/plain; } }

几个参数的必要性说清楚。server_name _是通配写法,匹配所有未命中的 Host,做单站点或者测试环境足够,正式环境应该换成真实域名。try_files $uri $uri/ =404是静态站点的标准写法,先找文件,再找目录,都没有就 404,比直接root少很多奇怪行为。location = /healthz是给负载均衡或者监控探活用的,access_log off避免探活请求把日志刷满——这个细节很多人不做,结果健康检查每 5 秒一次,一天写几万行日志。

生效流程固定三步:

nginx -t systemctl reload nginx curl -I http://127.0.0.1/healthz

5.4 worker 参数怎么估:别抄网上的数字

默认配置文件里的worker_connections 1024是老值,很多人直接照抄,机器配置高也用不上。这里给一个能算的说法。

worker_processes auto; events { worker_connections 4096; }

worker_processes auto让 Nginx 按 CPU 核数自动设,4 核就是 4 个 worker,这是推荐值,不用手写。worker_connections是单个 worker 能同时处理的最大连接数,理论最大并发是两者相乘:

  • 4 核 × 4096 = 16384 个连接
  • 如果做反向代理,一个客户端请求会占用两条连接(客户端侧 + 后端侧),实际能承载的客户端约 16384 / 2 = 8192

但有个硬约束在操作系统层面:每个连接占一个文件描述符,worker 进程的 fd 上限必须大于worker_connections。查当前限制:

ulimit -n # 当前 shell 的限制 cat /proc/$(pgrep -o nginx)/limits | grep 'open files'

如果显示 1024,那worker_connections 4096毫无意义,跑到 1023 个就Too many open files了。调高需要同时改systemd单元:

mkdir -p /etc/systemd/system/nginx.service.d cat > /etc/systemd/system/nginx.service.d/limits.conf <<'EOF' [Service] LimitNOFILE=65535 EOF systemctl daemon-reload systemctl restart nginx

经验值是LimitNOFILE设成worker_connections的 2 到 4 倍,留足余量给日志文件、临时文件、上游连接。别设成无穷大,系统级 fd 是共享资源,一个进程吃光会影响整机。

6. 踩坑实录:在线安装最常遇到的 10 个问题

这一节按问题类型整理,配上排查命令和原因说明,可以当速查表用。

6.1 仓库与安装类问题

报错/现象大概率原因排查与解决
Unable to locate package nginx(apt)索引没更新,或 universe 未启用apt update;grep universe /etc/apt/sources.list
No package nginx available(yum)仓库里确实没有,CentOS 7 缺 EPELyum install epel-release后重试
Could not resolve hostDNS 问题或网络不通getent hosts nginx.org,检查/etc/resolv.conf
NO_PUBKEY xxxxxxxx签名 key 没导入按 4.2 的方式重新下载并 dearmor
GPG key retrieval failedkey 地址不可达,或系统时间错误date看时间是否偏差过大,校正后重试
Error: Transaction check error ... conflicts系统包与官方仓库包冲突先卸载系统包dnf remove nginx,再加官方源重装
装完版本还是旧的官方源被 module 或 pin 压制CentOS 加module_hotfixes=true;Ubuntu 检查apt-cache policy

时间偏差那条特别隐蔽。系统时钟如果落后或者超前几年,TLS 握手和 GPG 验签都会失败,但报错信息完全看不出是时间问题。我遇到过一次容器环境,宿主机时间正常,容器里时间差了三个月,apt update一直报验签失败,查了半小时才想到date。校正用timedatectl set-ntp true。

6.2 服务启动类问题

现象一:Job for nginx.service failed because the control process exited with error code。这个报错本身没信息,必须看详细日志:

systemctl status nginx -l --no-pager journalctl -u nginx -n 50 --no-pager nginx -t

九成是配置语法错误,nginx -t会直接指出来哪一行。

现象二:bind() to 0.0.0.0:80 failed (98: Address already in use)。端口被占,找出是谁:

ss -lntp | grep :80 fuser -n tcp 80

常见占用者包括预装的 Apache、某些面板自带的服务、上一次没杀干净的 Nginx 进程。确认后停掉对方,或者改 Nginx 的监听端口。

现象三:启动成功但访问 403。按这个顺序查:目录权限(其他人有没有读和执行权限)、SELinux(getenforce)、index文件是否存在、nginx.conf里的user指令和目录属主是否匹配。Ubuntu 上特别容易犯的错是把目录 chown 给了nginx用户,但 Ubuntu 的 Nginx 跑在www-data下,读不了。

现象四:改了配置但行为没变。检查是不是改了sites-available里的文件却没建软链,或者同一个location在别的配置文件里被覆盖了。查完整生效配置:

nginx -T | grep -n "listen\|server_name\|root"

-T会把所有 include 的文件合并输出,比一个个翻文件快得多。

6.3 我自己的三条避坑心得

第一条:新机器先跑一遍体检再动手。第 1.3 节那三条命令,我现在写在批量脚本的最前面,尤其是端口占用检查。曾经有一次在客户现场,装完发现 80 被占,排查占用进程花的时间比装 Nginx 多十倍。

第二条:仓库优先级一定要显式配置,不要依赖默认行为。Ubuntu 上加了官方源却不配 pin,迟早被apt upgrade打回原形;CentOS 8 上不加module_hotfixes,官方源等于白加。这两个都是"不报错但结果不对"的类型,最难发现。

第三条:升级前先备份/etc/nginx整个目录。包管理器升级大概率会问你配置文件怎么处理,选保留旧的还是用新的,一旦选错,自定义的location就没了。

tar czf /root/nginx-conf-$(date +%F).tar.gz /etc/nginx

就一条命令,三十秒的事,能救回来一整天的配置重建。我现在的习惯是每次改配置前先打一个包,攒几天再清理,比记在脑子里靠谱。

另外提一个容易被忽略的点:systemctl reload nginx和restart的区别。reload是平滑重载,老 worker 处理完手头请求再退出,连接不断;restart是直接停再起,有几百毫秒的中断。生产环境改配置,只要没动监听端口、没换二进制,一律用reload。但如果换了worker_processes或者改了user指令,reload可能不生效,必须restart。

最后说个我自己的习惯:每台机器装完 Nginx,我会在/root/下留一个nginx-install-note.md,写清楚装的是什么版本、来自哪个仓库、加了哪些非默认配置、站点根目录在哪。这东西看着多余,但半年后你或者别人登上来,看一眼就全明白了,比翻 history 强太多。装软件这件事本身不复杂,复杂的是三个月后还能不能记得当时为什么这么装。

返回列表