ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Nginx从入门到实战:安装配置、反向代理与性能调优全指南

Nginx从入门到实战:安装配置、反向代理与性能调优全指南 1. 项目概述与环境准备1.1 为什么要用Nginx它能解决什么问题在Linux服务器上部署Web服务Nginx几乎是绕不开的一个名字。不管是搭建个人博客、部署前后端分离项目还是给已有服务做反向代理Nginx凭借高并发、低内存占用和灵活的配置方式长期占据Web服务器市场的主流位置。我用Nginx也有好几年了从最初只在虚拟机里跑个静态页面到后来给生产环境做负载均衡坦白说它确实是Linux运维和开发人员都必须掌握的基础技能。这篇内容不打算把Nginx官方文档搬一遍而是按照“装好—跑通—配好—用起来”这条主线把我在实际操作中验证过的步骤和踩过的坑一起写出来。适合看这篇文章的读者有两类一类是刚接触Linux想在本地虚拟机或云服务器上把Nginx跑起来的新手另一类是已经能跑通基础服务但在多站点配置、反向代理这些场景下还不太熟练的同学。我会尽量把每一步的原理和实际操作都讲清楚保证照着做就能复现。1.2 动手前的系统准备工作在开始安装Nginx之前先把基础环境确认清楚能省掉后面不少麻烦。无论你用的是Ubuntu、Debian还是CentOS核心准备步骤基本一致。先检查系统版本和架构确认自己的环境cat /etc/os-release uname -m这一步不是走形式因为不同Linux发行版使用的包管理器不同安装命令也有差别。比如Ubuntu/Debian用aptCentOS/RHEL用yum或dnf如果搞混了大概率会碰到“找不到软件包”这类报错。接着更新系统软件源确保可以获取到最新的软件包列表sudo apt update sudo apt upgrade -y # Ubuntu/Debian sudo yum update -y # CentOS/RHEL然后确认编译工具是否齐全。如果你是打算用源码编译安装Nginx后面会详细讲那么gcc、make、libpcre3-dev、zlib1g-dev、libssl-dev这几个依赖缺一不可。用二进制包安装的话这些可以先不管等编译时再装也行但提前装好也不吃亏。最后检查一下80端口是否被占用。Nginx默认监听80端口如果端口冲突后面启动会报错。可以用下面的命令提前排查sudo ss -tlnp | grep :80如果80端口已经被其他进程占用要么先停掉那个服务要么等配置Nginx时把端口改成8080之类的其他值。我建议新手第一次安装时保持默认的80端口等理解整个流程后再去做端口修改这样排查问题时更简单。2. 从零开始Nginx安装的两种主流方式2.1 极速上手用系统包管理器一键安装如果你是第一次接触Nginx我建议先用系统自带的包管理器安装。这种方式操作简单、依赖自动处理而且后续卸载也比较干净。Ubuntu/Debian系统执行sudo apt install nginx -yCentOS/RHEL系统执行sudo yum install nginx -y安装完成后验证是否装好nginx -v正常会输出类似nginx version: nginx/1.18.0 (Ubuntu)的信息。这里注意不同系统的Nginx版本可能不太一样Ubuntu通常自带的是1.18左右CentOS自带的可能更老一些。版本差异对基本使用影响不大但如果后面想用比较新的特性比如HTTP/3、更细粒度的限流配置就需要考虑源码编译安装了。启动Nginx服务并设置开机自启sudo systemctl start nginx sudo systemctl enable nginx然后打开浏览器访问http://你的服务器IP看到Nginx默认欢迎页面就说明服务已经跑起来了。这种方式最大的好处是快装完就能用。但缺点也比较明显一是版本可能不是最新的二是默认安装的模块可能缺一些你需要的功能。如果只是学习或跑常规业务二进制安装完全够用如果需要定制模块那就接着看下面这种安装方式。2.2 进阶首选源码编译安装Nginx源码编译安装的灵活性是二进制安装比不了的你可以自由选择要编译哪些模块也可以指定安装路径还能用上最新版本的特性和性能优化参数。第一步安装编译依赖库。Ubuntu系统执行sudo apt install build-essential libpcre3-dev zlib1g-dev libssl-dev -yCentOS执行sudo yum install gcc gcc-c make pcre-devel zlib-devel openssl-devel -y第二步下载Nginx源码包。去Nginx官网下载最新的稳定版这里用nginx-1.24.0举例cd /usr/local/src wget https://nginx.org/download/nginx-1.24.0.tar.gz tar -zxvf nginx-1.24.0.tar.gz cd nginx-1.24.0第三步配置编译参数。这一步是整个源码安装的核心参数决定Nginx安装到哪个目录、启用哪些模块./configure --prefix/usr/local/nginx \ --with-http_ssl_module \ --with-http_v2_module \ --with-http_realip_module \ --with-http_stub_status_module \ --with-stream简单解释一下关键参数的含义--prefix指定安装目录。默认是/usr/local/nginx所有Nginx相关文件都会放在这个目录下方便统一管理。--with-http_ssl_module启用HTTPS支持。现在不装SSL模块后面配置证书的时候就没法用。--with-http_v2_module启用HTTP/2协议对性能优化很有帮助。--with-stream启用TCP/UDP代理转发功能可以做四层负载均衡。--with-http_stub_status_module提供Nginx运行状态监控页面运维排查时很有用。第四步编译并安装make -j$(nproc) sudo make install-j$(nproc)的意思是让编译过程使用CPU的所有核心并行处理能显著加快编译速度。我第一台机器配置比较低没加这个参数编译nginx差不多等了快十分钟后来加了并行参数几分钟内就搞定了。安装完成后Nginx可执行文件在/usr/local/nginx/sbin/nginx配置目录在/usr/local/nginx/conf/nginx.conf。启动命令sudo /usr/local/nginx/sbin/nginx源码编译这种方式本质上就是“按需定制”的思路——你需要什么功能就在configure阶段声明编译器把对应的模块一起打包进可执行文件。这也解释了为什么源码安装的Nginx在性能上通常优于系统自带包因为里面没有用不到的模块拖累。提示如果你不确定自己需要哪些模块建议先跑一遍./configure --help看看所有可选项再结合自己的业务场景做取舍。3. 配置实战从默认页面到自定义站点3.1 全面认识nginx.conf核心配置装好Nginx之后最重要的事情就是理解配置文件。Nginx的所有行为都是由配置文件控制的搞懂它你就掌握了Nginx的驾驶舱。默认配置文件位于/etc/nginx/nginx.conf二进制安装或/usr/local/nginx/conf/nginx.conf源码编译安装下面拆开讲。Nginx配置文件的核心结构可以分成三大块全局块控制Nginx进程的全局属性。events块配置连接处理属性。http块配置HTTP服务相关属性包含server块、location块。看一个典型的配置骨架# 全局块 user nginx; worker_processes auto; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; # events块 events { worker_connections 1024; } # http块 http { include /etc/nginx/mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; # server块 server { listen 80; server_name localhost; # location块 location / { root /usr/share/nginx/html; index index.html index.htm; } } }几个比较关键的参数值得展开说worker_processes设置Nginx的工作进程数。设置为auto会让Nginx自动匹配CPU核心数这是最优配置。它的原理是一个工作进程处理一组连接多核CPU配合多进程才能把性能跑满。worker_connections每个工作进程能同时保持的最大连接数。默认1024对大多数中小业务够用。如果并发量很高可以适当调大但要注意服务器的文件描述符上限否则设置不生效。include的作用是引入外部配置文件。为什么要拆开来写因为随着站点增多如果把所有server块全部堆在nginx.conf里文件很快就会变成一团乱麻。Nginx的设计哲学是“约定优于配置”通过include /etc/nginx/conf.d/*.conf这种方式把不同站点的配置拆成独立文件管理起来清晰得多。3.2 手把手配置第一个自定义站点接下来就动手配置一个实际能访问的站点。假设我们要把项目放在/var/www/mysite目录下通过mysite.com这个域名访问。第一步创建网站根目录并写入测试页面sudo mkdir -p /var/www/mysite echo h1Hello Nginx/h1 | sudo tee /var/www/mysite/index.html第二步创建站点配置文件。注意不要直接改nginx.conf而是新建单独的配置文件推荐放在/etc/nginx/conf.d/目录下sudo vim /etc/nginx/conf.d/mysite.conf写入如下内容server { listen 80; server_name mysite.com www.mysite.com; root /var/www/mysite; index index.html index.htm; location / { try_files $uri $uri/ 404; } }第三步检查配置语法并重载sudo nginx -t sudo systemctl reload nginxnginx -t这条命令是检查语法用的非常重要。我每次写配置都会先跑一遍确认没有语法错误再重载服务。第四步配置本地域名解析。如果你没有购买真实域名想在本地测试可以修改/etc/hosts文件echo 127.0.0.1 mysite.com | sudo tee -a /etc/hosts然后浏览器访问http://mysite.com就能看到“Hello Nginx”页面。这里解释一下server_name和root的关系server_name是匹配用户请求的域名root是告诉Nginx去哪里找网页文件。用户的浏览器访问mysite.com时Nginx接收到请求检查server_name是否匹配匹配后就去root指定的目录找对应文件返回给用户。整个流程可以用一个生活场景来类比server_name相当于小区门口的门牌号root相当于住户家里的柜子。门卫Nginx看到访客报的门牌号确认是这个小区的然后去对应的柜子里拿东西给访客。3.3 location匹配规则深度解析location是Nginx配置里最常用也最容易被误解的部分。我可以负责任地说搞懂了location你就搞懂了大半个Nginx的URL路由逻辑。看一个具体的例子server { listen 80; server_name example.com; location / { # 通用匹配 proxy_pass http://backend; } location /favicon.ico { # 精确匹配 log_not_found off; access_log off; } location ~ \.(gif|jpg|png|css|js)$ { # 正则匹配 expires 7d; } location ^~ /api/ { # 前缀匹配 不再检查正则 proxy_pass http://api_backend; } }Nginx在匹配location时实际上有一套严格优先级流程顺序如下精确匹配location /path完全等于指定路径的请求命中后立即生效不再继续匹配。前缀匹配location ^~ /path匹配指定前缀命中后跳过正则匹配检查。正则匹配location ~ /path或location ~* /path按配置文件中的书写顺序逐一匹配正则。最长前缀匹配location /path匹配最长的前缀路径作为兜底方案。简单理解就是Nginx先跑精确匹配不行再看有没有带^~的前缀匹配还不行就按顺序跑正则最后再用最长前缀匹配兜底。举个例子帮你加深印象。假设有一个请求GET /api/user?id1先检查location /api/user?id1没有这样的精确匹配。再检查location ^~ /api/匹配成功且带^~直接使用这个配置不再往下验证正则。最终请求进入proxy_pass http://api_backend。这个优先级机制在实际业务中非常关键。比如你把静态资源的正则规则写在/的通用匹配后面但有个API前缀请求也匹配了某个静态资源正则那就可能把API请求错误地转发到静态资源服务去了。这类问题排查起来费时费力最好的办法就是写配置时心里先过一遍优先级顺序。注意在正则匹配中~区分大小写~*不区分大小写。实际配置时尽量使用~*匹配图片、CSS、JS这类扩展名避免因为大小写问题导致静态资源加载失败。4. 常见透传场景与进阶配置实战4.1 反向代理把请求转发给后端服务Nginx最常见的用途之一是反向代理。简单来说反向代理就是Nginx作为“中间人”接收用户的请求再转给局域网内的后端服务处理最后把结果返回给用户。用户只知道Nginx存在看不到后端服务的真正地址。真实场景举例你在服务器上用localhost:8080跑了一个Java应用但这端口不能直接暴露给公网用户这时就用Nginx把80端口的请求转发到8080。用户访问http://example.comNginx收到请求后转给http://localhost:8080处理。配置方法server { listen 80; server_name 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; } }这里有几个参数需要重点理解proxy_pass指定后端服务的地址。可以填IP、域名或upstream定义的负载均衡组。proxy_set_header在转发请求时修改或添加请求头。Host保持原始域名这样后端应用才能正确识别用户访问的域名X-Real-IP和X-Forwarded-For用于传递用户真实IP。为什么后端需要通过X-Forwarded-For获取用户IP因为Nginx转发请求时后端看到的来源IP永远是Nginx所在服务器的IP。如果不把这些头信息传过去后端的日志、安全策略都无法获取用户的真实IP这在分析访问来源和封禁恶意IP时会非常麻烦。4.2 本地虚拟机多站点域名配置很多人在本地开发阶段需要同时跑多个站点比如一个前端项目、一个后端API、一个管理后台。如果全部塞在同一个Nginx下就需要依赖server_name来区分不同域名。我在开发中常用的方案是这样的宿主机和虚拟机配合在/etc/hosts里自定义域名然后指向虚拟机的IP。举个例子我在VirtualBox里跑了一台Ubuntu虚拟机IP是192.168.56.101宿主机访问它时需要配置Nginx支持多个server块。先在/etc/nginx/conf.d/下建立多个配置文件# frontend.conf server { listen 80; server_name front.dev; root /var/www/frontend/dist; index index.html; }# api.conf server { listen 80; server_name api.dev; location / { proxy_pass http://127.0.0.1:8000; } }然后在宿主机比如Windows或Mac的hosts文件添加映射192.168.56.101 front.dev 192.168.56.101 api.dev这样浏览器访问http://front.dev时请求会被发送到虚拟机的80端口Nginx根据server_name匹配到对应的server块返回正确的站点。这里有一个很值得注意的配置细节如果你的项目前后端分离前端项目通过fetch(/api/login)请求后端接口而这个/api路径需要在Nginx层做个转发。这时候不要在前端代码里写死IP而是利用Nginx的location /api/转发规则server { listen 80; server_name front.dev; root /var/www/frontend/dist; index index.html; location /api/ { proxy_pass http://127.0.0.1:8000/; proxy_set_header Host $host; } }注意这里的proxy_pass末尾带不带/是有讲究的带/相当于http://127.0.0.1:8000/会把/api/前缀去掉后转发。比如请求/api/user转发给后端的是/user。不带/保留原始路径。比如请求/api/user转发给后端的是/api/user。后端接口定义的是/api/user还是/user决定了你选哪种方式。如果后端没有统一加/api前缀就选带/的那种把前缀去掉再转发。4.3 配置HTTPS让站点更安全现在的站点几乎都要上HTTPS否则浏览器会直接打出“不安全”的警告。Nginx配置HTTPS主要分两步获取SSL证书、修改配置加载证书。免费证书最常用的是Let‘s Encrypt也可以用acme.sh脚本自动申请。这里不展开讲申请过程重点讲拿到证书后怎么配置。假设你的证书文件放在/etc/nginx/ssl/目录下私钥和证书分别是example.com.key和example.com.pem配置如下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_ciphers HIGH:!aNULL:!MD5; location / { root /var/www/example; index index.html; } } # HTTP跳转HTTPS server { listen 80; server_name example.com; return 301 https://$server_name$request_uri; }拆分一下要点listen 443 ssl http2;表示监听443端口开启SSL和HTTP/2协议。HTTP/2可以多路复用请求页面加载速度有肉眼可见的提升。ssl_protocols和ssl_ciphers是安全性配置建议只启用TLSv1.2及以上版本。老旧的TLSv1.0、TLSv1.1存在已知漏洞开启它们等于把门留了一条缝。最后一个server块的作用是强制HTTP跳转HTTPS。用户访问http://example.com时收到301状态码浏览器自动跳到https://example.com。这个写法几乎成了标配凡是做了HTTPS的站点基本都会加上。我踩过一个比较典型的坑替换SSL证书后用nginx -t检查语法没问题但浏览器还是提示证书无效。后来排查发现是Nginx进程没有重新加载证书。解决方案是必须用systemctl reload nginx而不是systemctl restart nginx重启。这里区别在于restart是完全停止再启动进程而reload是平滑加载让旧进程处理完手头请求再退出新配置才会生效。如果改了证书但reload没做对旧证书会一直生效浏览器自然报错。4.4 给静态资源做缓存与压缩对于图片、CSS、JS等静态资源通过Nginx层做缓存和压缩能显著提升页面加载速度。缓存的核心思路是告诉浏览器这些文件在多久内不需要重新请求。location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ { expires 30d; add_header Cache-Control public, no-transform; }expires 30d的意思是这些静态资源让浏览器缓存30天。在这个周期内用户再次访问同一资源浏览器直接从本地缓存加载不再发请求服务端。我实测过静态资源占比高的站点开启这个配置后带宽消耗能下降一半以上。再说压缩。Nginx开启gzip压缩能让传输体积减少60%到70%尤其对纯文本类内容效果显著gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xmlrss text/javascript; gzip_min_length 1024; gzip_comp_level 6;gzip_min_length表示只有超过1KB的文件才压缩太小的文件压缩后反而可能变大。gzip_comp_level是压缩级别范围1-96是一个性能和压缩率的平衡点。级别太高CPU开销上升明显但对大多数机器来说压缩收益远大于CPU成本。5. 日常运维排查问题与性能调优5.1 高频问题速查从日志到状态码配置过程中难免踩坑这里把最常见的几个问题和排查思路整理成一个表格方便你直接对症下药。现象常见原因排查思路nginx -t报语法错误配置少了分号、括号不匹配看报错提示的行号逐行检查启动失败提示Address already in use80端口被占用ss -tlnp查看占用进程停掉或改端口访问返回403目录权限不足或缺少index文件检查root目录权限是否755文件是否存在访问返回404location匹配与root路径不一致检查root和实际文件的路径关系访问返回502后端服务挂了或proxy_pass地址不可达直接curl http://127.0.0.1:8080测试后端访问返回504后端响应超时调整proxy_read_timeout参数替换证书不生效reload未执行或路径错误确认证书路径执行systemctl reload nginx日志永远是排查问题的第一入口。Nginx的日志分两类访问日志和错误日志默认位置在/var/log/nginx/access.log和/var/log/nginx/error.log。当页面报错时先看tail -f /var/log/nginx/error.log通常能直接定位到问题。5.2 性能调优用最少的资源支撑更多请求一个Nginx进程能支撑的并发数取决于配置和系统参数。结合我实际调优的经验分享几个立竿见影的参数。调整worker_processes和worker_connectionsworker_processes auto; worker_rlimit_nofile 65535; events { worker_connections 4096; use epoll; }worker_rlimit_nofile设置每个进程能打开的最大文件描述符数。worker_connections乘以worker_processes就是理论最大并发连接数。use epoll是Linux 2.6以上内核推荐的事件驱动模型性能远高于默认的select。开启keepalive长连接keepalive_timeout 65; keepalive_requests 1000;长连接的好处是同一个客户端可以在这个连接上发送多个请求不需要每次请求都重新握手。对静态资源多的站点这个配置能大幅度降低TCP握手带来的延迟。日志写入优化access_log /var/log/nginx/access.log main buffer32k flush5s;buffer32k是让Nginx攒够32KB日志再写一次磁盘flush5s是超过5秒强制刷一次。好处是减少磁盘IO次数在高并发场景下能明显降低磁盘压力。不过日志实时性会稍微降低排查问题时要注意这个延迟。5.3 用stub_status模块监控运行状态如果编译的时候加了--with-http_stub_status_module二进制安装一般默认带可以通过Nginx内置的接口实时查看运行状态。在配置里增加一个locationlocation /nginx_status { stub_status on; access_log off; allow 127.0.0.1; deny all; }然后访问http://你的IP/nginx_status会输出类似下面的内容Active connections: 2 server accepts handled requests 12345 12345 56789 Reading: 0 Writing: 1 Waiting: 1字段含义Active connections当前活跃连接数。accepts/handled/requests自Nginx启动以来的总连接数、总握手数、总请求数。正常情况accepts和handled应该相等。Reading正在读取请求头的连接数。Writing正在响应请求的连接数。Waiting保持空闲长连接的连接数。Waiting数值高是正常现象说明有很多长连接在待命能快速响应后续请求。Reading或Writing长期高企则说明后端处理能力不足需要排查瓶颈。6. 一段关于“为什么这样配置”的总结思考回头看看整个Nginx的安装和配置流程最值得记在心里的其实不只是命令和参数而是Nginx的设计思路一切皆配置配置即代码。从编译安装时的模块选择到运行时的每个location规则都能通过配置文件精确控制。这种风格和很多现代基础设施工具是一脉相承的。我个人的习惯是每次配置完一个Nginx服务都把nginx -t的检查结果和最终生效的配置片段留档记录。遇到问题先在error.log里找线索再回头审视配置文件基本能解决九成以上的问题。真正复杂的场景比如多级代理、负载均衡权重调整也都是在这套基础配置之上做加法。如果在实际操作中遇到这里没提到的情况多敲两遍nginx -h看看官方帮助或者翻一下/etc/nginx/目录下的注释文档Nginx的官方注释做得相当详细很多时候答案就藏在那些注释里。
返回列表