nginx概念及使用
一、Nginx 核心概念
Nginx(发音为 "engine-x")是一个高性能、开源的 Web 服务器和反向代理服务器,由俄罗斯工程师伊戈尔・赛索耶夫(Igor Sysoev)于 2004 年开发,最初用于解决当时高并发场景下 Apache 服务器的性能瓶颈问题。
核心特点:
- 高并发低资源消耗:采用异步非阻塞(epoll/kqueue)的事件驱动模型,单台服务器可轻松处理数万并发连接,内存占用仅几十 MB(对比 Apache 的进程 / 线程模型,资源消耗更高)。
- 模块化设计:核心功能通过模块化扩展(如 HTTP、邮件代理、TCP/UDP 代理),支持动态加载模块(需编译时启用)。
- 反向代理与负载均衡:原生支持反向代理、负载均衡(轮询、权重、IP 哈希、最少连接等策略),是微服务架构中 API 网关的常见选择。
- 静态资源处理高效:对静态文件(HTML/JS/CSS/ 图片)的响应速度远超 Apache,支持文件缓存、压缩(gzip/brotli)、范围请求(断点续传)。
- 高可靠性:支持热重载(nginx -s reload),修改配置无需重启服务;Worker 进程独立运行,单个进程崩溃不影响整体服务。
二、Nginx 典型应用场景
Nginx 凭借其性能优势,广泛应用于以下场景:
1. 静态 Web 服务器
作为静态资源(HTML / 图片 / 视频)的托管服务器,比 Apache 更高效。例如:托管企业官网、前端框架(React/Vue)构建的静态站点。
2. 反向代理服务器
反向代理是 Nginx 最核心的用途之一:客户端请求先到 Nginx,由 Nginx 转发到后端真实服务器(如 Tomcat/Node.js/PHP-FPM),隐藏后端服务器细节,提升安全性。
3. 负载均衡器
通过配置多台后端服务器,Nginx 可将请求按策略(轮询、权重、IP 哈希等)分发给不同服务器,避免单节点压力过大,提升系统可用性。
4. API 网关
结合 Nginx 的请求路由、协议转换(HTTP/HTTPS)、流量控制(速率限制)、安全过滤(请求头修改、黑白名单)等功能,作为微服务架构的入口网关。
5. HTTP 缓存服务器
通过proxy_cache指令缓存后端服务器的响应结果,减少重复请求对后端的压力,提升用户访问速度(如缓存静态资源或高频动态接口)。
三、Linux 系统安装 Nginx
方式 1:通过包管理器安装(推荐)
# 更新包索引 sudo apt update # 安装Nginx sudo apt install nginx -y # 启动服务并设置开机自启 sudo systemctl start nginx sudo systemctl enable nginx
方式 2:源码编译安装(自定义功能)
适合需要定制模块(如ngx_http_ssl_module/ngx_http_realip_module)或更高版本的场景:
# 安装依赖 sudo apt install gcc make libpcre3-dev zlib1g-dev openssl-dev -y # Ubuntu # 或 sudo yum install gcc make pcre-devel zlib-devel openssl-devel -y (CentOS) # 下载源码(以1.24.0版本为例) wget https://nginx.org/download/nginx-1.24.0.tar.gz tar -zxvf nginx-1.24.0.tar.gz cd nginx-1.24.0 # 配置编译参数(启用SSL、gzip等模块) ./configure \ --prefix=/usr/local/nginx \ # 安装路径 --with-http_ssl_module \ # 启用HTTPS支持 --with-http_gzip_static_module \ # 启用gzip静态压缩 --with-http_realip_module # 启用真实IP获取(反向代理场景) # 编译并安装 make && sudo make install
例如我的./configure如下:
./configure --prefix=/usr/local/nginx --with-http_realip_module --with-http_addition_module --with-http_ssl_module --with-http_gzip_static_module --with-http_secure_link_module --with-http_stub_status_module --with-stream --with-pcre=/home/jerry/snap/nginx/pcre-8.45 --with-zlib=/home/jerry/snap/nginx/zlib-1.2.13 --with-openssl=/home/jerry/snap/nginx/openssl-1.1.1s
四、Nginx 核心配置解析
Nginx 的配置文件默认位于 /etc/nginx/nginx.conf(包管理器安装)或 /usr/local/nginx/conf/nginx.conf(源码安装),采用模块化层级结构,核心包含 3 大块:
1. 主配置块(main)
全局配置,影响所有模块,例如:
user www-data; # 运行Nginx的用户/用户组(Ubuntu默认www-data) worker_processes auto; # Worker进程数(建议设置为CPU核心数,auto自动检测) error_log /var/log/nginx/error.log warn; # 错误日志路径及级别(debug/info/warn/error) pid /run/nginx.pid; # 主进程PID文件路径 # 事件模块配置(events块) events { worker_connections 1024; # 每个Worker进程最大并发连接数 use epoll; # 指定事件驱动模型(Linux推荐epoll,FreeBSD用kqueue) }
当 worker_processes auto; 配置下开启四个进程(worker),且 Nginx 配置文件监听四个端口(9000~9003)时,完整连接处理过程如下:
-
Nginx 启动阶段
- Master 进程读取配置文件,创建 9000~9003 端口的监听套接字(fd),并开始监听。
- Master 进程通过 fork() 生成四个 worker 进程。每个 worker 进程继承 master 的监听套接字(fd),此时所有 worker 进程共享这四个端口的监听。
-
连接请求到达时
- 当客户端向某一端口(如 9000)发起连接请求,内核通过负载均衡机制(如 SO_REUSEPORT 特性避免惊群效应)选择一个 worker 进程处理该连接。
- 被选中的 worker 进程调用 accept() 接受连接,生成新的连接套接字(fd),并将该 fd 添加到自身的 epoll 实例中管理。
- 后续该连接的读 / 写事件由该 worker 进程通过 epoll 监听和处理(如读取客户端请求、返回响应等)。
-
多端口与负载均衡
- 对于 9001~9003 端口,流程类似:每个端口的连接请求由内核分配给某个 worker 进程,worker 进程处理连接并通过自身 epoll 管理。
- 四个 worker 进程各自独立维护自己的 epoll 实例,分别处理不同端口的连接请求,实现多进程并发处理,充分利用多核性能。
-
事件循环与资源管理
- 每个 worker 进程在自己的事件循环中通过 epoll 监听连接套接字的事件(如可读、可写)。
- 当连接关闭或发生异常时,worker 进程从 epoll 中移除对应 fd,并释放相关资源。
2. HTTP 块(http)
定义 HTTP 相关的核心功能,如虚拟主机、反向代理、缓存等,支持嵌套server(虚拟主机)和location(路径匹配)块:
http { # 全局HTTP配置(对所有server生效) include /etc/nginx/mime.types; # MIME类型映射文件 default_type application/octet-stream; # 默认MIME类型(未匹配时) # 日志格式定义(可自定义字段) log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; # 访问日志路径及格式 # 连接超时设置 send_timeout 60; # 发送响应超时时间(秒) keepalive_timeout 75; # 长连接超时时间 # 静态资源优化(gzip压缩) gzip on; gzip_min_length 1k; # 最小压缩文件大小(小于1KB不压缩) gzip_types text/plain text/css application/json application/javascript; # 压缩类型 # 虚拟主机(server块,可定义多个) server { listen 80; # 监听端口 server_name example.com www.example.com; # 绑定域名(支持通配符如*.example.com) root /var/www/example; # 网站根目录(静态文件路径) index index.html index.htm; # 默认索引文件 # 路径匹配(location块) location / { try_files $uri $uri/ =404; # 尝试访问文件/目录,不存在返回404 } # 反向代理示例(转发/api开头的请求到后端Node.js服务) location /api/ { proxy_pass http://127.0.0.1:3000/; # 后端服务器地址(注意末尾的/) proxy_set_header Host $host; # 传递原始请求头到后端 proxy_set_header X-Real-IP $remote_addr; # 传递真实客户端IP proxy_connect_timeout 10; # 连接后端超时时间(秒) } # 错误页面配置 error_page 404 /404.html; error_page 500 502 503 504 /50x.html; } }
以下是我写的问卷系统使用的nginx.conf,解析以及优化建议如下:
user root; worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; client_max_body_size 30m; # 添加以下配置,用于设置全局的跨域相关响应头,允许所有域名跨域访问(生产环境可按需修改为指定域名) add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; server { listen 80; server_name localhost; #index index.html index.htm default.htm default.html; root /home/jerry/Desktop/questionnare/questionnare-front; location /login { #root /home/jerry/Desktop/questionnare/questionnare-front; try_files $uri $uri/ /login.html; # 针对这个具体的location块,也可以单独配置更细化的跨域头信息,以下是示例(如果全局配置满足需求可不加) # add_header 'Access-Control-Allow-Origin' '*'; # add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS'; # add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; # add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; } location /reg { #root /home/jerry/Desktop/questionnare/questionnare-front; try_files $uri $uri/ /reg.html; } location /survey { #root /home/jerry/Desktop/questionnare/questionnare-front; try_files $uri $uri/ /survey.html; } location /root { #root /home/jerry/Desktop/questionnare/questionnare-front; try_files $uri $uri/ /root.html; } location /root_create_table{ #在root的开始界面的创建新的问卷 #root /home/jerry/Desktop/questionnare/questionnare-front; try_files $uri $uri/ /root_create_table.html; } location /root_table { #root /home/jerry/Desktop/questionnare/questionnare-front; try_files $uri $uri/ /root_table.html; } location /table { #root /home/jerry/Desktop/questionnare/questionnare-front; try_files $uri $uri/ /table.html; } # api相关location块 location /api/mypictures{ proxy_pass http://127.0.0.1:8081; # 针对/api开头的这些接口相关location块,也添加跨域头信息(可根据实际需求决定是否和全局配置保持一致或者单独配置) add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; } # api相关location块 location /api/mytables{ proxy_pass http://127.0.0.1:8081; # 针对/api开头的这些接口相关location块,也添加跨域头信息(可根据实际需求决定是否和全局配置保持一致或者单独配置) add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; } location /api/login{ proxy_pass http://127.0.0.1:8081; add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; } location /api/reg{ proxy_pass http://127.0.0.1:8081; add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; } location /api/unreg{ proxy_pass http://127.0.0.1:8081; add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; } location /api/upload{ proxy_pass http://127.0.0.1:8081; add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; } location /api/delete{ proxy_pass http://127.0.0.1:8081; add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; } location /api/root/tables{ proxy_pass http://127.0.0.1:8081; add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; } location /api/root/table_delete{ #删除特定的表格 proxy_pass http://127.0.0.1:8081; add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; } location /api/root/table_create{ #删除特定的表格 proxy_pass http://127.0.0.1:8081; add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; } # 添加 Lua 脚本的 location 块 location /test_login { default_type 'text/plain'; content_by_lua_file /home/jerry/Desktop/questionnare/questionnare-src/lua/test_login.lua; } location /test_questionnare { default_type 'text/plain'; content_by_lua_file /home/jerry/Desktop/questionnare/questionnare-src/lua/test_questionnare.lua; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
一、全局配置块
user root;
- 作用:指定 Nginx 工作进程运行的用户和用户组(默认 nobody)。
- 注意:
- 开发环境可临时使用 root,但生产环境严禁使用(权限过高存在安全风险),建议创建专用用户(如 nginx 或 www-data)。
- 配置格式:user [],如 user nginx nginx;。
worker_processes 1;
- 作用:设置 Nginx 工作进程(Worker)的数量。
- 解析:
- 1 表示仅启动 1 个 Worker 进程,适用于单核心 CPU 或开发环境。
- 生产环境建议:设为 auto(自动检测 CPU 核心数)或显式指定核心数(如 worker_processes 4;),充分利用多核性能。
二、事件模块(events 块)
events { worker_connections 1024; }
- 作用:配置 Worker 进程的连接处理策略。
- 解析:
- worker_connections 1024:每个 Worker 进程最多可同时处理的连接数(含监听连接和客户端连接)。
- 理论最大并发连接数:worker_processes * worker_connections,即此处为 1×1024=1024。
- 生产环境建议:根据内存调整,通常设为 10240 或更高(如 worker_connections 8192;)。
三、HTTP 核心配置(http 块)
http { include mime.types; default_type application/octet-stream;
- include mime.types:引入 MIME 类型映射文件(默认路径 /etc/nginx/mime.types),用于识别文件类型(如 .js 对应 application/javascript)。
- default_type application/octet-stream:未匹配到 MIME 类型的文件,默认以二进制流形式处理(避免浏览器误解析)。
sendfile on;
- 作用:启用 sendfile 系统调用(零拷贝技术),提升静态文件传输效率(减少内核空间与用户空间的数据拷贝)。
- 适用场景:静态资源服务器、文件下载等场景,建议始终开启(默认 off)。
keepalive_timeout 65;
- 作用:设置 HTTP 长连接的超时时间(秒)。
- 解析:客户端与 Nginx 建立的连接在空闲 65 秒后自动关闭,减少无效连接占用资源。
client_max_body_size 30m;
- 作用:限制客户端请求体的最大大小(含文件上传)。
- 场景:适用于需要上传文件的场景(如图片、文档),30m 表示允许最大 30MB 的请求体。
四、全局跨域配置
# 全局跨域头(开发环境可用 *,生产环境需限制具体域名) add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
- 作用:解决前端与后端的跨域问题(CORS)。
- 解析:
- Access-Control-Allow-Origin: *:允许所有域名跨域(开发环境方便,但生产环境需改为具体域名,如 add_header 'Access-Control-Allow-Origin' 'https://example.com';)。
- OPTIONS 请求处理:前端发送跨域请求时会先发送 OPTIONS 预检请求,需允许 OPTIONS 方法。
- 优化建议:将跨域头移至 http 块顶部,避免在每个 location 重复配置。
五、虚拟主机(server 块)
server { listen 80; server_name localhost;
- listen 80:监听 HTTP 80 端口。
- server_name localhost:绑定域名或 IP(此处为本地开发环境,仅响应 localhost 的请求)。
root /home/jerry/Desktop/questionnare/questionnare-front;
- 作用:设置当前虚拟主机的根目录,用于解析静态文件路径。
- 示例:当请求 /login.html 时,Nginx 会查找路径 /home/jerry/Desktop/questionnare/questionnare-front/login.html。
六、静态资源路由(location 块)
1. /login 路由
location /login { try_files $uri $uri/ /login.html; }
- 作用:处理 /login 路径的请求。
- 解析:
- try_files $uri $uri/ /login.html;:
- 先尝试访问请求的 URI(如 /login)对应的文件或目录;
- 若不存在,则返回根目录下的 login.html 文件(实现前端路由匹配,避免 404)。
- 适用场景:SPA(单页应用)路由,如 Vue/React 的前端路由。
2. 其他静态路由(/reg, /survey 等)
location /reg { try_files $uri $uri/ /reg.html; } # 省略 `/survey`, `/root` 等类似配置...
- 作用:与 /login 逻辑一致,分别映射到 reg.html, survey.html 等前端页面。
七、API 反向代理(location 块)
1. /api/mypictures 接口
location /api/mypictures{ proxy_pass http://127.0.0.1:8081; # 跨域头(全局已配置,此处可省略) add_header 'Access-Control-Allow-Origin' '*'; # ... 省略重复的跨域头配置 ... }
- 作用:将以 /api/mypictures 开头的请求转发到后端服务器 http://127.0.0.1:8081。
- 解析:
- proxy_pass:反向代理的目标地址,末尾不带 / 时,请求路径会保留前缀(如 /api/mypictures 转发为 http://127.0.0.1:8081/api/mypictures)。
- 跨域头优化:全局 http 块已配置跨域头,此处可删除重复的 add_header,避免响应头冗余。
2. 其他 API 接口(/api/login, /api/upload 等)
location /api/login{ proxy_pass http://127.0.0.1:8081; # ... 省略重复的跨域头配置 ... }
- 共性:所有 /api/ 开头的路径均转发到后端 8081 端口,适用于前后端分离架构(前端跑在 Nginx,后端为独立服务)。
- 建议优化:
location /api/ { # 统一匹配所有 /api/ 路径 proxy_pass http://127.0.0.1:8081; proxy_set_header Host $host; # 传递原始 Host 头 proxy_set_header X-Real-IP $remote_addr; # 传递客户端真实 IP }
合并为一个 location 块,避免重复代码,提升可维护性。
八、Lua 脚本支持(动态请求处理)
location /test_login { default_type 'text/plain'; content_by_lua_file /home/jerry/Desktop/questionnare/questionnare-src/lua/test_login.lua; }
- 作用:通过 ngx_lua 模块执行 Lua 脚本,动态生成响应内容(如测试接口、自定义逻辑)。
- 依赖:需提前编译 Nginx 并启用 ngx_lua 模块(--add-module=/path/to/ngx_lua)。
- 示例场景:
- 临时测试接口逻辑;
- 动态生成验证码、签名等。
九、错误页面配置
error_page 500 502 503 504 /50x.html; location = /50x.html { root html; }
- 作用:当后端返回 500 系列错误时,Nginx 自动返回 50x.html 页面。
- 解析:
- root html;:50x.html 的实际路径为 Nginx 默认的 html 目录(通常为 /usr/share/nginx/html 或编译时指定的路径)。
- 注意:若前端项目的错误页面在根目录(如 /home/jerry/.../50x.html),需将 root 指向前端目录:
location = /50x.html { root /home/jerry/Desktop/questionnare/questionnare-front; }
十、优化建议与注意事项
1. 生产环境改进点
- 用户权限:
user nginx nginx; # 创建专用用户(需先 `useradd nginx`)
- Worker 进程数:
worker_processes auto; # 自动适配 CPU 核心数
- 跨域安全:
add_header 'Access-Control-Allow-Origin' 'https://your-domain.com'; # 限制具体域名
- 合并 API 代理:
将多个 /api/ 路径合并为一个 location 块,减少配置冗余。
2. 性能优化
- 开启 Gzip 压缩:
gzip on; gzip_types text/plain text/css application/json application/javascript;
- 静态资源缓存:
location /api/ { # 统一匹配所有 /api/ 路径 proxy_pass http://127.0.0.1:8081; proxy_set_header Host $host; # 传递原始 Host 头 proxy_set_header X-Real-IP $remote_addr; # 传递客户端真实 IP }
3. 安全加固
- 禁止直接访问敏感文件:
location ~* \.(php|sh|bak|swp)$ { deny all; # 禁止访问 PHP、脚本文件、备份文件等 }
- 隐藏 Nginx 版本号:
server_tokens off;
五、Nginx 常用操作命令
命令 说明 sudo nginx 启动 Nginx 服务 sudo nginx -s stop 强制停止服务(立即终止所有连接) sudo nginx -s quit 优雅停止服务(完成当前请求后退出) sudo nginx -s reload 重新加载配置文件(热更新,推荐) sudo nginx -t 检查配置文件语法是否正确 sudo nginx -v 查看 Nginx 版本信息 六、Nginx 性能调优建议
- Worker 进程数:设置为 CPU 核心数(worker_processes auto),避免进程竞争。
- 连接数优化:worker_connections设为 10240(根据内存调整),配合multi_accept on(允许 Worker 进程一次性接受多个连接)。
- 静态资源缓存:通过expires指令设置客户端缓存时间(如图片 / JS/CSS 缓存 30 天)。
- 压缩配置:启用gzip或brotli压缩,减少传输流量(仅对文本类文件有效)。
- 日志优化:对静态资源关闭访问日志(access_log off;),减少 I/O 消耗。
七、常见问题排查
- 502 Bad Gateway:通常是后端服务器无响应(检查后端服务是否启动、端口是否开放)。
- 403 Forbidden:可能是 Nginx 用户(user)无权限访问网站目录(检查目录权限chmod)。
- 配置修改不生效:未执行nginx -s reload(需重载配置)或配置文件语法错误(通过nginx -t检查)。
- 日志查看:
- 访问日志:/var/log/nginx/access.log(记录所有请求)
- 错误日志:/var/log/nginx/error.log(记录异常信息)
八、反向代理(Reverse Proxy)
1. 核心原理
- 角色定位:Nginx 作为客户端的「代理服务器」,接收所有外部请求,根据规则转发到后端真实服务器(如 Tomcat/Node.js/Java 服务),并将响应返回给客户端。
- 核心作用:
- 隐藏后端服务器架构(IP、端口等细节),提升安全性;
- 统一处理跨域、认证、日志等公共逻辑,简化后端开发;
- 支持协议转换(如 HTTP ↔ HTTPS、WebSocket 代理)。
2. 典型配置场景
场景 1:基础 HTTP 反向代理
需求:将 http://api.example.com 的请求转发到后端 192.168.1.100:8080 服务,并传递真实客户端 IP。
配置示例:
server { listen 80; server_name api.example.com; location / { # 转发请求到后端服务器(注意结尾的/,与location路径匹配) proxy_pass http://192.168.1.100:8080/; # 传递原始请求头(Host 用于后端识别域名,X-Real-IP 传递真实IP) 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; proxy_send_timeout 30s; } }
场景 2:HTTPS 反向代理(代理 HTTPS 后端服务)
需求:后端服务使用 HTTPS 协议(如 Java Spring Boot 服务),Nginx 需转发 HTTPS 请求。
配置示例:
server { listen 80; server_name secure-api.example.com; location / { # 转发到 HTTPS 后端(协议为 https://) proxy_pass https://192.168.1.101:8443/; # 信任后端证书(若为自签名证书需添加) proxy_ssl_verify off; proxy_ssl_certificate /path/to/backend_cert.pem; # 可选:验证后端证书时使用 } }
场景 3:WebSocket 反向代理
需求:支持前端 WebSocket 连接(ws://chat.example.com),转发到后端 WebSocket 服务。
配置示例:
server { listen 80; server_name chat.example.com; location / { # 转发 WebSocket 请求(需切换协议头) proxy_pass http://192.168.1.102:8080; # 关键配置:升级协议为 WebSocket proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } }
场景 4:路径重写反向代理
需求:将 http://example.com/app/ 路径的请求转发到后端 http://backend:3000/,并去除路径前缀 /app。
配置示例:
server { listen 80; server_name example.com; location /app/ { # 去除路径前缀 /app,转发到后端根路径 proxy_pass http://backend:3000/; rewrite ^/app/(.*) /$1 break; # 重写路径 # 其他通用配置 proxy_set_header Host $host; } }
3. 验证方法
-
检查请求头:
后端服务中打印 X-Real-IP 或 X-Forwarded-For 头,确认是否为客户端真实 IP。
# 示例:用 curl 模拟请求并查看响应头 curl -H "Host: api.example.com" http://localhost/app/
-
日志验证:
在 Nginx 访问日志中添加 $upstream_addr 字段,查看请求转发的后端地址:
log_format proxy_log '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$upstream_addr"'; access_log /var/log/nginx/proxy_access.log proxy_log;
九、负载均衡(Load Balancing)高级应用
1. 负载均衡策略详解
Nginx 支持多种分配策略,通过 upstream 块配置:
策略 说明 适用场景 轮询 默认策略,依次将请求分发给后端服务器(权重相同则均匀分配)。 无状态服务,服务器性能一致。 权重 weight 参数指定服务器处理能力(如 weight=3 表示处理 3 倍请求)。 服务器性能不均场景。 IP 哈希 按客户端 IP 的哈希值固定路由到某台服务器(会话保持)。 需要会话保持的场景。 最少连接 优先将请求分发给当前连接数最少的服务器。 长连接较多的场景(如下载服务)。 URL 哈希 按请求 URL 的哈希值路由(需第三方模块 ngx_http_upstream_hash)。 相同 URL 需固定到同一服务器(如静态资源缓存)。 动态权重 根据服务器响应时间动态调整权重(需第三方模块 ngx_http_upstream_least_time)。 实时动态负载均衡。 2. 典型配置示例
场景 1:轮询策略(默认)
需求:将请求均匀分发给 3 台后端服务器。
配置示例:
http { upstream web_app { server 192.168.1.101:8080; server 192.168.1.102:8080; server 192.168.1.103:8080; } server { listen 80; server_name lb.example.com; location / { proxy_pass http://web_app; proxy_set_header Host $host; } } }
场景 2:权重策略(性能差异化)
需求:2 台高性能服务器(权重 2)和 1 台低性能服务器(权重 1)。
配置示例:
upstream web_app { server 192.168.1.101:8080 weight=2; server 192.168.1.102:8080 weight=2; server 192.168.1.103:8080 weight=1; }
场景 3:IP 哈希(会话保持)
需求:确保同一客户端的请求始终路由到同一服务器(如电商购物车场景)。
配置示例:
upstream web_app { ip_hash; # 启用 IP 哈希策略 server 192.168.1.101:8080; server 192.168.1.102:8080; }
场景 4:最少连接策略
需求:优先将请求分发给当前负载较低的服务器(如视频流媒体服务)。
配置示例:
upstream web_app { least_conn; # 启用最少连接策略 server 192.168.1.101:8080; server 192.168.1.102:8080; }
场景 5:健康检查(避免转发到故障节点)
需求:自动剔除不可用的后端服务器,并在恢复后重新加入集群。
配置示例(需启用 ngx_http_upstream_module):
upstream web_app { server 192.168.1.101:8080 max_fails=2 fail_timeout=30s; # 2次失败则标记为不可用,30s后重试 server 192.168.1.102:8080; server 192.168.1.103:8080 down; # 手动标记为下线(维护状态) }
3. 高级配置:会话保持与缓存
会话保持(Sticky Cookies)
通过 Cookie 实现会话固定,确保同一客户端请求始终路由到同一服务器:
upstream web_app { server 192.168.1.101:8080; server 192.168.1.102:8080; # 生成名为 "sticky" 的 Cookie,值为后端服务器的哈希值 sticky cookie srv_id expires=1h domain=.example.com path=/; }
缓存响应结果
通过 proxy_cache 减少后端压力,缓存高频请求结果:
http { # 定义缓存区域(内存+磁盘) proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m; proxy_cache_key "$scheme$host$request_uri"; # 缓存键规则 upstream web_app { server 192.168.1.101:8080; } server { location / { proxy_pass http://web_app; proxy_cache my_cache; # 启用缓存 proxy_cache_valid 200 302 1h; # 对200/302响应缓存1小时 proxy_cache_valid 404 1m; # 对404响应缓存1分钟 } } }
4. 验证负载均衡效果
-
模拟请求分发:
使用 curl 配合循环脚本,发送多个请求并观察后端服务器日志:
# 循环发送10次请求,查看响应来自哪台服务器 for i in {1..10}; do curl http://lb.example.com; done
-
压力测试:
使用 ab(Apache Benchmark)工具测试负载均衡均匀性:
ab -n 1000 -c 10 http://lb.example.com/
统计结果中 Requests per second 应接近后端服务器数量的倍数(如 3 台服务器则 QPS 约为单台的 3 倍)。
-
查看 Nginx 状态页:
启用 ngx_http_stub_status_module 查看 upstream 状态:
location /status { stub_status on; access_log off; allow 127.0.0.1; # 仅允许本地访问 deny all; }
访问 http://nginx_ip/status 可查看活跃连接数、请求总数等指标。
0voice · GitHub
-
- 禁止直接访问敏感文件:
- 用户权限:
- 作用:与 /login 逻辑一致,分别映射到 reg.html, survey.html 等前端页面。
- try_files $uri $uri/ /login.html;:
-