在Linux服务器上装Nginx这件事看起来简单但真正配到能上线、能抗住访问、能上HTTPS中间还是有不少坑。我最近刚给一台CentOS服务器从零装完Nginx顺手整理了一份保姆级笔记从环境检查、安装、配置到常见问题排查全都有。不管你是刚接触Linux的小白还是被Nginx配置折腾过的运维这篇应该都能让你少走点弯路。先把结论说在前面如果你只是想快速跑起来直接用系统自带的软件包管理器安装是最省事的如果你需要编译第三方模块或者追求最优性能再考虑源码编译。下面我会把两条路都讲清楚但会以上手最快的包管理方式为主。1. 安装前的准备与思路1.1 先搞清楚你要用Nginx做什么Nginx是一个高性能的HTTP和反向代理服务器也是一个IMAP/POP3/SMTP代理服务器。它的特点是占用内存少、并发能力强配置灵活。在实际项目里最常见的用途有四个静态文件服务、反向代理、负载均衡、SSL终端。比如你有一个Java后端跑在8080端口你希望用户通过80端口访问并且不想让用户感知到后端端口这就是典型的反向代理场景如果你想让Nginx直接托管前端打包出来的dist目录那就是静态文件服务如果你有多台后端服务器想均匀分配请求那就是负载均衡。搞清楚自己的需求后面配置起来才不会乱。我遇到的很多朋友上来就搜“Nginx安装”装完不知道下一步干嘛然后在配置里瞎改。所以我建议安装之前先花10分钟理清楚你是要托管静态页面、反代某个服务还是做负载均衡这会直接影响你最终要改哪些配置块。1.2 环境检查系统版本、网络和依赖安装之前先确认三件事系统版本、网络连通性、必要的编译工具如果走源码。检查系统版本命令cat /etc/os-release不同发行版的包管理器不一样CentOS/RHEL系用yum或dnfUbuntu/Debian系用apt。下面命令可以查看CPU架构uname -m如果你是x86_64的机器直接安装官方源里的Nginx就行如果是ARM架构比如树莓派、鲲鹏云主机包管理器里一般也有对应的版本不用担心。网络方面只需要保证能访问系统默认软件源。如果你在国内可能会遇到yum源或apt源速度慢这个可以通过配置国内镜像解决但注意不要引入任何非官方或来源不明的源优先使用系统自带源或知名云厂商的镜像源即可。依赖方面如果使用包管理器安装Nginx会帮你自动解决依赖不需要操心。但如果你打算源码编译则需要安装gcc、make、pcre、zlib、openssl等开发库。后面我会专门列出来。1.3 安装方式选型包管理器 vs 源码编译两种方式各有适用场景我简单对比一下比较项包管理器安装源码编译安装安装速度快通常1分钟内慢需要编译可能10分钟以上版本系统源中提供的版本可能不是最新可以自己指定版本自定义模块不方便通常只能使用自带模块可以在编译时选择模块卸载/升级方便一条命令需要手动清理升级麻烦适用场景绝大多数普通项目需要特定模块或定制优化我的建议是如果不是特殊需要直接用包管理器。很多人一看“源码编译更自由”就选源码结果编译时报缺少依赖折腾半天。生产环境求稳包管理器安装的Nginx同样稳定而且用systemd管理更方便。好接下来进入实操。2. 保姆级安装步骤2.1 CentOS/RHEL系列使用yum/dnf安装CentOS 7及以下用yumCentOS 8及以上包括Rocky Linux、AlmaLinux用dnf本质一样。执行sudo yum install -y nginx如果你使用的是云厂商的基础镜像可能默认带了epel源如果没有可以先装epel-releasesudo yum install -y epel-release sudo yum update -y sudo yum install -y nginx这里解释一下为什么需要epel源nginx在默认base源里可能不存在或版本较旧而EPELExtra Packages for Enterprise Linux是官方推荐的扩展源里面有nginx。装完以后可以通过下面的命令查看版本nginx -v启动并设置开机自启sudo systemctl start nginx sudo systemctl enable nginx检查状态sudo systemctl status nginx如果看到active (running)说明安装成功了。此时在浏览器里访问服务器IP如果能看到Nginx的默认欢迎页那就说明80端口已经正常工作。注意如果服务器有防火墙需要放行80端口和443端口下面给出常用命令sudo firewall-cmd --permanent --add-servicehttp sudo firewall-cmd --permanent --add-servicehttps sudo firewall-cmd --reload如果是云服务器还需要在安全组里放行80和443这个去云控制台操作即可。2.2 Ubuntu/Debian系列使用apt安装Ubuntu和Debian用apt安装命令更简单sudo apt update sudo apt install -y nginx安装完成后同样启动sudo systemctl start nginx sudo systemctl enable nginxUbuntu上Nginx默认的站点配置文件位置和CentOS略有不同。这里需要留意apt安装的Nginx默认配置文件在/etc/nginx/nginx.conf而站点配置一般放在/etc/nginx/sites-available/通过软链接到/etc/nginx/sites-enabled/启用。如果你习惯CentOS风格直接在nginx.conf里include conf.d/*.conf也可以只是需要自己调整。2.3 源码编译安装需要自定义模块时用如果你确实需要源码编译下面的步骤以当前主流的Nginx 1.24.0为例。先安装编译工具和依赖sudo yum install -y gcc make pcre pcre-devel zlib zlib-devel openssl openssl-develUbuntu下对应为sudo apt install -y build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev然后下载源码包并解压wget https://nginx.org/download/nginx-1.24.0.tar.gz tar -zxvf nginx-1.24.0.tar.gz cd nginx-1.24.0配置编译参数最基础的命令是./configure --prefix/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module这一步会检查环境并生成Makefile。--prefix表示安装路径--with-http_ssl_module表示启用SSL模块没有这个模块是无法配置HTTPS的。如果你要支持gzip静态压缩、流媒体等可以加上--with-http_gzip_static_module等参数但不要盲目加够用就好。接下来编译安装make -j2 sudo make install-j2表示用两个CPU核心并行编译如果你机器核数多可以-j4。编译时间取决于机器性能一般5到15分钟。安装完成后启动方式稍有不同因为源码安装不会自动创建systemd服务。你可以手动编辑/usr/local/nginx/conf/nginx.conf后使用/usr/local/nginx/sbin/nginx命令启动、停止、重载。为了方便我通常会自己写一个systemd服务文件但这一步对小白来说不是必须的。如果你只是想尝鲜先这样用着也行。2.4 验证安装与常用目录说明无论哪种方式安装安装完之后都要验证一下。检查Nginx版本和配置文件语法nginx -v nginx -tnginx -t是检查配置语法如果输出syntax is ok和test is successful说明配置文件没问题。下面把常见的目录和文件列一下方便你后面找路径作用/etc/nginx/nginx.conf主配置文件/etc/nginx/conf.d/存放自定义的站点配置文件CentOS系常用/etc/nginx/sites-available/站点可用配置Ubuntu/Debian常用/etc/nginx/sites-enabled/站点启用的配置软链接/var/log/nginx/access.log访问日志/var/log/nginx/error.log错误日志/usr/share/nginx/html/默认的网站根目录CentOS系/var/www/html/默认的网站根目录Ubuntu系如果你用源码编译安装路径则取决于你编译时指定的--prefix默认是/usr/local/nginx。2.5 systemd管理与开机自启包管理器安装的Nginx通常已经内置了systemd服务文件所以systemctl start nginx直接可用。源码编译的需要自己写服务文件不然重启服务器后Nginx不会自动跑起来。这里分享一个我常用的服务文件写入/etc/systemd/system/nginx.service[Unit] Descriptionnginx - high performance web server Afternetwork.target remote-fs.target nss-lookup.target [Service] Typeforking PIDFile/usr/local/nginx/logs/nginx.pid ExecStartPre/usr/local/nginx/sbin/nginx -t ExecStart/usr/local/nginx/sbin/nginx ExecReload/usr/local/nginx/sbin/nginx -s reload ExecStop/usr/local/nginx/sbin/nginx -s stop PrivateTmptrue [Install] WantedBymulti-user.target注意如果你的Nginx安装路径不是/usr/local/nginx需要对应修改。写完以后执行sudo systemctl daemon-reload sudo systemctl enable nginx sudo systemctl start nginx这样源码编译安装也能用systemd统一管理了。3. 核心配置解析与实操3.1 主配置文件nginx.conf的结构打开/etc/nginx/nginx.conf你会看到Nginx的配置核心。别被一大堆指令吓到其实结构很清晰。最外层是events和http两个块http块里面又有server块每个server块对应一个站点或者一个虚拟主机。一个最基本的配置骨架长这样user nginx; worker_processes auto; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 80; server_name example.com; root /usr/share/nginx/html; index index.html index.htm; } }这里简单解释几个关键参数worker_processesNginx的工作进程数一般设为CPU核心数或auto不用手动数。worker_connections每个工作进程能同时建立的连接数默认1024高并发场景可调大。sendfile开启后能提高静态文件传输效率建议开启。keepalive_timeout客户端保持连接的超时时间单位秒。如果你要增加多个站点有两种做法一是直接在http块里写多个server二是把每个站点单独写成一个文件放在/etc/nginx/conf.d/下并在主配置里include它们。推荐后面这种配置多了好管理。3.2 配置一个静态站点假设你的网站根目录在/var/www/myapp里面放了一个index.html你想让用户通过域名或者IP访问。在/etc/nginx/conf.d/myapp.conf里写server { listen 80; server_name myapp.com www.myapp.com; root /var/www/myapp; index index.html index.htm; location / { try_files $uri $uri/ 404; } access_log /var/log/nginx/myapp_access.log; error_log /var/log/nginx/myapp_error.log; }然后测试并重载配置nginx -t nginx -s reload这里server_name是域名匹配如果你不想用域名直接用IP访问可以写成server_name _;表示匹配所有请求。try_files用于先按$uri找文件找不到再按$uri/找目录都没有就返回404这是常见的静态站点配置。如果你是配置WordPress这类PHP站点还需要把location ~ \.php$的请求转发给PHP-FPM这里不展开但思路是一样的。3.3 反向代理与负载均衡配置反向代理是我用得最多的功能。比如你的后端有个Spring Boot应用跑在8080端口你希望用户访问80端口不用感知到8080就可以这样配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_pass转发目标地址可以写IP、域名、端口也可以写unix socket。proxy_set_header把客户端的原始信息转发给后端特别是Host和X-Forwarded-For后端才能正确拿到真实IP。如果后端的接口涉及WebSocket还需要额外配置Upgrade和Connection头。负载均衡其实也很简单。比如你有三台后端服务器可以定义一组upstreamupstream backend { server 192.168.1.10:8080 weight3; server 192.168.1.11:8080 weight1; server 192.168.1.12:8080 down; } server { listen 80; server_name load.example.com; location / { proxy_pass http://backend; } }weight表示权重数值越大分配到的请求越多down表示暂时不参与负载。默认的负载均衡策略是轮询还可以用least_conn最少连接、ip_hash客户端IP哈希等算法。比如需要会话保持时用ip_hash就能让同一个IP的请求始终打到同一台后端。3.4 配置SSL证书与“替换证书不生效”的排查现在站点基本都要上HTTPS。Nginx配置SSL证书并不复杂前提是你编译或安装的版本带http_ssl_module。可以用nginx -V查看nginx -V 21 | grep http_ssl_module如果输出里有--with-http_ssl_module说明支持。假设你的证书文件是example.com.pem和example.com.key放到/etc/nginx/ssl/目录下然后在server块里增加监听443和证书配置server { listen 443 ssl http2; server_name example.com; ssl_certificate /etc/nginx/ssl/example.com.pem; ssl_certificate_key /etc/nginx/ssl/example.com.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; root /usr/share/nginx/html; index index.html; }如果你同时要支持HTTP自动跳转HTTPS可以再加一个server块server { listen 80; server_name example.com; return 301 https://$host$request_uri; }配置好之后测试并重载nginx -t nginx -s reload很多同学会遇到“我换了新的SSL证书nginx -s reload也执行了但浏览器还是报旧证书”的问题。这里我重点说一下排查思路。首先nginx -s reload其实是平滑重载配置会重新读取被引用的证书文件。但是为什么你看着没生效通常原因有这几个证书路径没换但证书文件内容没真正更新。比如你覆盖了.pem文件但.key私钥没同步替换或者证书链不完整。这时可以先用openssl检查证书内容是否是你期望的新证书openssl x509 -in /etc/nginx/ssl/example.com.pem -noout -dates -subject -issuer如果显示的签发者等信息还是旧的说明文件没有更新成功。浏览器或客户端缓存。有些浏览器会缓存证书状态尤其是iOS和部分Android浏览器。需要强制刷新或用无痕模式测试也可以先用curl -v https://example.com 21 | grep subject:看服务端实际返回的证书信息。你改错配置文件了。很多服务器上配置了多个nginx实例或者nginx.conf里include了多个配置文件你改了一个文件但真正生效的server块在另一个文件里。可以用nginx -T大写T把所有生效的配置完整输出然后搜索证书路径确认实际使用的是哪个文件。nginx -s reload没有真正执行成功。如果你改了配置但reload完成后控制台提示[emerg] unknown directive之类的错误其实新配置没有生效。这时候一定要先nginx -t确保语法无误。可能你装了多个版本的Nginx比如系统自带的Nginx和源码编译的Nginx同时存在你执行reload的是其中一个而实际监听443端口的是另一个。可以用lsof -i:443或者ss -tlnp | grep 443查看哪个进程在监听。总之替换证书不生效九成是路径、文件内容、刷新时机这三个因素之一。按上面几步排查基本都能解决。4. 常见问题与排查技巧实录4.1 端口被占用bind() to 0.0.0.0:80 failed启动Nginx时如果报[emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)说明80端口被其他程序占了。最常见的占用者是Apache、httpd或者其他Nginx进程。查看占用进程sudo lsof -i:80或者sudo ss -tlnp | grep :80如果是Apache占用停掉它并关闭开机自启sudo systemctl stop httpd sudo systemctl disable httpd如果80端口被另一个Nginx进程占用先确认是不是你自己的旧进程如果是直接nginx -s stop后再启动。如果你确实有别的程序要用80端口那就在Nginx配置里改监听端口比如listen 8080;。但一般不建议改因为用户访问默认端口80更方便。4.2 worker进程以root运行或权限不足有时候你会看到Nginx主进程是root但worker进程以nginx用户运行这是正常设计。但如果你的网站目录设置了过严的权限Nginx读取不到文件就会返回403 Forbidden。排查权限问题先看目录权限ls -ld /path/to/site ls -l /path/to/site/index.htmlNginx worker进程需要能进入目录x权限并能读取文件r权限。如果你不确定可以简单点把网站目录属主改为nginxsudo chown -R nginx:nginx /var/www/myapp或者给目录添加执行权限sudo chmod 755 /var/www/myapp sudo chmod 644 /var/www/myapp/index.html注意如果网站目录在某个挂载的NAS或特殊文件系统上可能还需要检查SELinux。在CentOS/RHEL上SELinux默认开启如果网页文件是从home目录或外部存储同步过来的Nginx可能会被SELinux拦截。查看SELinux上下文ls -Z /var/www/myapp如果发现类型是home_root_t等而不是httpd_sys_content_t可以用chcon或restorecon修复sudo restorecon -Rv /var/www/myapp这一条很多人不知道但遇到403且权限正常时多半就是SELinux的问题。4.3 nginx -t报错unknown directive xxx配置语法错误的常见原因大概有几类少写了分号、引号不匹配、括号没闭合、指令名写错。比如server_name写成了serverName或者location块里忘记写proxy_pass后的分号。遇到这类报错先看提示的行号打开配置文件那一行附近检查。这里分享一个小技巧写配置时尽量用缩进块与块之间空一行不但在视觉上清晰也容易检查括号配对。每次都养成先nginx -t再reload的习惯。另外有些指令只在特定模块里才有比如http2指令如果你编译时没启用--with-http_v2_module就会报unknown directive http2这时要么改配置去掉该指令要么重新编译Nginx加入模块。4.4 改了配置不生效没有执行reload很多新手改完nginx.conf后刷新页面发现没变化因为Nginx的主配置文件在启动时已经读入内存修改文件本身不会自动生效。修改配置后必须让主进程重新加载配置nginx -s reload或者让systemd重载sudo systemctl reload nginx注意reload和restart不同。reload是不中断服务的平滑重载worker进程会逐步替换restart是直接停止再启动会有短暂断流。生产环境一般用reload。另外如果你改了include进来的文件也需要reload。如果你改了站点目录下的文件内容比如替换了html页面那不需要reload因为静态文件是每次请求时实时读取的。4.5 访问日志和错误日志怎么用遇到访问异常第一件事就是看日志。错误日志默认在/var/log/nginx/error.log访问日志在/var/log/nginx/access.log。比如你配置了HTTPS但访问时出现握手失败错误日志里会明确写出证书相关的问题。看最近几十行sudo tail -n 50 /var/log/nginx/error.log如果日志中频繁出现connect() failed (111: Connection refused)说明Nginx反代的后端服务没启动或端口不对。出现Upstream timed out说明后端响应太慢可能需要加大proxy_read_timeout。我每次排障都是这个思路先看Nginx是否能正常运行systemctl status然后看配置是否正确nginx -t再看端口是否监听ss -tlnp最后看错误日志。这套流程下来90%的问题都能定位。4.6 其他高频问题速查现象常见原因解决办法访问出现400 Bad Requestserver_name配置错误或请求头过大检查server_name必要时调大client_header_buffer_size上传文件超过限制报413client_max_body_size默认1m在server或location中设置client_max_body_size 20m;访问出现502 Bad Gateway后端服务不可用或超时检查后端端口查看错误日志访问出现504 Gateway Timeout后端处理超时调大proxy_read_timeout优化后端磁盘空间不足导致日志写入失败/var/log分区满了清理日志配置logrotate5. 日常运维与性能调优5.1 日志切割与定时清理Nginx自身不提供日志切割功能如果日志文件一直写会越来越大最终占用整个磁盘。Linux自带的logrotate可以完美解决。系统安装Nginx后通常会生成/etc/logrotate.d/nginx配置里面默认按天切割并保留一定份数。你可以检查一下cat /etc/logrotate.d/nginx如果默认配置不存在可以自己写一个/var/log/nginx/*.log { daily missingok rotate 14 compress delaycompress notifempty create 0640 nginx adm sharedscripts postrotate [ -f /var/run/nginx.pid ] kill -USR1 cat /var/run/nginx.pid endscript }这个配置表示每天切割一次日志保留14天压缩旧日志。切割后通知Nginx重新打开日志文件kill -USR1是Nginx官方推荐的方式不会中断服务。5.2 gzip压缩与缓存配置优化静态资源加载速度最直接的是开启gzip。在http块中加入gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xmlrss image/svgxml; gzip_min_length 1024; gzip_comp_level 5;gzip_min_length表示小于1KB的文件不压缩因为压缩小文件反而增加开销gzip_comp_level是压缩级别1到9级别越高越耗CPU5是性能和压缩率的平衡点。如果是静态资源还可以配置浏览器缓存location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ { expires 30d; add_header Cache-Control public, no-transform; }这样用户第二次访问时就直接读取本地缓存节省带宽。注意涉及版本更新的资源文件名里最好带hash否则缓存可能会让用户加载到旧文件。5.3 worker进程和连接数调优高并发场景下Nginx的worker_processes和worker_connections需要调一调。最简单的设置worker_processes auto; events { worker_connections 10240; }worker_processes auto会自动识别CPU核心数。worker_connections表示每个worker能同时处理的连接数调大可以提升并发能力。但也不是越大越好它受限于系统文件描述符上限。你需要先确认系统支持的最大打开文件数ulimit -n如果只有1024可能不够。可以在/etc/security/limits.conf里修改或者通过systemd服务文件里的LimitNOFILE来调整。一般我会把worker_connections设为5120或10240同时把worker_rlimit_nofile也调大worker_rlimit_nofile 65535;这个指令设置worker进程的最大打开文件数配合worker_connections一起改才能真正提升并发上限。另一个需要注意的是keepalive_timeout。如果业务是短连接比如移动端APIkeepalive_timeout设个30秒就够如果是网页访问可以设65。太长的keepalive会占用连接资源太短则增加握手开销。5.4 健康检查与后端摘除在负载均衡中如果某台后端挂了默认情况下Nginx仍然会把请求转发过去直到超时报错。可以在upstream中开启主动健康检查Nginx Plus支持但开源版没有主动健康检查模块。开源版可以用max_fails和fail_timeout控制被动健康检查upstream backend { server 192.168.1.10:8080 max_fails3 fail_timeout30s; server 192.168.1.11:8080 max_fails3 fail_timeout30s; }意思是如果30秒内连续失败3次就把这台后端标记为不可用30秒后再重新试探。这个参数非常实用能自动摘除故障节点。加上它你的负载均衡配置才算完整。最后再分享点个人经验上面这些内容基本覆盖了Linux下安装配置Nginx从入门到能用的全过程。如果你想把Nginx用得更好我建议多熟悉一下location的匹配规则和proxy_pass的细节这是最容易踩坑的两块。比如proxy_pass后面是否带斜杠会导致不同的URI拼接结果网上有很多例子一定要亲自动手试一遍。还有一件事别把server块写的太复杂一个站点一个配置文件命名清晰注释写明白绝对是以后省心的关键。我见过把十几个server块全塞在一个文件里的服务器后来维护的人改一个配置都要小心翼翼。配置文件也是代码保持简洁和规范能让你的Linux运维生涯少很多麻烦。如果你现在正打算在自己的服务器上装Nginx别犹豫照着上面的步骤走一遍遇到问题就翻翻日志一定能跑起来。