
事情是这样的。去年有个同事在测试环境装Nginx折腾了一下午先是编译报错说找不到PCRE装好依赖以后启动又失败一看是80端口被另一个服务占了好不容易空出端口浏览器还是打不开最后发现是防火墙没有放行。这几个坑单看都不难但串在一起没点经验确实能卡一天。这篇文章就把Linux系统下载安装Nginx这件事从头到尾理一遍版本怎么选、源码包从哪下、编译参数怎么配、装完怎么验证、之后怎么管理和排查每一步我都会把背后的原因讲清楚而不是只给一条命令让你复制。文章主要面向Linux运维新手也适合已经在用Nginx但一直没有系统梳理过安装流程的朋友。看完以后你至少能独立完成一次从下载到上线的基础部署并且知道出问题的时候从哪下手查。1. 装之前先想清楚三种安装方式怎么选1.1 包管理器安装省事但未必省心用包管理器安装Nginx是最直观的方式。Debian/Ubuntu系用 apt install nginxCentOS/RHEL系用 yum install nginx一行命令装完自动处理依赖装完以后有现成的systemd服务直接 systemctl start nginx 就能跑起来。这对只想快速跑通一个场景的人来说确实方便但用到生产环境就有几个问题。首先是版本落后发行版仓库里的Nginx版本往往比官方主线慢很多尤其是一些长期维护的发行版仓库里的版本可能是几年前的虽然稳定但缺少新协议、新模块和新性能优化。其次是模块定制不自由Nginx很多有用的模块默认不带比如stream四层代理、http_v2、stub_status状态页官方包或者发行版包不一定都编译进去你没法按需选择。第三是目录结构跟官方源码安装不一样比如Ubuntu的apt装出来配置文件在 /etc/nginx日志在 /var/log/nginx站点配置要放 /etc/nginx/sites-available而很多教程都是基于源码装的 /usr/local/nginx 写的新手看着看着就对不上号了。所以我的建议是如果是生产或学习场景想真正理解Nginx、后续方便自定义模块优先用源码编译安装。包管理器安装更适合临时环境比如容器里快速验证、本地开发机随便跑跑。1.2 源码编译安装可控性最强的一条路源码编译安装本质上就是自己去官网下载源代码然后通过 configure 配置编译参数再用 make 编译成二进制文件最后 make install 把文件安装到指定目录。整个过程每一步你都能参与装了什么模块、装在哪个目录、用什么用户运行全都由你决定。代价是需要自己动手处理依赖关系编译也比较耗时但也就几分钟到十几分钟的事。对运维来说这点成本换来的是对系统的掌控感特别是一次编译出来的二进制文件可以在一模一样的服务器之间直接分发批量部署效率反而更高。1.3 源码包从哪下版本选择与下载渠道Nginx官方下载地址是 nginx.org具体下载页面是 nginx.org/en/download.html。页面里有两个大分类Mainline version 是主线版本更新频繁会带最新的功能特性但相应引入新bug的风险也高Stable version 是稳定版本经过更多测试生产环境一般都选稳定版。下载的时候建议选择 tar.gz 后缀的包用 wget 直接命令行拉取。比如当前写这篇文章时稳定版本是1.24.x系列可以这样下cd /usr/local/src wget https://nginx.org/download/nginx-1.24.0.tar.gz tar -xzf nginx-1.24.0.tar.gz cd nginx-1.24.0如果官网下载速度不理想可以用一些公共镜像源国内很多云厂商和开源镜像站都有nginx源码包的镜像下载方式就是把 wget 的URL换成镜像地址。选镜像时不要太旧有些镜像同步不及时版本会落后下之前跟官网版本号对一下就行。2. 从源码到可运行完整编译安装手册2.1 先准备好编译环境四样东西缺一不可源码编译Nginx之前系统里必须装好编译器 gcc、make以及几个关键开发库。这里我把它们的作用说清楚而不是让你死记包名。第一个是 gcc。Nginx源码是C语言写的gcc负责把源码翻译成机器码。没装gcc执行 configure 的时候不会立刻报错但跑到 make 会直接失败报错信息是 cc: command not found。第二个是 PCRE 库。Nginx的 location 指令用正则表达式匹配URL靠的就是PCRE。没装的话configure 会告诉你缺少 PCRE 支持编译进度直接卡住。CentOS上对应的包名是 pcre-develUbuntu上是 libpcre3-dev。第三个是 zlib 库。Nginx 的 gzip 压缩功能依赖它比如对 HTML、CSS、JS 做压缩传输没装 zlibconfigure 会提示 --with-http_gzip_static_module 无法启用或者直接编译报错。CentOS 是 zlib-develUbuntu 是 zlib1g-dev。第四个是 OpenSSL 库。只要你想启用HTTPS也就是配置SSL证书就必须有OpenSSL开发头文件。CentOS 是 openssl-develUbuntu 是 libssl-dev。没有它--with-http_ssl_module 这个参数就编不进去。在CentOS系上可以一次性把编译工具链都装上yum install -y gcc make pcre-devel zlib-devel openssl-develUbuntu/Debian系apt update apt install -y build-essential libpcre3-dev zlib1g-dev libssl-dev这些依赖就像做饭的锅碗瓢盆缺一个菜就炒不熟。装完以后可以用 rpm -q 或者 dpkg -l 检查一下包是否装好不过一般情况下yum、apt不会骗你。2.2 configure参数怎么选才合理进入解压后的源码目录第一件事是执行 configure 脚本。它是个收集配置信息的程序检查系统里有没有需要的库然后根据你的参数生成编译所需的 Makefile。很多人第一次看到 configure 参数会懵不知道哪些是必选的。其实核心就两个--prefix 指定安装目录--with-xxx_module 表示要编译进去的模块。我常用的生产配置是这样./configure \ --prefix/usr/local/nginx \ --with-http_ssl_module \ --with-http_v2_module \ --with-http_stub_status_module \ --with-http_gzip_static_module \ --with-stream \ --with-http_realip_module逐条解释一下。--prefix 决定Nginx最终安装到哪个目录默认是 /usr/local/nginx我会不写默认值明确写出来后面找文件方便。--with-http_ssl_module 是HTTPS必备不编译这个模块nginx.conf里 listen 443 ssl 根本不让用。--with-http_v2_module 是HTTP/2协议多路复用对现代站点性能提升明显。--with-http_stub_status_module 提供基础的访问状态页地址是 /nginx_status可以看到当前活跃连接数。--with-http_gzip_static_module 做静态文件预压缩配合 gzip on 使用能省不少传输流量。--with-stream 是四层TCP/UDP代理支持很多人在Nginx上做MySQL代理、Redis代理靠的就是这个模块。--with-http_realip_module 用来在反代场景下获取真实客户端IP比如前面挂了CDN或者ELB。这些参数选完configure 会输出一个Summary表格列出安装路径、编译模块等。如果哪一步缺少依赖它会明确报错比如 checking for PCRE library ... not found这时候返回去装依赖就行。configure通过以后目录下会生成 Makefile编译就进入了下一阶段。2.3 编译与安装等待时间正好用来理解结构编译执行 make 命令。机器核数多的可以加 -j 参数并行编译比如4核就用 make -j4能明显缩短时间。Nginx整体不大编译一般也就一两分钟慢的时候三分钟这个时间正好可以看看源码目录里的 auto 文件夹了解下 configure 是怎么检查系统的。编译完成后执行 make install这一步才是真正把文件复制到 --prefix 指定的目录。安装完成后你要的东西已经出现在 /usr/local/nginx 下面了。如果安装过程中出现权限错误检查你当前登录用户对 /usr/local 是否有写权限生产环境一般习惯用 root 或 sudo 完成这一步。2.4 装完先别急目录检查与首次启动验证安装完成先检查目录结构ls -l /usr/local/nginx/ ls -l /usr/local/nginx/sbin/ ls -l /usr/local/nginx/conf/ ls -l /usr/local/nginx/html/正常情况下会有四个子目录conf 放着所有配置文件html 是默认站点首页logs 存放访问日志和错误日志sbin 里是 nginx 可执行文件。这几个目录要熟以后每天打交道就靠它们了。首次启动前先做配置语法检查养成这个习惯能省大量排错时间/usr/local/nginx/sbin/nginx -t看到 syntax is ok 和 test is successful 就说明配置没问题可以启了。启动命令/usr/local/nginx/sbin/nginx启动后验证进程和端口ps -ef | grep nginx ss -lntp | grep 80 curl -I http://127.0.0.1curl 返回 HTTP/1.1 200 和 Server: nginx/1.24.0 就大功告成。浏览器访问服务器IP看到Welcome to nginx!页面说明这台Linux上的Nginx已经能对外提供服务了。3. 配置解析读懂nginx.conf的核心骨架3.1 Nginx配置的层级结构装好的Nginx自带一个默认配置路径是 /usr/local/nginx/conf/nginx.conf。第一次打开它你会看到很多井号注释去掉注释后核心结构大概是这样worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; server { listen 80; server_name localhost; location / { root html; index index.html index.htm; } } }我在带新人的时候常打一个比方nginx.conf 是一个公司的组织架构图。最外层是 main 区可以理解成整个公司的董事层决定有几个工作进程每个进程最多开多少连接。events 区是运营团队管事件处理模型。http 区是整个业务层所有Web请求的处理规则都在里面。http 里面可以有多个 server每个server类似一栋楼的前台通过不同域名或端口分流。server 里面的 location 则是各个楼层的前台负责把不同路径的请求送到对应房间。记住一句话Nginx的配置是层层嵌套、逐级匹配的。请求进来先看http层再匹配server然后按location规则分派处理每层的指令只能在当层生效这也是新手最容易搞混的地方。比如 listen 只能写在 server 里写成 http 层必然报错。3.2 常用指令与实际配置示例最常用的三个指令是 worker_processes、worker_connections、server_name。worker_processes 决定Nginx启动几个工作进程。线上经验值一般设成和CPU核心数相同不用过多。查看核数用 nproc。worker_connections 是每个工作进程能同时处理的最大连接数默认1024太小线上可以调到4096甚至更高但要注意系统级文件描述符限制。这两者乘起来基本就是Nginx能撑住的并发上限。server_name 用来匹配请求的Host头。客户端访问 www.example.com 时Nginx会拿着这个名字跟每个 server 的 server_name 比对命中就进入这个server。下面是一份可用于静态站点的基础配置示例server { listen 80; server_name example.com www.example.com; root /data/www/example; index index.html index.htm; location / { try_files $uri $uri/ 404; } location ~* \.(css|js|png|jpg|jpeg|gif|ico)$ { expires 30d; access_log off; } }root 指定站点文件的根目录location / 里的 try_files 先查有没有对应的文件没有再查目录都没有就返回404。对静态资源加个 expires 30d 让浏览器强缓存能大幅减少请求量这个写法很实用。3.3 日常管理命令与平滑重载的秘密Nginx运行中改配置文件是常有的事。改完别急着重启先执行 nginx -t 检查语法然后执行 nginx -s reload 重载配置。nginx -s 后面跟参数可以控制进程nginx -s stop立即停止相当于直接杀掉进程nginx -s quit优雅停止处理完当前请求再退出nginx -s reload重载配置不停服务nginx -s reopen重新打开日志文件配合日志切割用很多人不理解 reload 为什么比 restart 好这里把原理说一下。nginx 启动时有一个 master 主进程和多个 worker 工作进程。reload 发送的是 HUP 信号master 收到后先读取新配置语法没问题就启动新的 worker旧 worker 处理完手头请求自动退出。整个过程对客户端基本无感连接不中断。restart 则是先杀后起那一瞬间连接全断线上绝对不能随便用。如果你想开机自启源码安装默认没有systemd服务文件。可以手写一个 /etc/systemd/system/nginx.service内容大致这样[Unit] Descriptionnginx web server Afternetwork.target [Service] Typeforking PIDFile/usr/local/nginx/logs/nginx.pid ExecStart/usr/local/nginx/sbin/nginx ExecReload/usr/local/nginx/sbin/nginx -s reload ExecStop/usr/local/nginx/sbin/nginx -s quit PrivateTmptrue [Install] WantedBymulti-user.target写好后执行 systemctl daemon-reload然后 systemctl enable --now nginx 就能开机自启。Typeforking 很关键因为 nginx 启动后主进程会 fork 出子进程init系统要用 PIDFile 里的 pid 判断服务状态。4. 两个高频实战静态站点与反向代理4.1 静态站点部署从路径到访问一次跑通先做一个最简单的静态站。假设网站代码放在 /data/www/demo 目录下里面有个 index.html。配置如下server { listen 80; server_name demo.local; root /data/www/demo; index index.html; location / { try_files $uri $uri/ 404; } }启动后访问 http://服务器IP/ 就能看到页面。这里有个非常常见的坑root 和 alias 的区别。上面写的是 root意思是根目录 /data/www/demo当请求 /images/logo.png 时Nginx会去 /data/www/demo/images/logo.png 找文件。alias 则用于 location 局部路径的绝对映射比如location /static/ { alias /data/uploads/; }这个请求 /static/a.css实际文件是 /data/uploads/a.cssalias 会把 URL 中 location 匹配的路径部分替换成 alias 指定路径规则简单记root 直接拼alias 做替换。用错的话404是家常便饭。4.2 反向代理把请求转交给后端应用Nginx最出名的场景就是反向代理。比如说你有个Java应用跑在8080端口不想让用户直接访问就可以用Nginx代理转发配置server { listen 80; server_name api.example.com; location / { proxy_pass http://127.0.0.1:8080; 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; } }用户访问 api.example.comNginx就把请求转给本机8080端口的Java应用看起来就像应用直接在80端口对外提供服务。proxy_set_header 这几行是在转发时把客户端的真实信息带上如果不加 Host 头后端拿着的是Nginx自己的地址有些按域名做判断的应用就会出逻辑错误。尤其是 X-Forwarded-For多级代理场景下后端要靠它拿到真实IP做日志分析、防作弊非常关键。这里还有一个很多人踩过的坑proxy_pass 的URI部分带不带斜杠行为完全不一样location /api/ { proxy_pass http://127.0.0.1:8080; # 不带斜杠会保留完整路径 /api/xxx } location /api/ { proxy_pass http://127.0.0.1:8080/; # 带斜杠路径中 /api/ 会被替换掉 }第一种请求 /api/user后端收到 /api/user。第二种请求 /api/user后端收到 /user因为带斜杠时匹配的 /api/ 部分被替换了。选哪种取决于后端接口设计定义接口时如果没有 /api 前缀就要用带斜杠的形式否则404或者路由不匹配。4.3 负载均衡多台后端的请求分发当单台后端扛不住流量时Nginx还能当负载均衡器用。核心就一个 upstream 块定义一个后端服务器组upstream backend { server 192.168.1.101:8080 weight3; server 192.168.1.102:8080 weight1; keepalive 32; } server { listen 80; server_name app.example.com; location / { proxy_pass http://backend; } }默认按轮询方式把请求轮流分到两台后端weight 参数控制权重weight3 的服务器会分到差不多3倍的流量。keepalive 32 是连接复用让Nginx和后端之间保持长连接减少握手开销。生产环境通常还会配上 fail_timeout 和 max_fails用于健康检查比如连续失败3次就把节点标记为不可用过一段时间再重新试探。这个组合拳打下来后端宕机一台服务也不中断。5. 常见问题排查实录从编译到访问一条龙5.1 编译阶段报错怎么破我把编译期最常见的几个报错整理成一张表方便你对照处理报错特征缺少的依赖处理方法configure: error: the HTTP rewrite module requires the PCRE libraryPCRE库装 pcre-devel / libpcre3-devconfigure: error: the HTTP gzip module requires the zlib libraryzlib库装 zlib-devel / zlib1g-devcc: command not foundgcc装 gcc / build-essentialConfigure: error: SSL modules require OpenSSLopenssl装 openssl-devel / libssl-dev另外还有一个不常见但很气人的情况依赖明明装好了configure 依然报找不到。原因多半是系统里有多个版本共存比如系统自带一个老版本的pcre你又装了个新的configure 默认找的就是老版本。这种情况下可以用 ./configure --with-pcre路径 来指定但这是少数情况初学者遇到先把冲突的旧包卸掉。5.2 启动失败80端口被占用的排查流程nginx -t 通过执行启动却报 bind() to 0.0.0.0:80 failed (98: Address already in use)十有八九是端口被别的服务占了。Linux上排查端口占用就三招ss -lntp | grep 80 lsof -i :80 netstat -tlnp | grep 80如果看到 httpd 或者 nginx 老进程占着要么停掉它要么给新Nginx配一个非80端口。生产环境如果是迁移就先把旧服务停干净再启新的注意 zombie 进程可能要 kill -9 强杀。还有一个容易被忽略的情况是端口被 TIME_WAIT 状态的连接占用但Nginx正常启动时 SO_REUSEADDR 是开着的一般不受影响如果你自定义编译时没带上相关宏麻烦才大。5.3 服务启动了但外部访问不了这种情况最磨人本机 curl 正常其他机器打不开。先别改配置按顺序排查两步。第一步查防火墙。CentOS 7以上用 firewalldsystemctl status firewalld firewall-cmd --list-all firewall-cmd --permanent --add-port80/tcp firewall-cmd --reloadUbuntu用 ufwufw status ufw allow 80/tcp第二步查SELinux。CentOS默认开启SELinuxNginx装到非标准目录后有时会因为文件上下文问题被拦日志里能看到 denied 字样。临时关闭用 setenforce 0检查状态用 getenforce。如果想永久放行80端口可以这样semanage port -a -t http_port_t -p tcp 80但 semanage 需要安装 policycoreutils-python-utils 这个额外的包各发行版名字不一样。对于新手如果确认是SELinux拦截临时关掉验证一下确定是它的锅再考虑是彻底关闭还是写放行规则。5.4 改配置不生效与SSL证书替换的坑改完配置发现不生效优先排查这三点有没有执行 nginx -t 并看到 syntax is ok有没有执行 nginx -s reload光改文件不重载等于白改有没有保存权限问题导致文件根本没写进去关于SSL证书替换不生效这个我遇到过不少。常见原因不是Nginx没读新证书而是你只替换了证书文件没重载或者证书链不完整。Nginx加载的是 pem 文件里面应该包含站点证书和中间证书链最好按 域名.crt ca-chain.crt 的顺序拼接成一个完整文件。替换后建议执行nginx -t nginx -s reload openssl x509 -in /路径/证书.pem -noout -dates最后一条命令可以看证书起止日期确认服务器读到的是不是你替换后的新证书。还有一个容易被忽略的点如果你在Nginx上配置了 OCSP stapling那么需要确保服务器能访问到OCSP响应服务器否则浏览器仍然会认为证书状态未知表现就是证书明明换了却不生效。这个问题排查起来很绕但本质是链路问题不是Nginx配置本身的问题。结尾这几年的使用经验下来我最大的体会是Nginx安装本身不难难的是搞清楚每一条命令和参数背后到底发生了什么。比如你明白了 reload 是 HUP 信号、stop 是 QUIT 信号就不会在线上贸然 restart明白了 root 和 alias 的拼接逻辑就不会为404挠头半小时。最后分享一个工作习惯我在所有服务器上都这么做任何配置文件改动前先 cp 一份带日期的备份比如 nginx.conf.bak-2024-06-01每次改完必跑 nginx -t如果一次改了很多内容不要直接上生产先在测试环境用同一版本Nginx验证一遍。另外如果你是第一次搭线上环境装完以后记得把 nginx -V 编译参数的输出存起来后面升级版本、重新编译的时候对照着用能少踩很多坑。这个内容后续你还可以往平滑升级、日志切割、TCP/SSL优化这些方向去扩展。先把安装这关平安过了后面的路就顺了。