🔍 1. 什么是 Nginx?
详细解析:
Nginx(发音为"engine-x")是一个高性能的开源 Web 服务器 ,同时也作为反向代理服务器 、负载均衡器 和 HTTP 缓存使用。
核心特性:
-
事件驱动架构:采用异步非阻塞 I/O 模型,能够高效处理大量并发连接
-
模块化设计:通过模块扩展功能,支持自定义开发
-
低内存消耗:特别是在处理静态文件时表现优异
-
高稳定性:能够长时间运行而不需要重启
支持的协议:
-
HTTP/1.0、HTTP/1.1、HTTP/2
-
HTTPS(SSL/TLS)
-
SMTP、POP3、IMAP(作为邮件代理)
-
WebSocket
-
gRPC
应用场景:
-
静态内容服务
-
动态内容反向代理
-
API 网关
-
负载均衡
-
内容缓存
-
SSL 终端
🧩 2. Nginx 的特性
详细解析:
2.1 反向代理 / L7 负载均衡器
bash
upstream backend {
server 10.0.0.1:8080 weight=3;
server 10.0.0.2:8080 weight=2;
server 10.0.0.3:8080 backup;
}
server {
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
负载均衡算法:
-
轮询(默认)
-
最少连接(least_conn)
-
IP 哈希(ip_hash)
-
加权轮询
2.2 嵌入式 Perl 解释器
-
允许在配置文件中嵌入 Perl 代码
-
支持复杂的请求处理逻辑
-
逐渐被 Lua 模块(OpenResty)替代
2.3 动态二进制升级
bash
# 无需停止服务即可升级
nginx -s upgrade
优势:
-
零停机时间更新
-
保持现有连接不中断
-
回滚机制
2.4 URL 重写与 PCRE 支持
bash
location /products {
rewrite ^/products/(.*)$ /items/$1 permanent;
}
location ~* \.(jpg|jpeg|png|gif)$ {
expires 30d;
add_header Cache-Control "public";
}
⚖️ 3. Nginx 与 Apache 的不同点
详细对比:
| 特性 | Nginx | Apache |
|---|---|---|
| 架构模型 | 事件驱动、异步非阻塞 | 多进程/多线程、同步阻塞 |
| 并发处理 | 单进程可处理数万并发 | 受限于进程/线程数量 |
| 内存使用 | 较低且稳定 | 随并发数线性增长 |
| 静态内容 | 性能极高 | 性能一般 |
| 动态内容 | 需转发给后端处理器 | 内置模块支持(如 mod_php) |
| 配置方式 | 集中式配置,不支持 .htaccess | 支持分布式 .htaccess |
| 热部署 | 支持 | 有限支持 |
| 学习曲线 | 较陡峭 | 相对平缓 |
选择建议:
-
选择 Nginx:高并发、静态内容多、内存受限
-
选择 Apache:需要 .htaccess、共享主机环境、传统应用
🔁 4. Nginx 如何处理 HTTP 请求?
详细架构解析:
4.1 事件驱动模型
c
bash
// 伪代码表示事件循环
while (true) {
events = epoll_wait(epoll_fd, events_list, MAX_EVENTS, -1);
for (i = 0; i < events; i++) {
if (events_list[i].events & EPOLLIN) {
// 处理读事件
handle_read_event(events_list[i].data.fd);
}
if (events_list[i].events & EPOLLOUT) {
// 处理写事件
handle_write_event(events_list[i].data.fd);
}
}
}
4.2 请求处理流程
-
接收连接:Worker 进程接受新连接
-
解析请求:解析 HTTP 头部,确定虚拟主机
-
匹配 Location:根据 URI 匹配 location 块
-
处理请求:执行相应的处理逻辑(静态文件、代理等)
-
生成响应:构建 HTTP 响应
-
发送响应:异步发送响应数据
4.3 多进程架构
bash
Master Process (PID: 1001)
├── Worker Process (PID: 1002) → 处理连接 A、C、E...
├── Worker Process (PID: 1003) → 处理连接 B、D、F...
└── Cache Manager/Loader (PID: 1004)
🚫 5. 如何使用未定义的服务器名称阻止请求?
详细配置说明:
bash
# 方法1:使用空服务器名
server {
listen 80;
server_name "";
return 444; # Nginx 自定义状态码,关闭连接
}
# 方法2:默认服务器捕获所有未匹配请求
server {
listen 80 default_server;
server_name _;
deny all;
return 444;
}
# 方法3:针对特定非法域名
server {
listen 80;
server_name malicious.com *.hacker.org;
access_log off;
error_log off;
return 444;
}
应用场景:
-
防止域名恶意指向
-
阻止扫描器探测
-
减少无效请求的资源消耗
🛡️ 6. 反向代理服务器的优点
详细优势分析:
6.1 安全性增强
bash
# 隐藏后端服务器信息
proxy_pass http://backend;
proxy_hide_header X-Powered-By;
proxy_hide_header Server;
# 添加安全头
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
6.2 负载均衡
bash
upstream app_servers {
zone backend 64k;
least_conn;
server 10.1.1.1:8080 max_fails=3 fail_timeout=30s;
server 10.1.1.2:8080 max_fails=3 fail_timeout=30s;
server 10.1.1.3:8080 max_fails=3 fail_timeout=30s backup;
}
6.3 内容缓存
bash
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m;
location / {
proxy_cache my_cache;
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_pass http://backend;
}
6.4 SSL 终端
bash
server {
listen 443 ssl;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://backend; # 后端使用 HTTP
}
}
🚀 7. Nginx 的最佳用途
详细应用场景:
7.1 静态内容服务
bash
server {
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
location /static/ {
alias /var/www/static/;
autoindex off;
}
}
7.2 动态内容代理
bash
# Spring Boot 应用 (内嵌 Tomcat/Jetty)
location /spring-boot/ {
# 代理到 Spring Boot 应用
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_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
# 超时设置
proxy_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
# 缓冲设置
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
# 启用 WebSocket 支持
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Spring Boot Actuator 端点
location /spring-boot/actuator/ {
proxy_pass http://127.0.0.1:8080/actuator/;
proxy_set_header Host $host;
# 安全限制
allow 192.168.1.0/24;
allow 10.0.0.0/8;
deny all;
access_log off;
}
7.3 负载均衡器
bash
upstream microservices {
zone upstreams 64k;
server api1.example.com:8080 weight=2;
server api2.example.com:8081;
server api3.example.com:8082 backup;
# 健康检查
health_check interval=5s fails=3 passes=2;
}
👨💼 8. Master 和 Worker 进程
详细进程架构:
8.1 Master 进程职责
bash
# 查看进程树
$ pstree -p | grep nginx
nginx(1001)─┬─nginx(1002)
├─nginx(1003)
├─nginx(1004)
└─nginx(1005)
Master 进程功能:
-
读取和验证配置文件
-
绑定监听端口
-
管理 Worker 进程(启动、停止、重启)
-
平滑升级二进制文件
-
重新打开日志文件
8.2 Worker 进程职责
bash
# 配置 Worker 进程
worker_processes auto; # CPU 核心数
worker_cpu_affinity auto;
worker_rlimit_nofile 100000; # 文件描述符限制
events {
worker_connections 10240; # 每个 Worker 最大连接数
use epoll; # 事件模型
multi_accept on;
}
Worker 进程特性:
-
独立的进程,互不影响
-
处理实际的网络连接
-
使用异步非阻塞 I/O
-
可配置的 CPU 亲和性
🔧 9. 如何在非 80 端口启动 Nginx?
详细配置方法:
9.1 修改默认配置文件
bash
# /etc/nginx/sites-available/default
server {
listen 8080; # 改为 8080 端口
listen [::]:8080;
server_name example.com;
root /var/www/html;
index index.html index.htm;
}
9.2 多端口监听
bash
server {
listen 80;
listen 443 ssl;
listen 8080;
listen 8443 ssl;
server_name example.com;
# ... 其他配置
}
9.3 SELinux 环境下的注意事项
bash
# 检查当前端口上下文
semanage port -l | grep http
# 添加新端口
semanage port -a -t http_port_t -p tcp 8080
# 重启 Nginx
systemctl restart nginx
9.4 防火墙配置
bash
# 开放端口
ufw allow 8080/tcp
firewall-cmd --permanent --add-port=8080/tcp
firewall-cmd --reload
❗ 10. 替换错误为 502/503
详细错误处理配置:
10.1 基本错误页面配置
bash
http {
# 定义错误页面
error_page 500 502 503 504 /50x.html;
error_page 404 /404.html;
location = /50x.html {
root /usr/share/nginx/html;
internal;
}
location = /404.html {
root /usr/share/nginx/html;
internal;
}
}
10.2 动态错误处理
bash
location /api/ {
proxy_pass http://backend;
proxy_intercept_errors on;
# 将 502 错误转换为 503
error_page 502 =503 /maintenance.html;
# 自定义错误处理
error_page 404 = @fallback;
error_page 500 502 503 504 = @down;
}
location @fallback {
try_files $uri $uri/ @proxy;
}
location @down {
add_header Retry-After 3600;
return 503 "Service temporarily unavailable";
}
10.3 FastCGI 错误拦截
bash
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php-fpm.sock;
fastcgi_intercept_errors on;
# 拦截 FastCGI 错误
error_page 500 502 503 504 /error.php;
include fastcgi_params;
}
🔗 11. 保留 URL 中的双斜线
详细配置说明:
11.1 merge_slashes 指令
bash
server {
# 关闭斜线合并
merge_slashes off;
location /api/ {
# 某些路径允许双斜线
merge_slashes off;
proxy_pass http://backend;
}
location /static/ {
# 静态资源通常不需要双斜线
merge_slashes on;
try_files $uri $uri/ =404;
}
}
11.2 应用场景
-
API 路径 :
/api/v1//users可能需要保留双斜线 -
文件路径 :
//share//file.txt特殊文件系统 -
URL 重写:保留原始 URL 结构
11.3 正则表达式处理
bash
location ~* "^//+(.*)$" {
# 处理多个斜线开头的请求
rewrite "^//+(.*)$" /$1 break;
proxy_pass http://backend;
}
🔁 12. ngx_http_upstream_module 的作用
详细模块功能:
12.1 上游服务器定义
bash
upstream backend {
# 基础配置
server 10.0.1.1:8080;
server 10.0.1.2:8080;
# 负载均衡方法
least_conn; # 最少连接
# 健康检查
health_check interval=5s fails=3 passes=2;
}
12.2 服务器参数详解
bash
upstream app_servers {
# 服务器状态
server 10.0.1.1:8080 weight=5; # 主服务器,权重高
server 10.0.1.2:8080 weight=3; # 次要服务器
server 10.0.1.3:8080 down; # 停机维护
server 10.0.1.4:8080 backup; # 备份服务器
# 故障转移设置
server 10.0.1.5:8080 max_fails=3 fail_timeout=30s;
# 解析器用于动态 DNS
resolver 8.8.8.8 valid=30s;
}
12.3 代理配置
bash
location / {
proxy_pass http://backend;
# 超时设置
proxy_connect_timeout 5s;
proxy_send_timeout 10s;
proxy_read_timeout 30s;
# 缓冲设置
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
# 重试机制
proxy_next_upstream error timeout invalid_header;
proxy_next_upstream_tries 3;
proxy_next_upstream_timeout 30s;
}
💥 13. 什么是 C10K 问题?
详细技术解析:
13.1 问题定义
C10K(Concurrent 10,000 Connections)指的是服务器同时处理一万个并发连接的技术挑战。
13.2 传统服务器的限制
c
bash
// 传统阻塞 I/O 模型
while (1) {
client_fd = accept(server_fd); // 阻塞
read(client_fd, buffer); // 阻塞
process_request(buffer);
write(client_fd, response); // 阻塞
close(client_fd);
}
13.3 Nginx 的解决方案
c
bash
// 事件驱动模型
while (1) {
n = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
for (i = 0; i < n; i++) {
if (events[i].data.fd == server_fd) {
// 接受新连接
client_fd = accept(server_fd);
set_nonblocking(client_fd);
add_to_epoll(client_fd);
} else {
// 处理现有连接
handle_client(events[i].data.fd);
}
}
}
13.4 现代解决方案
-
I/O 多路复用:epoll(Linux)、kqueue(BSD)
-
异步 I/O:io_uring(Linux)
-
用户态网络栈 :DPDK、FD.io
📊 14. stub_status 和 sub_filter 指令
详细功能说明:
14.1 stub_status 指令
bash
# 启用状态页面
server {
listen 80;
server_name status.example.com;
location /nginx_status {
stub_status on;
access_log off;
allow 192.168.1.0/24;
deny all;
}
}
状态信息解读:
bash
Active connections: 291
server accepts handled requests
16630948 16630948 31070465
Reading: 6 Writing: 179 Waiting: 106
-
Active connections:当前活跃连接数
-
accepts:接受的客户端连接总数
-
handled:处理的连接数
-
requests:客户端请求总数
-
Reading:正在读取请求头的连接数
-
Writing:正在写入响应的连接数
-
Waiting:空闲客户端连接数
14.2 sub_filter 指令
bash
location / {
proxy_pass http://backend;
# 内容替换
sub_filter 'http://old-domain.com' 'https://new-domain.com';
sub_filter 'Old Text' 'New Text';
sub_filter_once off; # 替换所有出现
sub_filter_types text/html text/css; # 指定 MIME 类型
# 响应头修改
sub_filter_last_modified on;
}
应用场景:
-
域名迁移
-
内容更新
-
A/B 测试
-
错误修复
🗜️ 15. 是否支持将请求压缩到上游?
详细压缩配置:
15.1 响应解压缩(gunzip)
bash
# 启用解压缩模块
http {
gunzip on;
gunzip_buffers 16 8k;
location / {
proxy_pass http://backend;
# 如果后端返回压缩内容,但客户端不支持
gunzip on;
}
}
15.2 请求压缩
bash
# 向上游发送压缩请求
location /api/ {
proxy_pass http://backend;
# 启用请求体压缩
proxy_set_header Accept-Encoding "gzip";
# 压缩请求体(需要相应模块)
client_body_in_file_only clean;
client_body_buffer_size 128K;
}
15.3 响应压缩(gzip)
bash
http {
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/xml+rss
application/json;
# 预压缩文件支持
gzip_static on;
}
⏰ 16. 如何在 Nginx 中获得当前的时间?
详细时间变量:
16.1 内置时间变量
bash
server {
location /time {
# 返回当前时间
add_header Content-Type "text/plain";
return 200 "GMT: $date_gmt\nLocal: $date_local\n";
}
location /api/ {
proxy_pass http://backend;
# 传递时间戳给后端
proxy_set_header X-Request-Time $msec;
proxy_set_header X-Request-Date $date_gmt;
}
}
16.2 可用时间变量
-
$date_gmt:GMT 格式的当前时间 -
$date_local:本地时区格式的当前时间 -
$time_iso8601:ISO 8601 格式时间 -
$time_local:本地时间的通用日志格式 -
$msec:带毫秒的 Unix 时间戳
16.3 SSI 模块时间显示
bash
location /ssi-page {
ssi on;
# 在 HTML 中嵌入时间
# <!--# echo var="date_gmt" -->
# <!--# config timefmt="%Y-%m-%d %H:%M:%S" -->
}
⚙️ 17. Nginx -s 参数的作用
详细信号管理:
17.1 常用信号命令
bash
# 重新加载配置(平滑重启)
nginx -s reload
# 立即停止
nginx -s stop
# 优雅停止(处理完当前请求)
nginx -s quit
# 重新打开日志文件(用于日志轮转)
nginx -s reopen
17.2 信号对应关系
bash
# 直接向进程发送信号
kill -HUP $(cat /var/run/nginx.pid) # 等同于 reload
kill -QUIT $(cat /var/run/nginx.pid) # 等同于 quit
kill -TERM $(cat /var/run/nginx.pid) # 等同于 stop
kill -USR1 $(cat /var/run/nginx.pid) # 等同于 reopen
17.3 信号处理流程
bash
用户命令: nginx -s reload
↓
发送 HUP 信号给 Master 进程
↓
Master 检查新配置语法
↓
启动新的 Worker 进程
↓
优雅关闭旧的 Worker 进程
↓
完成平滑重启
🧩 18. 如何在 Nginx 中添加模块?
详细模块管理:
18.1 编译时添加模块
bash
# 查看当前已编译模块
nginx -V
# 下载 Nginx 源码
wget http://nginx.org/download/nginx-1.24.0.tar.gz
tar -zxvf nginx-1.24.0.tar.gz
cd nginx-1.24.0
# 配置编译参数(包含现有模块和新模块)
./configure \
--prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
--modules-path=/usr/lib/nginx/modules \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_stub_status_module \
--add-module=/path/to/custom-module \
--add-dynamic-module=/path/to/dynamic-module
# 编译和安装
make
make install
18.2 动态模块加载
bash
# 在 nginx.conf 中加载动态模块
load_module modules/ngx_http_geoip_module.so;
load_module modules/ngx_stream_geoip_module.so;
http {
# 使用动态模块
geoip_country /usr/share/GeoIP/GeoIP.dat;
}
18.3 常用第三方模块
-
OpenResty:LuaJIT 支持
-
Headers More:增强的头部控制
-
Cache Purge:缓存清理
-
Fancy Index:美观的目录列表
18.4 模块开发基础
c
bash
// 简单的 Hello World 模块
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
static ngx_int_t ngx_http_hello_handler(ngx_http_request_t *r) {
ngx_str_t response = ngx_string("Hello, Nginx Module!");
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = response.len;
ngx_http_send_header(r);
return ngx_http_output_filter(r, &response);
}