简介
nginx 安装方法 参考 Installing nginx。
nginx 是一个高性能的 HTTP 和 反向代理服务器(Reverse Proxy Server),也可以做 IMAP/POP3/SMTP 代理服务器。
nginx 作用:
- 作为 HTTP 服务器,处理静态资源请求。比如 博客网站静态文件, 前端项目打包后的文件, 图片、视频等文件。
- 作为 反向代理服务器, 将客户端请求 转发到后端服务,并将后端服务器的响应返回给客户端。
反向代理服务器 处理的一般也是 HTTP 请求。本文不严格区分 HTTP 服务器 和 反向代理服务器。
什么是 HTTP 服务器?
HTTP 服务器 (HTTP Server) 是一种 提供网页内容服务的程序, 它基于 HTTP (HyperText Transfer Protocol, 超文本传输协议) 来处理客户端(通常是浏览器)的请求, 并返回响应。HTTP 服务器的基本工作流程:
- 监听端口
- HTTP 服务器通常监听 80 (HTTP) 或 443 (HTTPS) 端口。
- 接收请求
- 客户端(如浏览器、移动端)通过 URL 发送 HTTP 请求, 服务器接收请求报文。
- 请求内容包括方法 (GET、POST、PUT、DELETE 等)、路径、请求头和请求体。
- 处理请求
- HTTP 服务器根据请求内容找到对应的资源 (如 HTML、图片、API 接口程序), 或把请求转发给 后端应用程序 (这就是反向代理的功能)。
- 返回响应
- HTTP 服务器生成 HTTP 响应报文 (状态码、响应头、响应体), 发送给客户端。
- 浏览器再把响应内容渲染出来。
nginx 进程模型
nginx 有 一个主进程(master process) 和 多个工作进程(worker process)。
master 进程 的主要作用是 读取和解析 nginx 配置文件, 并维护工作进程。
worker 进程 的主要作用是 处理实际的请求。
nginx 采用 基于事件的模型 和 依赖于操作系统的机制,以高效地在 worker 进程 之间分配请求。
worker 进程 的数量在配置文件中定义。
nginx 命令
nginx 常用命令:
# 启动nginx
nginx
# 停止nginx(优雅): 先发送 quit 信号, 等待所有请求处理完成, 再停止进程
nginx -s quit
# 停止nginx(快速): 直接发送 stop 信号, 不等待请求处理完成, 立即停止进程
nginx -s stop
# 重新加载配置
nginx -s reload
查看 nginx 进程:
ps aux | grep nginx
测试配置文件是否正确:
nginx -t
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful
查看版本、编译参数和依赖信息:
nginx -V
# nginx version: nginx/1.20.1
# built by gcc 10.2.1 20200825 (Alibaba 10.2.1-3.8 2.32) (GCC)
# built with OpenSSL 1.1.1k FIPS 25 Mar 2021
# TLS SNI support enabled
# configure arguments: --prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf ......
nginx -v
# nginx version: nginx/1.20.1
配置文件
nginx 及其 模块(module) 的工作方式由 配置文件 决定。
默认情况下,配置文件名为 nginx.conf,存放于 /usr/local/nginx/conf、/etc/nginx或/usr/local/etc/nginx 目录中。
如果不确定配置文件的位置, 可以用
nginx -t或nginx -V命令输出。
nginx 官网给的配置文件中的概念(我觉得不用掌握, 知道怎么配置就行了):
nginx 由多个 模块(module) 组成,这些 模块 由 配置文件 中指定的 指令(directive) 控制。指令 分为 简单指令(simple directive) 和 块指令(block directive):
- 简单指令 由 名称 和 参数 组成,名称 和 参数之间用空格分隔,并以分号(
;)结尾。- 块指令 与 简单指令 的结构相同,但它不是以分号结尾,而是以一组用大括号(
{和})包围的附加指令结尾。如果块指令的大括号内可以包含> 其他指令,则称为 上下文(context 例如:events、http、server 和 location)。井号(
#)后面的内容 被视为 注释。
简化的配置文件结构:
http 块是 最外层块, 一般在 nginx.conf 配置文件中。
upstream 块 定义 后端服务器组, 一般在子配置文件中。upstream 是上游服务器的意思, 用户在下游, 服务器在上游。
server 块 定义 虚拟主机, 一般在子配置文件中。一个 server 块 代表一个服务。
location 块 定义 路由规则。
示例:
- 访问 example.com:8000/static1 时, nginx 会根据配置文件, 找到对应的 location 块(/static1), 根据该块的配置, 会返回静态资源文件。
- 访问 example.com:8000/api_xxx/xxx 时, nginx 会根据配置文件, 找到对应的 location 块(/api_xxx/xxx), 根据该块的配置, 会将请求转发到后端服务器组 upstream-server1, 最终 upstream-server1 中的一台机器会接收请求并响应。
nginx.conf
/etc/nginx/nginx.conf 是我服务器上默认的 nginx 配置文件, 它包含了 nginx 的全局配置, 如 worker 进程数、日志文件路径、模块加载等。
具体内容如下:
# 指定 Nginx 工作进程的运行用户为 nginx。
# 确保该用户对需要访问的文件/目录有合适权限(如 root、日志、html 目录等)。
user nginx;
# 自动根据 CPU 核心数启动 worker 进程,一般用于取最大并行能力。也可写具体数值。
worker_processes auto;
# 错误日志文件路径。可以加日志级别 error_log /var/log/nginx/error.log warn;
error_log /var/log/nginx/error.log;
# master 进程的 PID 文件位置,systemd/脚本常用它来管理进程
pid /run/nginx.pid;
# 加载动态模块的配置(通常包含 load_module 指令)。有些发行版会把动态模块放这里
include /usr/share/nginx/modules/*.conf;
# events 块
events {
# 每个 worker 能同时处理的最大连接数(含客户端连接和与后端的连接等)。
# 一般建议设置为 1024 或 2048。
worker_connections 1024;
}
# http 块
http {
# 定义访问日志格式
# 格式名称为 main,后续 access_log 指令可以引用这个名称。
# 格式中包含了客户端 IP(remote_addr)、用户、时间、请求方法、状态码、响应字节数、引用者、用户代理和 X-Forwarded-For 请求头(常用于代理转发时记录真实 IP)。
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# 启用访问日志并指定使用上面定义的 main 格式
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# 保持连接超时时间(单位:秒), 一般建议设置为 65 秒。
keepalive_timeout 65;
types_hash_max_size 4096;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 包含 /etc/nginx/conf.d 目录下的所有 .conf 文件
# 这些文件通常包含了 站点级别的配置,如 server 块、location 块等。
# 通常: 每个 .conf 文件 对应 一个站点或服务。
include /etc/nginx/conf.d/*.conf;
# server 块(默认站点)
server {
# 监听 IPv4 的 80 端口
listen 80;
# 监听 IPv6 的 80 端口
listen [::]:80;
# 下划线作为 server_name 常被用作“catch-all”默认域名(不是标准语义,只是习惯用法)
server_name _;
# 该 server 的站点根目录,静态文件会从这里提供。
root /usr/share/nginx/html;
# 加载该 server 的额外配置片段(例如安全头、特殊 location 等)
include /etc/nginx/default.d/*.conf;
# 当发生 404 时,内部重定向到 /404.html
error_page 404 /404.html;
# = 表示精确匹配,当请求 EXACT 为该路径时,使用这个 location。
# 常见默认配置中会把错误页放在 /40x.html 和 /50x.html。
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
}
整体结构, Nginx 配置有几个主要上下文(context):
- 主配置(main / global): 最顶层,可以放 user、worker_processes、error_log、pid、load_module 等。
- events: 与连接处理相关的设置(如 worker_connections)。
- http: HTTP 服务相关的全局设置(日志、mime 类型、缓存、包括 server 块等)。
- server: 虚拟主机,一个 server 块就是一个站点(监听端口、server_name、root、location 等)。
- location: 请求路径匹配并处理的具体规则。
Serving Static Content
/etc/nginx/conf.d/blog.conf 是我的博客站点的配置文件。
内容如下:
server {
# 监听 443 端口 (HTTPS 默认端口)
# 启用 SSL
# 开启 HTTP/2 协议,提高多路复用能力和页面加载性能
listen 443 ssl http2;
# 服务器名称,用于匹配请求的 Host 头
# 当请求的 Host 头部为 blog.mitrecx.top 时,匹配到这个 server 块。
server_name blog.mitrecx.top;
# 公钥证书文件 (PEM 格式)
ssl_certificate /etc/nginx/ssl/blog.mitrecx.top.pem;
# 私钥文件
ssl_certificate_key /etc/nginx/ssl/blog.mitrecx.top.key;
# TLS 协议与加密套件
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m; # 开启 SSL 会话缓存,多个连接可复用,提高性能
ssl_session_timeout 10m; # 会话缓存过期时间
# 网站根目录
root /home/josie/blog/public;
# 默认首页文件
index index.html;
# 匹配所有请求路径
location / {
# try_files 指令会依次尝试:
# 1. 请求的文件 ($uri)
# 2. 请求的目录 ($uri/)
# 3. 如果都不存在,返回 404
try_files $uri $uri/ =404;
}
# 正则匹配,以不区分大小写方式匹配静态资源后缀
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {
# 设置浏览器缓存时间为 1年
expires 1y;
# 开启缓存, 缓存策略:
# public: 所有缓存层 (浏览器、CDN) 都可以缓存
# immutable: 资源内容不会改变,缓存后可以长期使用
add_header Cache-Control "public, immutable";
}
# 开启 gzip 压缩
gzip on;
gzip_vary on;
# 只有响应体大于 1KB 才压缩
gzip_min_length 1024;
# 指定压缩的 MIME 类型 (HTML 默认已包含)
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
}
# HTTP 跳转 server 块, 所有 HTTP 请求永久重定向到 HTTPS
server {
# 监听 80 端口 (HTTP 默认端口)
listen 80;
# 服务器名称,用于匹配请求的 Host 头
# 当请求的 Host 头部为 blog.mitrecx.top 时,匹配到这个 server 块。
server_name blog.mitrecx.top;
# 所有请求 301 永久重定向到对应的 HTTPS 地址
return 301 https://$host$request_uri;
}
总结, 这个配置的功能是:
- 提供 https://blog.mitrecx.top 的静态网站服务 (支持 http2)。
- 所有 HTTP 请求强制跳转到 HTTPS。
- 配置了严格的 TLS 协议和套件,安全性较高。
注意, location 中 root 和 alias 的区别:
- root: 会将请求路径拼接在 root 后面, 然后查找文件。
- alias: 会将请求路径替换为 alias 后面的路径, 然后查找文件。
Setting Up a Simple Proxy Server
下面看一下我的 “家庭账单” 项目的 nginx 配置 /etc/nginx/conf.d/family-bills.conf, 这是一个前后端分离的 web 项目, 配置文件中包含了 反向代理 配置:
# 定义 upstream 后端服务池
upstream backend_api {
# 默认是轮询
server 127.0.0.1:8000;
# 以后可以轻松扩展
# server 127.0.0.1:8001;
# server 127.0.0.1:8002;
}
server {
listen 443 ssl http2;
server_name jo.mitrecx.top;
ssl_certificate /etc/nginx/ssl/jo.mitrecx.top.pem;
ssl_certificate_key /etc/nginx/ssl/jo.mitrecx.top.key;
# SSL 优化配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# 网站根目录 (前端构建后的文件)
root /var/www/family-bills-frontend;
# 默认前端首页文件
index index.html;
# 前端路由支持
location / {
try_files $uri $uri/ /index.html;
}
# API 代理 (反向代理到后端)
# 把前端请求 /api/xxx 转发到 127.0.0.1:8000/api/xxx
# 实现前后端分离: 前端不直接调用后端 IP, 而是通过 Nginx 中转。
location /api/ {
# proxy_pass 的作用就是 告诉 nginx 要把请求转发到哪个后端服务, 是实现 反向代理 和 API 网关 的关键配置
proxy_pass http://backend_api/api/;
# 也可以直接写 IP:
# proxy_pass http://127.0.0.1:8000/api/;
# 请求头设置 (保证后端能识别真实请求信息):
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;
# 超时设置 - 支持大文件上传和AI处理(5分钟)
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
proxy_buffering off;
# 客户端请求体大小限制(支持大文件上传)
client_max_body_size 100M;
}
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# Gzip压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
}
# 所有 HTTP 请求永久重定向到 HTTPS
server {
listen 80;
server_name jo.mitrecx.top;
return 301 https://$host$request_uri;
}
总结
我只有一台 ECS(Elastic Compute Service, 弹性计算服务/云上虚拟服务器), 在这台 ECS 上运行了 nginx 服务, 添加了上面的两个配置文件, 实现了:
- 访问 blog.mitrecx.top 地址时, 返回 静态博客 的页面
- 访问 jo.mitrecx.top 地址时, 返回 家庭账单系统 的页面
- 访问 jo.mitrecx.top/api/ 地址时, 反向代理到 127.0.0.1:8000/api/ 地址