JavaScript 已禁用

为了获得更好的体验,请启用JavaScript,或点击下方链接跳转:

跳转至百度
Skip to content

Nginx配置

本文分享一下本博客使用Nginx反向代理的一些心得

主要涉及ssl,连接优化,vitepress路径处理和通用处理二级域名等。

二级域名

通用处理二级域名

通过mapupstream指令可以实现通过一个server块通用处理二级域名

nginx
# 1. 定义二级域名到 upstream 的映射表
map $subdomain $upstream_name {
    default "";                          # 默认空值(不转发)
    "twikoo" "twikoo_backend";           # twikoo.dl-web.top → 8080
}

# 2. 定义 upstream 块(管理后端服务)
upstream twikoo_backend {
    server localhost:8080;
    keepalive 32;  # 启用长连接
}


server {
    listen 80;
    listen 443 ssl http2;
    # 同时匹配主域名和子域名
    server_name dl-web.top ~^(?<subdomain>.+)\.dl-web\.top$;

    # 公共配置
    index index.php index.html index.htm default.php default.htm default.html;
    access_log /www/sites/dl-web.top/log/access.log;
    error_log /www/sites/dl-web.top/log/error.log;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    resolver 8.8.8.8 ipv6=off;

    # HTTP 跳转 HTTPS
    if ($scheme = http) {
        return 301 https://$host$request_uri;
    }

    # SSL 配置
    ssl_certificate /www/sites/dl-web.top/ssl/fullchain.pem;
    ssl_certificate_key /www/sites/dl-web.top/ssl/privkey.pem;
    ssl_protocols TLSv1.3 TLSv1.2 TLSv1.1 TLSv1;
    ssl_ciphers 省略;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_stapling on;
    ssl_stapling_verify on;
    add_header Strict-Transport-Security "max-age=31536000";

    # 错误页处理
    error_page 497 https://$host$request_uri;

    # 限流配置
    limit_conn perserver 300;
    limit_conn perip 25;
    limit_rate 512k;

    location / {
        proxy_set_header Host $host;  # 关键:传递原始域名(status.dl-web.top)给后端
        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;  # 传递协议(http/https),避免后端误判
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port $server_port;

        # 逻辑1:有效二级域名 → 转发到对应服务
        if ($upstream_name != "") {
            proxy_pass http://$upstream_name;
            break;  # 终止后续处理
        }

        # 逻辑2:无效二级域名(非主域名且无映射) → 直接返回404/502
        if ($subdomain != "") {  # $subdomain有值 → 是二级域名但未匹配映射
            return 404;  # 或 return 502; 按需选择
        }
        
        # 逻辑3:主域名 → 处理静态资源(仅当$subdomain为空时执行)
        charset utf-8;
        root /www/sites/dl-web.top/index/dist;
        try_files $uri $uri.html $uri/ =404;
        error_page 404 /404.html;
        error_page 403 /404.html;

        # 静态资源缓存(仅主域名生效)
        location ~* ^/assets/ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }
    }

    # 新增:确保二级域名的所有路径都被转发到后端
    location ~ ^/(assets|api|socket.io|dashboard|login) {
        if ($upstream_name != "") {
            proxy_pass http://$upstream_name$request_uri;
            break;
        }
    }

    # 3. 主域名的 /api 转发(子域名不生效)
    location /api {
            proxy_pass http://localhost:9123;
            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 Referer $http_referer;
    }
}


# 独立的 status.dl-web.top 配置
server {
    listen 80;
    listen 443 ssl http2;
    server_name status.dl-web.top;

    # 共用 SSL 配置
    ssl_certificate /www/sites/dl-web.top/ssl/fullchain.pem;
    ssl_certificate_key /www/sites/dl-web.top/ssl/privkey.pem;

    # 所有请求直接转发到 Uptime Kuma
    location / {
        proxy_pass http://localhost:3001;
        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;
    }
}


server {
    listen 80;
    listen 443 ssl http2;
    server_name umami.dl-web.top;

    # 共用 SSL 配置
    ssl_certificate /www/sites/dl-web.top/ssl/fullchain.pem;
    ssl_certificate_key /www/sites/dl-web.top/ssl/privkey.pem;

    # 所有请求直接转发到 Uptime Kuma
    location / {
        proxy_pass http://localhost:3000;
        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;
    }
}

普通配置二级域名

这样配置可以避免相互之前产生影响

下面的示例就是我配置了status.dl-web.topumami.dl-web.top两个子域名

nginx

# 独立的 status.dl-web.top 配置
server {
    listen 80 ; 
    listen 443 ssl http2 ; 
    server_name status.dl-web.top; 
    # 共用 SSL 配置
    ssl_certificate /www/sites/dl-web.top/ssl/fullchain.pem; 
    ssl_certificate_key /www/sites/dl-web.top/ssl/privkey.pem; 
    # 所有请求直接转发到 Uptime Kuma
    location / {
        proxy_pass http://localhost:3001; 
        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; 
    }
}

server {
    listen 80 ; 
    listen 443 ssl http2 ; 
    server_name umami.dl-web.top; 
    # 共用 SSL 配置
    ssl_certificate /www/sites/dl-web.top/ssl/fullchain.pem; 
    ssl_certificate_key /www/sites/dl-web.top/ssl/privkey.pem; 
    # 所有请求直接转发到 Uptime Kuma
    location / {
        proxy_pass http://localhost:3000; 
        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; 
    }
}

图片防盗链

在 Nginx 中配置图片防盗链,核心是通过限制请求来源(Referer)来阻止其他网站非法引用你的图片资源,从而节省带宽并保护内容版权。以下是详细的配置方法:

一、防盗链原理

浏览器在请求资源时,会在 HTTP 头中携带 Referer 字段,记录该请求的来源页面 URL。Nginx 可以通过检测 Referer 字段,允许可信域名的请求,拒绝其他域名的请求(如返回 403 错误或替换为默认图片)。

二、基础配置:限制 Referer

在 Nginx 的配置文件(如 nginx.conf 或站点配置文件 xxx.conf)中,针对图片资源(如 .jpg.png 等)添加防盗链规则:

配置示例

nginx
server {
    listen 80;
    server_name yourdomain.com; # 你的域名

    # 图片防盗链配置
    location ~* \.(jpg|jpeg|png|gif|webp|bmp|svg)$ {
        # 允许直接访问(Referer为空,如直接在浏览器输入图片URL)
        # 允许可信域名(自己的网站域名)
        valid_referers none blocked yourdomain.com *.yourdomain.com;

        # 如果Referer不在允许列表中,执行以下操作
        if ($invalid_referer) {
            return 403; # 拒绝访问,返回403错误
            # 或返回自定义图片:rewrite ^/ /forbidden.png break;
        }

        # 其他图片相关配置(可选)
        expires 30d; # 缓存30天
        add_header Cache-Control "public, max-age=2592000";
    }
}

三、配置参数详解

  1. location ~\* \.(jpg|jpeg|png|gif|webp|bmp|svg)$
    • 匹配所有图片格式的 URL(~* 表示不区分大小写),可根据需要添加其他格式(如 .ico.avif 等)。
  2. valid_referers 定义允许的来源,支持以下值:
    • none:允许无 Referer 的请求(如直接在浏览器输入图片 URL)。
    • blocked:允许 Referer 被防火墙或代理隐藏的请求(Referer 为空或不含协议)。
    • yourdomain.com:允许来自本域名的请求。
    • *.yourdomain.com:允许来自所有子域名的请求(如 blog.yourdomain.com)。
    • 其他可信域名:如 trusted.com *.trusted.com(允许合作网站引用)。
  3. if ($invalid_referer)
    • 当Referer不在valid_referers列表中时,$invalid_referer为true执行内部逻辑:
      • return 403:直接拒绝,返回 “403 Forbidden”。
      • rewrite ^/ /forbidden.png break:跳转到自定义的 “防盗链提示图”(需提前准备 forbidden.png 并放在网站根目录)。

四、进阶配置:更灵活的规则

1. 允许多个可信域名

如果需要允许多个外部域名引用(如合作网站),可在 valid_referers 中添加:

nginx
valid_referers none blocked yourdomain.com *.yourdomain.com trusted1.com;

2. 对非法请求返回默认图片

替代 403 错误,返回自定义提示图(更友好):

nginx
if ($invalid_referer) {
    rewrite ^/ /anti-hotlink.png break; # 替换为你的提示图路径
}

需确保 anti-hotlink.png 放在 Nginx 配置的 root 目录下(如 /usr/share/nginx/html)。

3. 针对 HTTPS 站点

如果网站启用了 HTTPS(listen 443 ssl),Referer 可能包含 https://,配置无需额外修改(valid_referers 会自动匹配协议)。

五、注意事项

  1. Referer 的局限性

    • Referer 可被伪造,无法完全杜绝防盗链,但能阻止绝大多数普通盗链。
    • 部分浏览器或隐私模式可能不发送 Referer,因此 valid_referers 中建议保留 noneblocked
  2. 静态资源服务器 如果图片放在独立的静态资源域名(如 img.yourdomain.com),需在该域名的 Nginx 配置中单独添加防盗链规则。

  3. 配置生效 修改后需重启或重载 Nginx 使配置生效:

bash
nginx -t # 检查配置是否有误
systemctl restart nginx # 重启Nginx(CentOS/Ubuntu)
# 或 service nginx reload

六、测试防盗链效果

  1. 合法引用:在 yourdomain.com 的页面中引用图片,应正常显示。
  2. 非法引用:在其他域名(如 otherdomain.com)的页面中引用图片,应返回 403 或自定义提示图。
  3. 直接访问:在浏览器地址栏输入图片 URL(无 Referer),应正常显示(如果配置了 none)。

通过以上配置,可有效阻止大部分非法盗链行为,保护图片资源。根据实际需求,可调整允许的域名和非法请求的处理方式。

防盗链进阶

Referer 头可以被轻易伪造,因此基于 Referer 的防盗链机制只能阻止普通用户的盗链行为,无法防范专业攻击者。若要进一步增强安全性,可以结合以下方法:

一、使用 HTTP 签名(防篡改)

为图片 URL 添加签名参数,验证请求合法性:

实现原理

服务端生成签名: 在生成图片 URL 时,计算一个包含时间戳、图片路径的签名,并附加到 URL 中。

python
# Python示例:生成带签名的URL
import hmac
import hashlib
import time

def generate_signed_url(path, secret_key, expires=3600):
    timestamp = int(time.time()) + expires  # 签名有效期
    string_to_sign = f"{path}{timestamp}"
    signature = hmac.new(secret_key.encode(), string_to_sign.encode(), hashlib.sha256).hexdigest()
    return f"https://yourdomain.com{path}?t={timestamp}&s={signature}"

Nginx 验证签名: 使用 ngx_http_lua_modulengx_http_map_module 验证签名:

nginx
location /images/ {
    # 提取参数
    map $request_uri $path {
        "~^(?<p>/images/[^?]+)" $p;
    }
    map $arg_t $timestamp {}
    map $arg_s $signature {}

    # 验证时间戳(防过期)
    if ($timestamp < $msec) {
        return 403;
    }

    # 验证签名(与服务端计算逻辑一致)
    set $string_to_sign "$path$timestamp";
    set $my_signature "";  # 通过Lua或其他方式计算签名
    if ($my_signature != $signature) {
        return 403;
    }
}

优点

  • 无法伪造 URL,必须知道密钥才能生成有效签名。
  • 可设置 URL 有效期(如 30 分钟后失效),适合临时访问。

通过用户会话验证请求合法性:

实现方式

用户登录后设置 Cookie

python
# 用户登录时设置加密Cookie
response.set_cookie('auth_token', encrypt(user_id), expires=3600)

Nginx 验证 Cookie

nginx
location /images/ {
    # 检查Cookie是否存在且有效
    access_by_lua_block {
        local auth_token = ngx.var.cookie_auth_token
        if not auth_token or not verify_token(auth_token) then
            return ngx.exit(403)
        end
    }
}

变种:JSON Web Token (JWT)

nginx
# 使用ngx_http_auth_jwt_module验证JWT
location /images/ {
    auth_jwt "Restricted";
    auth_jwt_key_file /path/to/public_key.pem;
}

三、基于用户行为分析(防爬虫)

通过分析请求模式识别异常访问:

实现方法

IMPORTANT

limit_req_zone不是写在server块内,而是写在http块内

限制请求频率
nginx
# 限制每个IP每分钟最多请求100次图片
limit_req_zone $binary_remote_addr zone=img_limit:10m rate=100r/m;

location /images/ {
    limit_req zone=img_limit;
}
检测异常请求模式
  • 同一 IP 短时间内请求大量不同图片。
  • 非浏览器 UA(如 curlwget)请求图片。
nginx
# 禁止非浏览器UA访问
if ($http_user_agent !~* (Chrome|Firefox|Safari|Edge)) {
    return 403;
}

四、使用客户端渲染(防直接抓取)

将图片 URL 隐藏在 JavaScript 中动态生成:

实现示例

html
<!-- HTML中不直接暴露真实图片URL -->
<div id="image-container"></div>

<script>
// 通过JavaScript动态加载图片(带签名或token)
fetch('/api/get-image-url?path=/images/test.jpg')
  .then(res => res.json())
  .then(data => {
    const img = new Image();
    img.src = data.signed_url; // 如:/images/test.jpg?t=123&s=abc
    document.getElementById('image-container').appendChild(img);
  });
</script>

优点

  • 爬虫难以直接获取真实图片 URL。
  • 可结合用户会话进一步验证。

五、使用 Cloudflare 等 CDN 安全功能

CDN 提供商通常提供更高级的防盗链功能:

Cloudflare 配置示例

  1. 启用 Hotlink Protection: 在 Cloudflare 控制面板中,进入 Rules → Hotlink Protection,配置允许的域名。
  2. 使用 Cloudflare Access: 对特定路径设置身份验证,仅允许授权用户访问。
  3. WAF 规则: 配置自定义 WAF 规则,阻止异常图片请求。

六、图片水印(终极方案)

对图片添加不可见水印或显著水印,降低被盗用的价值:

实现方法

服务端动态添加水印

python
from PIL import Image, ImageDraw, ImageFont

def add_watermark(img_path, text):
    img = Image.open(img_path)
    draw = ImageDraw.Draw(img)
    font = ImageFont.truetype("arial.ttf", 36)
    draw.text((10, 10), text, font=font)
    return img

使用 Nginx 模块: 如 ngx_http_image_filter_module 或第三方模块。

七、综合方案推荐

  1. 初级防护
    • 基础 Referer 验证(防普通盗链)。
    • 图片水印(降低盗用价值)。
  2. 中级防护
    • 签名 URL(防 URL 篡改)。
    • 频率限制(防爬虫)。
  3. 高级防护
    • 用户会话验证(精准控制)。
    • CDN 安全功能 + WAF(抵御大规模攻击)。

八、权衡安全性与性能

增强安全性通常会增加系统复杂度和性能开销,需根据实际需求选择:

  • 普通网站:Referer + 水印 + 频率限制 即可。
  • 高价值内容:考虑签名 URL + 用户认证 + CDN。
  • 极端安全需求:结合多种方法,并定期更换密钥。
最近更新