internal 指令用于标记仅限 Nginx 内部跳转访问的 location,必须置于 ^~ 或 = 精确匹配的具名块中,通过 rewrite last、auth_request 或 X-Accel-Redirect 触发,实现语义级硬隔离。
internal 指令的作用不是“限制访问”,而是标记路径身份:它让 Nginx 明确这个 location 只接受自己内部发起的跳转请求(比如 rewrite last、auth_request 成功后的子请求、X-Accel-Redirect 响应头触发等),所有来自浏览器、curl、扫描器的原始 HTTP 请求,一律不匹配、直接返回 404 —— 连路径是否存在都不暴露。
它不是鉴权开关,也不是防火墙规则,而是一道语义级闸门。用对了,就能实现真正的“硬隔离”。
internal 只能在 具名前缀匹配的 location 块里生效,不能写在 server 或 http 级,也不能用于正则或泛匹配块。
✅ 正确写法:
location ^~ /_api/ { internal; proxy_pass http://backend/;}
❌ 错误写法:
location ~ ^/_api/ { internal; } → 正则 location 不支持 internal
location / { internal; } → 整个站点变 404,且语义错误server { internal; } → 语法报错,根本无法 reload关键点:
^~ 或 = 明确匹配类型,避免歧义 /_api/、/_files/),方便后续 rewrite 或 X-Accel-Redirect 精确指向 proxy_pass 和 rewrite redirect 同在一个块里internal location 自身没有入口。你得先定义一个对外暴露的入口 location,并用 Nginx 原生内部跳转方式把它“送进去”。
三种可靠触发方式:
rewrite ... last;
外部请求 /api/user → 重写为 /_api/user → 重新匹配 location → 触发 internal
注意:必须是 last(不是 break 或 redirect),否则不重新匹配,进不了 internal 块
auth_request 子请求验证后自动流转
location /api/ { auth_request /auth; proxy_pass http://backend;}location = /auth { internal; # 鉴权地址本身也要加 internal,防绕过 proxy_pass http://auth-svc;}
后端响应头 X-Accel-Redirect
后端返回:X-Accel-Redirect: /_files/report.pdf
Nginx 匹配到 location ^~ /_files/ { internal; alias /data/files/; } → 内部读取并流式返回
注意:头里的路径必须精确匹配 location 前缀,不能带协议、域名、相对路径(如 ../)
攻击者不会老老实实走你设计的入口。常见绕过方式包括:
/auth → 所以 /auth location 也必须加 internal /_files/config.json → 所以 /_files/ location 必须加 internal location /api/)漏掉子路径 → 应该用 location ^~ /_api/ 这类精确前缀 别把 internal 放在 location / 或 location /api/ 这种宽泛块里,容易误拦或失效。
internal 解决的是“能不能命中”,不是“该不该放行”。建议叠加:
auth_request、签名验证、IP 白名单、时间戳检查 limit_except GET POST { deny all; } 限制 method,避免意外方法触发 proxy_set_header X-Real-IP $remote_addr; 给后端做风控 allow/deny + satisfy any,此时不应再用 internal(二者逻辑冲突)不复杂但容易忽略