我的Nginx 的配置分析

一. 如何确定当前服务器有哪些Nginx配置

两个问题:

  1. 当前机器的主配置入口是哪个文件?
  2. 最终加载了哪些conf.

确认主入口文件:

nginx -V 2>&1 | grep -oE -- '--conf-path=[^ ]+'
--conf-path=/etc/nginx/nginx.conf

打开文件后查看 include /etc/nginx/modules-enabled/*.conf; 有这么一行.

然后继续查看有这个地方引入了哪些文件

ls -lah /etc/nginx/sites-enabled
lrwxrwxrwx 1 root root   36 Jan 15 11:22 card-game -> /etc/nginx/sites-available/card-game
lrwxrwxrwx 1 root root   38 Jan 20 08:58 zhangrh.top -> /etc/nginx/sites-available/zhangrh.top

readlink -f /etc/nginx/sites-enabled/*
/etc/nginx/sites-available/card-game
/etc/nginx/sites-available/zhangrh.top

这里可以看到, 我们饮用了两个地址的配置 分别是card-game, zhangrh.top.

二. 分析我的Nginx配置

# /etc/nginx/sites-available/zhangrh.top

# -----------------------------
# HTTP -> HTTPS
# -----------------------------
server {
  listen 80; # 监听80端口 也就是http
  server_name zhangrh.top www.zhangrh.top; # 这个server处理的域名, 只有host匹配域名, 才会走这个server

  location / { # / 是前缀匹配, 匹配所有的路径
    return 301 https://$host$request_uri; # 直接301重定向, $host是请求的Host, $request_uri原始路径+query
  }
}

# -----------------------------
# HTTPS
# -----------------------------
server {
  # 监听443端口(https), ssl: 启用TLS. 
  # http2: 开启HTTP/2(访问静态资源更快)
  # websocket依旧是Http1.1/upgrade
  listen 443 ssl http2;
  server_name zhangrh.top www.zhangrh.top;

	# TLS证书文件pem, 私钥文件key
  ssl_certificate     /etc/nginx/ssl/zhangrh.top.pem;
  ssl_certificate_key /etc/nginx/ssl/zhangrh.top.key;

  # -----------------------------
  # Tracking endpoint: /t or /t/
  # -----------------------------
  # location ~: 正则匹配locaton
  # ^开头 /t匹配 /?可选一个/ $结尾, 所以只能匹配/t, /t/
  location ~ ^/t/?$ {
	  # 这个location的访问日志写到指定目录
	  # track 是一个log_format名称, 在http{}全局中定义过
    access_log /var/log/nginx/track.log track;
    # 不添加缓存
    add_header Cache-Control "no-store, no-cache, must-revalidate, max-age=0" always;
    # 兼容旧行为, always 即使是204/4xx/5xx也加入状态码, 这些默认不加
    add_header Pragma "no-cache" always;
    # 返回204 No Conent(无响应体)
    return 204;
  }

  # -----------------------------
  # Verify file: direct access
  # -----------------------------
  # 微信验证文件
  # location =: 精确匹配, 只能访问这个路径
  location = /3ddb389bdb8ab254c1b8ede286ec0f08.txt {
	  # 这个location的请求根目录, 请求路径会拼到这个后面形成实际的文件路径
    root /var/www/card-game-site.new;
    default_type text/plain; # 没有扩展名, / 类型不明确时, 默认响应text/plain
    try_files /3ddb389bdb8ab254c1b8ede286ec0f08.txt =404; # 按照这个顺序找文件, 没有的话404
  }

  # -----------------------------
  # Root redirect to blog
  # -----------------------------
  # 根目录直接跳转到博客
  # 这里是相对路径跳转, host保持不变
  location = / {
    return 301 /20250122_website/;
  }

  # -----------------------------
  # API -> backend (include WebSocket)
  #
  # IMPORTANT:
  # - Keep original path (NO rewrite).
  # - Your WS URLs are:
  #     /api/20250120_card-game01/ws
  #     /api/20250126-card_game02/ws
  #   So upstream will receive the same path.
  # -----------------------------
  # api开始反向代理, ^~ 一旦匹配这个前缀, 后面的正则location就不能用了, 保护/api的优先级
  location ^~ /api/ {
    access_log /var/log/nginx/api_ws.log;
    # 请求转发到当前机器的3001端口
    #没有尾部/, 转发时保持原样
    # /api/xxx => upstream 仍然是/api/xxx 对ws路径关键
    proxy_pass http://127.0.0.1:3001;
    # 代理到upstream时, 使用http/1.1
    # websocket 升级依赖http/1.1的upgrade机制, 所以是1.1
    proxy_http_version 1.1;

    # websocket upgrade (also ok for normal http)
    # Upgrade: 客户端的Upgrade头传给upstream
    # Connection: 告诉upstream这是升级链接
    proxy_set_header Upgrade $http_upgrade;
    # $connection_upgrade来自全局map, 用来在有upgarde时, 设置为upgarde. 否则close
    proxy_set_header Connection $connection_upgrade;

		# 原始host转发
    proxy_set_header Host $host;
    # 真实客户端ip
    proxy_set_header X-Real-IP $remote_addr;
    # 客户端ip追加到XFF列表, (多层代理, 保持路径)
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    # 告诉后端原始请求是什么 http / https
    proxy_set_header X-Forwarded-Proto $scheme;
    
		# 读写超过1小时, 就关闭. 对长链接很重要
    proxy_read_timeout 3600;
    proxy_send_timeout 3600;
  }

  # -----------------------------
  # Static assets cache: /<project>/static/...
  # -----------------------------
  # 静态资源匹配
  location ~ "^/([A-Za-z0-9_-]+)/static/" {
    root /var/www/card-game-site.new;
    # 允许真实存在的文件访问, 否则直接404.
    try_files $uri =404;
    access_log off;
    # 浏览器缓存30天
    expires 30d;
  }

  # -----------------------------
  # Add trailing slash: /<project> -> /<project>/
  # -----------------------------
  location ~ "^/([A-Za-z0-9_-]+)$" {
    return 301 /$1/;
  }

  # -----------------------------
  # SPA fallback (two-level): /<project>/<entry>/... -> /<project>/<entry>.html
  #
  # FIX:
  # - add "=404" to stop internal redirect cycle when fallback file doesn't exist
  # -----------------------------
  # 两级spa回退
  location ~ "^/([A-Za-z0-9_-]+)/([A-Za-z0-9_-]+)(?:/.*)?$" {
    root /var/www/card-game-site.new;
    try_files $uri $uri/ /$1/$2.html =404;

    add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always;
    add_header Pragma "no-cache" always;
    add_header Expires "0" always;
  }

  # -----------------------------
  # SPA fallback (project root): /<project>/... -> /<project>/index.html
  #
  # FIX:
  # - add "=404" to stop internal redirect cycle when fallback file doesn't exist
  # -----------------------------
  # 项目根spa回退.
  location ~ "^/([A-Za-z0-9_-]+)/" {
    root /var/www/card-game-site.new;
    try_files $uri $uri/ /$1/index.html =404;

    add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always;
    add_header Pragma "no-cache" always;
    add_header Expires "0" always;
  }

  # -----------------------------
  # Default: deny other root paths
  # -----------------------------
  location / {
    return 404;
  }
}

三. 不懂的点:

  • ssl:启用 TLS什么意思?
    • listen 443 ssl;表示这个端口的链接不再是明文http. 先做一层TLS握手/加密
    • 浏览器连到zhangrh.top: 443, 先校验证书, 协商加密孙法, 建立加密通道
    • 通道建立以后, 浏览器在这个加密通道发送http请求
  • location ^~ /api/ 能写成 location ~ ^/api/吗?
    • 技术上能写, 但是^~ 表示的是强位优先级, 不再去看后面的正则location
    • ~ ^/api/: 会参与正则location竞争, 如果有更靠前的正则会被抢走
    • 会被其他的比如项目上的html正则误匹配
  • $http_upgrade;啥意思
    • $http_xxx表示: 客户端里请求头是xxx值
  • $connection_upgrade来自全局map, 用来在有upgarde时, 设置为upgarde. 否则close, 这个没有理解, 这是一个转发也就是ng收到这个请求, 然后转发到3001, 那长链接, 是首先浏览器和ng建立, 然后ng再和3001端口建立吗?
    • 两段连接是独立的.
    • 浏览器请求WebSocket时, Ng也需要发起WebSocket请求
    • 普通Api没有Upgrade头, 如果强行发Connection: upgrade会被误会, 所以全局用一个map生成变量 $connection_upgrade;
    • 如果有$http_upgrade时, $connection_upgrade 就时upgrade
    • 如果没有, 就是close
  • location ~ 这种是不是一直向下匹配
    1. 先看location =
    2. 在看location /xxx
    3. 如果最长匹配时 ^~ 就用这个, 停止匹配
    4. 按照顺序检查政策 location ~, 第一个正则
    5. 没有任何正则 用第二步找到最长前缀
    6. 不会匹配多个, 只有一个最终location
  • / -> // 这个是不是不用也行, 感觉其他网站都不会这么用.
    • 如果全部用绝对路径引用资源
    • 要么框架, 构建构建帮忙处理base path
    • 要么服务端路由, 不靠静态相对路径
    • 那我后面检查了我的frontend 这个工程, 确认了路径即可 保证资源路径都是绝对路径
  • proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade; 和proxy_set_header Connection $connection_upgrade;这一行的区别?
    • 不能合并, 因为是两个不同的key, 导致的不同的value
    • 合并指的是$connection_upgrade能代表两个值.
posted @ 2026-02-05 20:14  张润昊  阅读(6)  评论(0)    收藏  举报