Nginx 笔记
约 7991 字大约 27 分钟
2025-10-23
Nginx 简介
Nginx 是一款轻量级的 Web 服务器 、反向代理服务器及电子邮件(IMAP/POP3)代理服务器。
什么是反向代理?
反向代理(Reverse Proxy)方式是指以代理服务器来接受 internet 上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给 internet 上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。
Nginx 入门
基本控制命令
快速关闭 Nginx,可能不保存相关信息,并迅速终止 web 服务。
nginx -s stop平稳关闭Nginx,保存相关信息,有安排的结束web服务。
nginx -s quit因改变了Nginx相关配置,需要重新加载配置而重载,平滑重载配置(不会断开现有连接)
nginx -s reload重新打开日志文件。
nginx -s reopen指定自定义配置文件(默认用 conf/nginx.conf)
nginx -c filename不运行,仅仅测试配置文件。nginx 将检查配置文件的语法的正确性,并尝试打开配置文件中所引用到的文件。
nginx -t重要
nginx -t 是用于检测 Nginx 配置文件有效性的命令,输出的两行内容分别对应不同层面的检测结果:
第一行:nginx: the configuration file [路径] syntax is ok
含义:仅针对主配置文件(如示例中的 /www/server/nginx/conf/nginx.conf)本身进行语法校验,确认其没有语法错误(如指令格式、括号配对、参数书写等问题)。
第二行:nginx: configuration file [路径] test is successful
含义:对整个配置体系进行完整性检测。除主配置文件外,还会加载所有通过 include 指令引入的子配置文件(如站点配置、模块配置等),确认整个配置集合逻辑通顺、可正常运行。
简言之,第一行验证 “主文件语法正确”,第二行验证 “主文件 + 所有关联配置整体有效”。两者都显示 ok 或 successful 时,说明配置可安全重载(nginx -s reload)。
设置 nginx 的工作目录(conf、logs 等目录相对该路径)
nginx -p C:\nginx\显示 nginx 的版本。
nginx -v显示 nginx 的版本,编译器版本和配置参数。
nginx -V如果不想每次都敲命令,可以在 nginx 安装目录下新添一个启动批处理文件startup.bat,双击即可运行。内容如下:
@echo off
rem 如果启动前已经启动nginx并记录下pid文件,会kill指定进程
nginx.exe -s stop
rem 测试配置文件语法正确性
nginx.exe -t -c conf/nginx.conf
rem 显示版本信息
nginx.exe -v
rem 按照指定配置去启动nginx
nginx.exe -c conf/nginx.conf调试相关命令
全局覆盖配置指令,例如 daemon off; 可以让 nginx 前台运行(方便调试 Docker/PowerShell 观察日志)
nginx -g "daemon off;"测试不同目录和配置文件,不修改默认路径即可临时切换配置
nginx -p C:\nginx\ -c conf/nginx.conf测试指定配置语法
nginx -t -c conf/test.conf注意:在修改配置之前或之后总是 nginx.exe -t,避免启动失败。
如果无法关闭?
找到 nginx 进程 PID:
tasklist | findstr nginx输出示例:
nginx.exe 1234 Console 1 5,000 K
nginx.exe 5678 Console 1 5,000 K强制杀掉:
taskkill /F /PID 1234
taskkill /F /PID 5678Windows 上 nginx 有 master + worker 进程,通常两个以上进程,要全部 kill 才彻底关闭。
Nginx 实战
http 反向代理
nginx.conf 配置文件如下:
#运行用户
#user somebody;
#启动进程,通常设置成和cpu的数量相等
worker_processes 1;
#全局错误日志
error_log logs/error.log;
error_log logs/notice.log notice;
error_log logs/info.log info;
#PID文件,记录当前启动的nginx的进程ID
pid logs/nginx.pid;
#工作模式及连接数上限
events {
worker_connections 1024; #单个后台worker process进程的最大并发链接数
}
#设定http服务器,利用它的反向代理功能提供负载均衡支持
http {
#设定mime类型(邮件支持类型),类型由mime.types文件定义
include mime.types;
default_type application/octet-stream;
#设定日志
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 logs/access.log main;
rewrite_log on;
#sendfile 指令指定 nginx 是否调用 sendfile 函数(zero copy 方式)来输出文件,对于普通应用,
#必须设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为 off,以平衡磁盘与网络I/O处理速度,降低系统的uptime.
sendfile on;
#tcp_nopush on;
#连接超时时间
keepalive_timeout 120;
tcp_nodelay on;
#gzip压缩开关
#gzip on;
#设定实际的服务器列表
upstream yu_server1{
server 127.0.0.1:3000;
}
#HTTP服务器
server {
#监听80端口,80端口是知名端口号,用于HTTP协议
listen 80;
#定义使用www.xx.com访问
server_name www.helloworld.com;
#首页
index index.html
#指向webapp的目录
root main\webapp;
#编码格式
charset utf-8;
#代理配置参数
proxy_connect_timeout 180;
proxy_send_timeout 180;
proxy_read_timeout 180;
proxy_set_header Host $host;
proxy_set_header X-Forwarder-For $remote_addr;
#反向代理的路径(和upstream绑定),location 后面设置映射的路径
location / {
proxy_pass http://yu_server1;
}
#静态文件,nginx自己处理
location ~ ^/(images|javascript|js|css|flash|media|static)/ {
root main\webapp\views;
#过期30天,静态文件不怎么更新,过期可以设大一点,如果频繁更新,则可以设置得小一点。
expires 30d;
}
#设定查看Nginx状态的地址
location /NginxStatus {
stub_status on;
access_log on;
auth_basic "nginxstatus";
auth_basic_user_file htpasswd;
}
#禁止访问 .htxxx 文件
location ~ /\.ht {
deny all;
}
#错误处理页面(可选择性配置)
#error_page 404 /404.html;
#error_page 500 502 503 504 /50x.html;
#location = /50x.html {
# root html;
#}
}
}root main\webapp 这是告诉 Nginx 静态文件的根目录,主要用于 Nginx 自己直接处理静态文件(比如 .html、.js、.css、图片等)。
proxy_pass http://yu_server1 这是 反向代理,也就是说当访问匹配到这个规则的路径时,Nginx 不自己处理,而是把请求转发到 upstream yu_server1 对应的后端服务器,这里是 127.0.0.1:8089。
location / {
proxy_pass http://zp_server1;
}你访问 http://www.helloworld.com/ 或其他 / 开头的路径。
Nginx 会把请求 全部转发给 127.0.0.1:8089。
所以你看到的内容,是 8089端口后端服务器的内容,不是 main\webapp 目录的文件。
location ~ ^/(images|javascript|js|css|flash|media|static)/ {
root main\webapp\views;
expires 30d;
}匹配 /images/...、/js/...、/css/... 这样的请求。
这类请求 Nginx 自己直接读取本地磁盘的文件,并返回给客户端。
所以这些请求看到的内容,是 main\webapp\views 下的文件。
特殊路径 /NginxStatus 和 .ht 文件
/NginxStatus→ 查看 Nginx 状态,不经过代理。.ht文件 → 被deny all;禁止访问。
- 启动 webapp,注意启动绑定的端口要和 nginx 中的
upstream设置的端口保持一致。 - 更改 host:在 C:\Windows\System32\drivers\etc 目录下的 host 文件中添加一条 DNS 记录
127.0.0.1 www.helloworld.com- 启动 Nginx
- 在浏览器中访问 www.helloworld.com,不出意外,已经可以访问了。
https 反向代理
对于一些对安全性要求较高的站点,通常会使用 HTTPS(基于 SSL/TLS 的安全 HTTP 协议)进行通信。使用 Nginx 配置 HTTPS 需要注意以下几点:
端口号 HTTPS 默认使用 443 端口,不同于 HTTP 的 80 端口。
安全证书 HTTPS 需要使用 SSL 证书来加密通信,因此在 nginx.conf 中必须指定证书文件和对应的私钥。
配置方式 HTTPS 的反向代理与 HTTP 基本相同,只是在 server 配置块中增加了 SSL 相关参数。
server {
# 监听 443 端口,启用 SSL
listen 443 ssl;
# 站点域名
server_name www.helloworld.com;
# SSL 证书及私钥
ssl_certificate cert.pem;
ssl_certificate_key cert.key;
# 可选的 SSL 参数
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# 站点根目录
location / {
root /root;
index index.html index.htm;
}
}说明:
ssl_certificate:SSL 证书文件路径,常见格式为.crt或.pem。ssl_certificate_key:证书对应的私钥文件。ssl_ciphers:加密套件,可根据安全需求进行调整。ssl_prefer_server_ciphers on;:优先使用服务器定义的加密套件。- 其他 HTTPS 配置与 HTTP 配置类似,例如
location、root、index等。
负载均衡
假设我们有一个 Web 应用部署在三台 Linux 服务器上,IP 和端口分别为:
192.168.1.11:80192.168.1.12:80192.168.1.13:80
网站域名为 www.helloworld.com,公网 IP 为 192.168.1.11。我们将在公网 IP 所在的服务器上部署 Nginx,作为反向代理和负载均衡器,处理所有来自客户端的请求。
本示例使用 加权轮询(weighted round-robin) 策略来分配请求,权重越高的服务器收到请求的几率越大。
http {
# MIME 类型配置,类型定义在 mime.types 文件中
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 日志配置
access_log /var/log/nginx/access.log;
# 负载均衡的后端服务器列表
upstream load_balance_server {
# 权重配置,权值越高被分配到的请求越多
server 192.168.1.11:80 weight=5;
server 192.168.1.12:80 weight=1;
server 192.168.1.13:80 weight=6;
}
# HTTP 服务配置
server {
# 监听 80 端口
listen 80;
# 绑定域名
server_name www.helloworld.com;
# 负载均衡代理所有请求
location / {
# 定义网站根目录
root /root;
# 默认首页文件
index index.html index.htm;
# 转发请求到 upstream 定义的服务器
proxy_pass http://load_balance_server;
# 反向代理头信息配置(可选但推荐)
proxy_set_header Host $host; # 保留原始请求的 Host
proxy_set_header X-Real-IP $remote_addr; # 后端可获取客户端真实 IP
proxy_set_header X-Forwarded-For $remote_addr;
# 代理超时设置
proxy_connect_timeout 90s; # 与后端建立连接超时时间
proxy_send_timeout 90s; # 向后端发送请求超时时间
proxy_read_timeout 90s; # 等待后端响应超时时间
# 缓冲区设置(根据实际页面大小和并发调整)
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
# 客户端请求限制
client_max_body_size 10m; # 允许客户端上传文件的最大大小
client_body_buffer_size 128k; # 缓冲客户端请求体大小
}
}
}负载均衡策略
Nginx 提供了多种负载均衡策略,不同策略适合不同的应用场景,原理在各种分布式系统中基本一致。
轮询(Round Robin)
配置示例:
upstream bck_testing_01 {
server 192.168.250.220:8080;
server 192.168.250.221:8080;
server 192.168.250.222:8080;
}特点:
- 默认所有服务器权重相同(weight=1)。
- 每次请求依次分配给下一台服务器。
- 简单易用,适合后端性能相近的场景。
加权轮询(Weighted Round Robin)
upstream bck_testing_01 {
server 192.168.250.220:8080 weight=3;
server 192.168.250.221:8080; # 默认权重为 1
server 192.168.250.222:8080; # 默认权重为 1
}特点:
- 可以根据服务器性能分配权重,权值越高,分配到的请求越多。
- 适合服务器性能不均衡的集群。
最少连接(Least Connections)
upstream bck_testing_01 {
least_conn;
server 192.168.250.220:8080;
server 192.168.250.221:8080;
server 192.168.250.222:8080;
}特点:
- 优先把请求分配给当前活动连接数最少的服务器。
- 动态分配,更适合处理请求处理时间差异较大的场景。
加权最少连接(Weighted Least Connections)
upstream bck_testing_01 {
least_conn;
server 192.168.250.220:8080 weight=3;
server 192.168.250.221:8080; # 默认权重为 1
server 192.168.250.222:8080; # 默认权重为 1
}特点:
- 在最少连接的基础上加权,性能强的服务器承载更多请求。
- 对于后端性能差异明显且请求处理时间不均匀的集群更合理。
IP Hash
upstream bck_testing_01 {
ip_hash;
server 192.168.250.220:8080;
server 192.168.250.221:8080;
server 192.168.250.222:8080;
}特点:
根据客户端 IP 地址计算哈希值,将请求固定分配给某台服务器。
保证同一用户的请求总是访问同一台服务器(会话粘性)。
注意:后端服务器上下线会改变哈希分配,需要配合健康检查。
普通 Hash(按请求 URI)
upstream bck_testing_01 {
hash $request_uri;
server 192.168.250.220:8080;
server 192.168.250.221:8080;
server 192.168.250.222:8080;
}特点:
- 根据请求 URI 或自定义变量生成哈希值分配请求。
- 常用于静态资源或缓存路由,保证相同 URI 请求总是访问同一台后端。
- 对会话或动态数据不敏感,适合内容固定的分发场景。
多 Webapp
当一个网站功能越来越丰富时,通常会将一些相对独立的功能模块 拆分成独立的 Webapp,便于独立开发、部署和维护。
举例来说,假设 www.helloworld.com 有三个 Webapp:
- finance(金融模块)
- product(产品模块)
- admin(用户中心)
用户访问方式通过上下文(Context Path)区分:
www.helloworld.com/finance/
www.helloworld.com/product/
www.helloworld.com/admin/端口与反向代理问题
- HTTP 默认端口是 80,如果在同一台服务器上启动三个 Webapp,都用 80 端口,会产生端口冲突。
- 因此每个 Webapp 需要绑定 不同端口:
| Webapp | 内部端口 |
|---|---|
| product | 8081 |
| admin | 8082 |
| finance | 8083 |
- 用户访问时不希望带端口号,这时可以使用 Nginx 反向代理:通过上下文路径,将请求转发到对应端口的 Webapp。
http {
# upstream 定义各 Webapp 对应的后端服务器
upstream product_server {
server 127.0.0.1:8081; # 产品模块
}
upstream admin_server {
server 127.0.0.1:8082; # 用户中心模块
}
upstream finance_server {
server 127.0.0.1:8083; # 金融模块
}
server {
listen 80;
server_name www.helloworld.com;
# 默认访问根路径,指向产品模块
location / {
proxy_pass http://product_server;
}
# 各 Webapp 的上下文路径映射
location /product/ {
proxy_pass http://product_server;
}
location /admin/ {
proxy_pass http://admin_server;
}
location /finance/ {
proxy_pass http://finance_server;
}
# 可选:反向代理头信息配置
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}upstream 定义
- 每个 Webapp 使用不同端口或不同服务器实例。
- 可灵活配置负载均衡策略(轮询、加权轮询等)。
location 路径匹配
/根路径通常指向默认 Webapp(示例中是product)。/product/、/admin/、/finance/通过上下文路径映射到对应 Webapp。
端口透明
- 用户无需在 URL 中输入端口号,由 Nginx 在内部完成端口映射。
反向代理头信息
X-Real-IP、X-Forwarded-For让后端 Webapp 获取客户端真实 IP。Host保留原始域名,便于后端进行虚拟主机判断或生成 URL。
扩展与优化
- 可为每个 Webapp 配置独立缓存、负载均衡策略。
- 对不同 Webapp 可以设置不同的超时、缓冲区、访问限制策略。
通过 Nginx 反向代理 + 上下文路径 + 不同端口的独立 Webapp,可以轻松实现一个网站多个模块的独立部署,同时对用户透明,保证访问体验和维护灵活性。
多网站部署
在现代部署中,一台服务器上通常只运行 一个 Nginx 实例,负责接收所有 HTTP/HTTPS 请求。
不同网站或 Webapp 通过 独立的 server 模块 来区分,而不是把所有逻辑写在同一个 server 里。
http {
server {
listen 80;
server_name www.helloworld.com;
# Webapp 或反向代理配置...
}
server {
listen 80;
server_name www.example.com;
# 另一网站的配置...
}
server {
listen 80;
server_name www.test.com;
# 第三网站配置...
}
}- 每个
server块相当于 独立的网站入口,可以单独配置反向代理、静态资源路径、缓存、日志等。 - 当请求到达 Nginx 时,会根据
Host字段匹配到对应的server,实现不同网站的独立访问。
对于一个网站内部有多个功能模块(Webapp)的情况:
- 现代做法也倾向于在 同一个 server 块内部,用 上下文路径(location) 或单独的
upstream配置进行反向代理。 - 每个 Webapp 绑定不同端口或运行在不同容器/服务上,通过反向代理透明访问。
server {
listen 80;
server_name www.helloworld.com;
location /product/ {
proxy_pass http://127.0.0.1:8081;
}
location /admin/ {
proxy_pass http://127.0.0.1:8082;
}
location /finance/ {
proxy_pass http://127.0.0.1:8083;
}
}- 用户访问时无需带端口号,Nginx 内部完成端口映射。
- 每个 Webapp 可独立维护,升级或部署互不影响。
对于大型应用或多租户网站,现代生产环境往往结合容器化部署(Docker、K8s):
- 每个 Webapp 在容器内运行,端口自由分配;
- Nginx 统一反向代理外部请求;
- 可以实现 服务发现 + 自动负载均衡 + 弹性扩容。
单台服务器只运行一个 Nginx 实例,避免端口冲突,同时提高维护和监控效率。
upstream 和 proxy_pass
在 Nginx 中,可以通过两种方式将请求转发到后端 Webapp:
- 通过
upstream定义后端服务器 - 直接在
location使用 IP:Port
使用 upstream + proxy_pass
upstream product_server {
server 127.0.0.1:8081;
}
location /product/ {
proxy_pass http://product_server;
}可扩展性强
支持多台后端服务器,方便负载均衡:
upstream product_server {
server 127.0.0.1:8081 weight=2;
server 127.0.0.1:8084 weight=1;
}支持负载均衡策略
轮询(Round Robin)、加权轮询(Weighted Round Robin)、最少连接(Least Connections)、IP Hash 等。
健康检查
可以与 Nginx Plus 或第三方模块结合,实现服务器健康检查和自动剔除故障节点。
统一管理
后端服务器配置集中,方便维护和修改。
适用场景
大型 Webapp、多实例部署、容器化环境、需要高可用和负载均衡。
直接在 location 使用 IP:Port
location /product/ {
proxy_pass http://127.0.0.1:8081;
}简单直观
适合单实例 Webapp,配置简单。
不可扩展负载均衡
后端增加多台服务器时,需要修改所有 location 配置。
维护成本高
后端 IP/端口变动,需要修改多个 location。
不支持负载均衡或健康检查
适用场景
小型、单实例 Webapp 或测试环境。
总结
- 单实例、简单部署 → 可直接使用 IP:Port。
- 多实例、负载均衡、容器化 → 强烈推荐使用
upstream+proxy_pass,统一管理,易扩展。
静态站点
假设静态资源都放在 /app/dist 目录下,Nginx 配置如下:
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
gzip on;
gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/javascript image/jpeg image/gif image/png;
gzip_vary on;
server {
listen 80;
server_name static.zp.cn;
location / {
root /app/dist;
index index.html;
# 可选择配置 SPA 路由重写
}
}
}部署 MPA(多页应用)的注意事项
目录结构
每个页面有独立的 HTML 文件,例如:
/app/dist
├─ index.html
├─ about.html
├─ contact.html
└─ css/
└─ js/location 配置
默认访问 / 时指向 index.html,其他页面直接访问对应 HTML 文件:
location / {
root /app/dist;
index index.html;
}
location /about/ {
root /app/dist;
index about.html;
}SEO & 缓存
- MPA 更适合 SEO,因为每个页面都有独立 URL。
- 可为静态资源配置缓存:
location ~* \.(js|css|png|jpg|gif|ico)$ {
expires 30d;
add_header Cache-Control "public";
}MPA(多页应用)在 Nginx 默认配置下会 按照文件系统结构映射 URL 路径
假设你的静态站点目录如下:
/app/dist/
├─ index.html
├─ about.html
├─ contact.html
├─ css/
├─ js/server {
listen 80;
server_name www.example.com;
root /app/dist;
index index.html;
}映射规则
- 访问
/→ 返回/app/dist/index.html - 访问
/about.html→ 返回/app/dist/about.html - 访问
/contact.html→ 返回/app/dist/contact.html - 访问
/css/style.css→ 返回/app/dist/css/style.css
注意:路径是 URL 对应文件系统相对路径。Nginx 会把 URL 去掉域名后的路径拼接到 root 上查找文件。
路径必须匹配文件名:如果你想访问 /about/ 而不是 /about.html,需要添加 index 或使用重写:
location /about/ {
root /app/dist;
index about.html;
}否则访问 /about/ 会返回 404。
假设你有子目录 /blog/post1.html,访问 /blog/post1.html 就会映射到 /app/dist/blog/post1.html。
MPA 默认不会自动去掉 .html 扩展名,需要 try_files 或 rewrite 才能实现 /about 映射到 /about.html:
location / {
try_files $uri $uri.html =404;
}部署 SPA(单页应用)的注意事项
路由重写:SPA 通过前端路由管理页面,刷新或直接访问非 / 路径时,服务器默认找不到对应 HTML,需要将所有路径转发到 index.html:
location / {
root /app/dist;
index index.html;
try_files $uri /index.html;
}try_files $uri /index.html; 会先尝试访问实际文件,如果不存在则返回 index.html。
缓存策略
- 对 JS、CSS、图片等静态资源可开启长期缓存。
- 对
index.html设置较短缓存,避免用户访问到旧版本页面:
location /index.html {
expires 1h;
}gzip & 压缩
开启 gzip 压缩,提高静态资源传输效率(已在示例配置中开启)。
安全性
禁止访问隐藏文件或敏感目录:
location ~ /\. {
deny all;
}可限制请求方法,仅允许 GET、HEAD:
limit_except GET HEAD { deny all; }配置访问日志与错误日志,便于调试:
access_log /var/log/nginx/static_access.log;
error_log /var/log/nginx/static_error.log;对静态站点,也可使用 upstream + 多服务器负载均衡,提高访问性能和高可用性。
HTTP/2 与 SSL
如果部署在公网,推荐开启 HTTPS 与 HTTP/2:
listen 443 ssl http2;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;前端构建优化:SPA 部署时,通常使用 Webpack、Vite 等打包工具生成带 Hash 的文件名,结合缓存策略,提高加载速度。
文件服务器
在 Nginx 上快速搭建一个简易文件服务器 的配置,主要用途是让一个目录下的文件和文件夹可以通过浏览器直接访问和浏览。你可以把它理解为一个“轻量级的文件共享服务”,类似 Windows 的共享文件夹或者 FTP,但通过 HTTP 访问。
配置功能
| 配置项 | 作用 |
|---|---|
autoindex on; | 打开目录浏览,浏览器可以看到文件和文件夹列表。默认是关闭的。 |
autoindex_exact_size on; | 显示文件大小,单位 B/KB/MB 等。 |
autoindex_localtime on; | 显示文件的最后修改时间。 |
root /share/fs; | 设置对外开放的目录根路径,即文件服务器目录。 |
charset utf-8,gbk; | 设置页面字符编码,避免中文乱码(Linux 下 UTF-8 正常,Windows 下 GBK 仍可能乱码)。 |
listen 9050; | 指定 HTTP 端口,方便文件服务不和网站端口冲突。 |
示例配置
autoindex on; # 显示目录
autoindex_exact_size on; # 显示文件大小
autoindex_localtime on; # 显示文件修改时间
server {
charset utf-8,gbk; # 字符集,避免中文乱码
listen 9050 default_server;
listen [::]:9050 default_server;
server_name _; # 默认 server
root /share/fs; # 文件服务目录
}打开浏览器访问 http://<服务器IP>:9050/ 即可浏览 /share/fs 目录下的文件和文件夹。
可以直接下载文件,类似一个轻量版 HTTP 文件共享服务。
安全性:默认开启目录浏览可能导致敏感信息泄露,最好在内部网络使用或者加上访问控制:
location / {
autoindex on;
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
}Linux 下 UTF-8 正常显示,Windows 下 GBK 编码的文件名可能仍乱码,解决方法可能需要在 Windows 上统一 UTF-8 文件名或使用文件名转码工具。
简易文件服务适合小型团队使用,不适合高并发或大文件传输场景,如果需要高性能可考虑专业的文件服务器或 CDN。
跨域(CORS)
在 前后端分离的 Web 开发中,前端和后端往往部署在不同端口或不同域名下,这会引发 跨域问题。
- 前端:React/Vue 等单页应用
- 后端:Java、Node.js、Python 等 API 服务
浏览器默认会阻止跨域请求,需要解决跨域才能正常通信。
跨域常用思路
CORS(推荐)
- 后端设置 HTTP 响应头
Access-Control-Allow-Origin,允许指定域名访问。 - 支持跨域 AJAX、fetch 请求,安全灵活。
JSONP(老方案)
- 后端返回 JSON 数据包装成函数调用,前端通过
<script>标签加载。 - 只支持 GET 请求,不推荐新项目使用。
重要
跨域问题指 浏览器出于安全策略,阻止一个网页去请求不同源的资源。
同源(Same-Origin)规则要求:
- 协议(protocol)相同
- 域名(host)相同
- 端口(port)相同
只有三个条件完全相同,浏览器才认为请求是同源,否则就是跨域。
限制跨域的目的
- 浏览器安全策略的一部分 “同源策略” (Same-Origin Policy, SOP)
- 防止恶意网页窃取用户敏感数据,比如 Cookie、LocalStorage 或调用用户账户接口。
- 限制了网页直接跨域访问任意服务器资源,提高了安全性。
触发跨域限制
AJAX / fetch / XMLHttpRequest 请求
- 当前网页发起的异步请求,只要目标不是同源,就会被浏览器限制。
WebSocket
- 虽然协议不同,但某些浏览器也会限制跨域连接。
Fetch API + Credential
- 如果带上
withCredentials或credentials: include,必须明确 CORS 配置,否则浏览器会阻止。
不受跨域限制
<script src="..."><img src="..."><link href="..."><iframe src="...">(受沙箱限制,但不直接阻止请求)
这就是 JSONP 出现的原因:利用 <script> 标签不受跨域限制,返回可执行的 JS 函数。
Nginx 配置跨域示例
enable-cors.conf 文件(CORS 配置片段)
# allow origin list
set $ACAO '*';
# 动态设置单个 origin
if ($http_origin ~* (www.helloworld.com)$) {
set $ACAO $http_origin;
}
# 针对不同请求方法设置 CORS 响应头
if ($cors = "trueget") {
add_header 'Access-Control-Allow-Origin' "$http_origin";
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
# 根据请求方法设置标识
if ($request_method = 'OPTIONS') {
set $cors "${cors}options";
}
if ($request_method = 'GET') {
set $cors "${cors}get";
}
if ($request_method = 'POST') {
set $cors "${cors}post";
}主 Nginx 配置(引入 CORS 配置)
假设前端端口为 9000,后端 API 端口为 8080:
upstream front_server {
server www.helloworld.com:9000;
}
upstream api_server {
server www.helloworld.com:8080;
}
server {
listen 80;
server_name www.helloworld.com;
# API 路径,开启 CORS
location ~ ^/api/ {
include enable-cors.conf;
proxy_pass http://api_server;
rewrite "^/api/(.*)$" /$1 break;
}
# 前端应用路径
location / {
proxy_pass http://front_server;
}
}API 跨域
/api/的请求会被 Nginx 转发到后端 API,同时添加 CORS 响应头。- 浏览器允许跨域访问,前端可以正常调用 API。
前端资源
/路径下的请求直接转发到前端应用(端口 9000)。- 无需跨域处理,因为访问同域名即可。
OPTIONS 预检请求
- 浏览器发送
OPTIONS请求,Nginx 返回允许的跨域方法和头信息。
实际上,CORS 可以在两个地方处理,各有利弊:
在后端配置 CORS
优点:
- 最直接:后端知道请求的来源,可以精准控制允许的域名、方法和头信息。
- 灵活性高:可以根据不同的接口、不同的用户权限设置不同的跨域策略。
- 可控性强:避免 nginx 层配置太多逻辑,保持反向代理简单。
缺点:
- 对于前端分离多个服务时,每个服务都需要配置跨域逻辑,可能重复。
示例(Node.js Express):
const cors = require('cors');
app.use(cors({
origin: 'http://www.helloworld.com',
credentials: true,
methods: ['GET','POST','OPTIONS']
}));在 Nginx 配置 CORS
优点:
- 统一管理:所有 API 接口通过 nginx 反向代理,可以在一处配置 CORS,避免重复修改后端代码。
- 前后端分离时方便:前端只访问统一域名,跨域逻辑由 nginx 处理。
- 性能稍优:避免后端处理大量预检 OPTIONS 请求。
缺点:
- 配置逻辑复杂一点,需要掌握 nginx 的条件判断、头部设置。
- 对不同接口的差异化策略不如后端灵活。
总结
- 小型或单后端项目 → 推荐直接在后端代码中配置 CORS,灵活且易维护。
- 多服务、大型分布式项目 → 可以在 Nginx 层统一配置 CORS,减少重复配置,提高运维效率。
实际上两者可以结合使用:Nginx 统一处理大部分跨域请求,后端针对特定接口做更精细的控制。
分层结构
Nginx 配置文件大致是这样的分层:
main(全局) -> http -> server -> location全局(main)
- 放在
nginx.conf顶层 - 对整个 Nginx 进程生效
- 示例:
worker_processes、error_log、pid - 不在
http/server/location下生效
http 块
- 配置 HTTP/HTTPS 相关全局设置
- 示例:
include mime.types;、default_type、log_format、gzip on;、upstream - 可以包含多个
server块
server 块
- 对应一个虚拟主机(域名 + 端口)
- 示例:
server_name、listen - 可以包含多个
location块
location 块
- 对应请求的路径匹配
- 示例:静态资源路径
/css/、代理路径/api/
Nginx 的指令分为 可继承 和 不可继承:
| 层级 | 继承规则 | 示例 |
|---|---|---|
| 全局 -> http | 大部分全局指令对 http 可继承(例如 error_log 可被覆盖) | error_log logs/error.log; |
| http -> server | 大部分指令可继承,但可在 server 覆盖 | keepalive_timeout 120; 可以在 server 覆盖为 60 |
| server -> location | 可继承,location 可以覆盖 | proxy_connect_timeout、root、index |
注意:
- 并不是所有指令都可继承。官方文档中每个指令会标明作用域(
main、http、server、location)。 - 一旦在更低级别覆盖了,低级别的值生效。
举例说明
http {
keepalive_timeout 120; # http级别默认120s
server {
listen 80;
server_name www.example.com;
# server 层覆盖
keepalive_timeout 60;
location / {
proxy_pass http://127.0.0.1:8080;
# location层再覆盖
keepalive_timeout 30;
}
location /static/ {
root /var/www/html;
# /static/ 的 keepalive_timeout 没设置,则继承 server 的60
}
}
}请求 / → keepalive_timeout = 30(location 覆盖)
请求 /static/xxx.js → keepalive_timeout = 60(继承 server 的值)
越下层,优先级越高,可以覆盖上层设置。
可继承指令:如果下层没有定义,自动使用上层的值。
不可继承指令:只在定义的层生效,不会被下层继承。
注意 location 匹配:Nginx 匹配请求时,会选择最具体的 location,覆盖相关指令。
最佳实践
生产级反向代理配置
# ===============================
# 生产级反向代理配置
# ===============================
worker_processes 1; # Windows 下 1 个进程即可
events {
worker_connections 4096; # 最大并发连接
}
http {
include mime.types;
default_type application/octet-stream;
# 高性能 I/O
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
client_max_body_size 50m;
# 日志
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 logs/access.log main;
error_log logs/error.log warn;
# upstream 负载均衡
upstream backend {
server 127.0.0.1:3001 max_fails=3 fail_timeout=30s; # 后端服务 1
server 127.0.0.1:3002 max_fails=3 fail_timeout=30s; # 后端服务 2
least_conn; # 使用最少连接数的服务器
}
# 可选 proxy 缓存路径
proxy_cache_path C:/nginx/cache levels=1:2 keys_zone=mycache:10m max_size=1g inactive=60m use_temp_path=off;
server {
listen 80;
server_name _; # 匹配所有请求
# 主代理配置
location / {
proxy_pass http://backend; # 转发到 upstream backend
proxy_set_header Host $host; # 保留原始 Host
proxy_set_header X-Real-IP $remote_addr; # 客户端真实 IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 代理链
proxy_http_version 1.1;
proxy_set_header Connection ""; # 解决 HTTP/1.1 长连接问题
# 缓存配置
proxy_cache mycache;
proxy_cache_valid 200 302 10m; # 正常响应缓存 10 分钟
proxy_cache_valid 404 1m; # 404 缓存 1 分钟
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_bypass $http_cache_control;
add_header X-Proxy-Cache $upstream_cache_status; # 查看缓存命中状态
}
# 静态资源单独缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
root html;
expires 30d;
add_header Cache-Control "public";
}
# URL 重写示例
location /oldpath/ {
rewrite ^/oldpath/(.*)$ /newpath/$1 permanent; # 301 永久重定向
}
}
}生产级静态资源服务配置
# ===============================
# 生产级静态资源服务配置
# ===============================
# Worker 进程数
# Windows 下建议 1 个,Linux 可根据 CPU 核心调整
worker_processes 1;
events {
# 每个 worker 最大并发连接数
worker_connections 4096;
}
http {
# 加载 MIME 类型映射
include mime.types;
default_type application/octet-stream;
# 高性能 I/O 设置
sendfile on; # 启用零拷贝,提高静态文件传输效率
tcp_nopush on; # 发送大文件前先打包 HTTP header
tcp_nodelay on; # 减少小包延迟
keepalive_timeout 65; # 长连接超时时间,单位秒
client_max_body_size 50m; # 客户端请求最大体积(上传文件限制)
# gzip 压缩,提高前端加载速度
gzip on;
gzip_disable "msie6"; # IE6 不使用 gzip
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_min_length 256; # 小于 256 字节不压缩
gzip_comp_level 5; # 压缩等级 1~9
# 日志格式
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 logs/access.log main;
error_log logs/error.log warn;
# 服务器块
server {
listen 80; # 监听端口 80
server_name _; # 通配符,匹配所有请求 Host
root html; # 静态文件根目录
index index.html index.htm; # 默认首页
# SPA 前端 fallback
location / {
try_files $uri $uri/ /index.html;
# 尝试文件或目录,不存在则回退到 index.html
}
# 静态资源缓存策略
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 30d; # 浏览器缓存 30 天
add_header Cache-Control "public"; # 声明可缓存
}
# 错误页
error_page 404 /index.html;
}
}一键修改Hosts文件
@echo off
setlocal enabledelayedexpansion
:: 定义要添加的内容和hosts文件路径
set "content=127.0.0.1 www.helloworld.com"
set "hostsPath=%SystemRoot%\System32\drivers\etc\hosts"
:: 检查是否以管理员权限运行
fltmc >nul 2>&1 || (
echo 请以管理员权限运行此脚本!
pause
exit /b 1
)
:: 检查内容是否已存在
findstr /c:"%content%" "%hostsPath%" >nul 2>&1
if %errorlevel% equ 0 (
echo 内容已存在于hosts文件中,无需重复添加。
pause
exit /b 0
)
:: 追加内容到hosts文件
echo.>>"%hostsPath%"
echo %content%>>"%hostsPath%"
:: 检查操作是否成功
if %errorlevel% equ 0 (
echo 成功添加内容到hosts文件。
) else (
echo 添加内容失败,请检查权限或文件状态。
)
pause