跳到正文

静态文件与目录响应

Host 映射可以不经过反向代理,直接用 fn-knock 网关所在文件系统中的一个文件或目录响应请求。它适合发布下载文件、静态文档、小型站点或只读文件目录,不需要另外运行 Web Server。

静态响应仍是完整的 Host 路由:要求登录、高级认证、网关可见性、WAF、定时开放、请求日志和网关节流会在读取文件前生效。它不提供服务器端重写或单页应用(SPA)回退;需要把任意未知路径都返回 index.html 时,应继续使用支持该能力的上游 Web Server。

选择响应类型

添加或编辑业务 Host 时,在 响应类型 中选择:

响应类型请求行为典型用途
反向代理把请求转发到 HTTP、HTTPS 或 WebSocket Target动态 Web 应用和 API
单个文件只在当前 Host 的根路径 / 返回指定文件下载入口、说明文件、固定资源
目录把 URL 路径映射到指定目录中的文件和子目录静态站点、文档和文件浏览

从反向代理切换到静态响应时,页面会要求确认并清除只属于代理的 Target、路径响应、上游 Basic Auth、保留 Host 和目标路径模式。Host 的认证、可见性、WAF、可用时段、标题、图标和分组会保留。关闭编辑窗口前切回反向代理,可以恢复本次尚未保存的代理草稿。

静态映射不会从文件内容自动提取标题或图标。需要在传送门、映射列表或书签中显示友好名称时,手工填写 展示标题 并上传自定义图标。

配置步骤

  1. 使用 子域模式内网穿透 → 子域映射,并确保业务 Host 已进入 fn-knock 网关。
  2. 子域映射 添加或编辑业务 Host,选择 单个文件目录
  3. 服务器路径 旁点击 浏览。可以逐级浏览网关服务器,也可以在地址栏输入绝对路径后按 Enter 前往。
  4. 目录响应进入目标目录后点击 使用当前文件夹;单文件响应先选择普通文件,再点击 使用所选文件
  5. 目录响应按需调整默认文档、目录列表和 README 渲染。
  6. 配置 要求登录、网关可见性、WAF、可用时段、标题和图标,然后保存。
  7. 从实际访问链路请求根路径、一个文件和一个不存在的路径,并在请求分析中核对路由类型与状态码。

浏览服务器路径

路径浏览器显示的是 fn-knock 网关进程可见的文件系统,不是打开管理后台的电脑。已有路径会作为起点;路径为空时,POSIX 平台从 / 开始,Windows 则先显示可用的本机盘符。文件系统根位置只用于导航,不能选作静态目录。Docker 中只能浏览已挂载到容器内的内容,浏览器不会读取宿主机路径,也不会创建或修改挂载。

地址栏支持输入绝对路径,旁边提供根位置、上一级、面包屑和刷新操作。列表始终把目录排在普通文件之前,每页最多显示 100 项,并提供前后翻页;单文件模式只允许选择普通文件,目录模式则使用当前文件夹。项目过多而无法在安全上限内扫描时,整个目录会显示错误,不会只返回一份可能误导选择的截断列表。

浏览器会省略以 . 开头的隐藏名称、以 __ 开头的内部保留名称、特殊文件、无法安全打开的项目,以及受保护路径和它们的后代。受保护路径的上级目录仍可用于前往其他位置,但不能选作静态根目录。符号链接只有在解析后仍位于当前浏览目录内,且没有进入隐藏或受保护位置时才会显示。

点击 使用当前文件夹使用所选文件 时,系统会再次确认该精确路径仍然存在、可读且类型匹配;确认成功只会把路径写回当前映射草稿,仍需保存映射才会生效。这是即时检查,不会锁定文件或挂载点。新建静态映射,或修改服务器路径、响应类型时,保存也会探测路径;只调整目录选项不会重复探测。即使选择和保存时都通过,路径之后仍可能被删除、替换或失去读取权限,网关会在每次请求时重新打开并校验。

单个文件响应

单文件映射只响应 Host 根路径:

text
download.example.com/        -> /srv/downloads/manual.pdf
download.example.com/other   -> 404

网关根据服务器文件名扩展名设置 Content-Type,支持 GETHEAD、范围请求和常见的条件缓存请求。文件内容变化后,ETag 与修改时间会随文件状态更新。URL 不需要包含服务器文件名;查询参数不会改变所选文件。

目录响应

目录映射把请求路径逐级映射到配置根目录:

text
docs.example.com/                 -> /srv/docs/
docs.example.com/assets/app.css   -> /srv/docs/assets/app.css
docs.example.com/manual/          -> /srv/docs/manual/

请求命中目录但 URL 末尾没有 / 时,网关会永久重定向到带斜杠的规范地址;请求命中普通文件但 URL 末尾多了 / 时,会永久重定向到去掉斜杠的地址。两种重定向都会保留查询参数。进入目录后按配置顺序查找默认文档;初始顺序为 index.htmlindex.htm,最多可配置 16 个。名称只能是可见的单个文件名,不能包含路径分隔符;清空列表会关闭默认文档查找。

未找到默认文档时:

  • 目录列表 关闭:返回 404
  • 目录列表 开启:生成当前目录的文件列表;
  • 渲染 README.md 只在目录列表开启时可用,并把当前目录的 README.md 安全渲染在列表下方。

目录列表默认按名称排序,并始终把目录放在普通文件之前。页面可按名称、大小或修改时间切换升降序,带面包屑导航、明暗主题和前后翻页;每页最多显示 100 项。索引界面当前使用英文标签,修改时间固定按北京时间(UTC+8)显示。它不会显示隐藏名称、特殊文件或无法安全打开的条目。

README 使用 GitHub 风格 Markdown,单个文件最大 1 MiB。原始 HTML 和不安全内容会被过滤;图片只允许同源相对地址,外部链接会增加安全属性。只有在没有命中默认文档、实际显示目录列表时才会渲染 README。

目录响应不执行扩展名改写、动态压缩、尾路径回退或 SPA History Fallback,也没有为静态目标配置自定义响应头或缓存策略的入口。请求的文件不存在时直接返回 404

认证、WAF、日志与缓存

静态 Host 与反向代理 Host 使用相同的入站策略:

  • 要求登录 和高级认证在文件读取前检查;局域网来源仍可能命中 local_exempt,公网策略应从真实外部网络验证。
  • 网关可见性、通用黑名单、扫描拦截、反向代理节流和可用时段继续生效。
  • 当前 Host 的 启用 WAF 打开且全局 WAF 已启用时,请求会先经过 WAF,再读取静态内容。
  • 请求日志和 WAF 日志把路由类型分别记录为 静态文件静态目录,上游目标为空;日志不会写入服务器文件系统路径。

公开静态文件使用需要重新验证的公共缓存策略。需要认证或已经带有认证结果的响应使用 private, no-store,避免受保护内容进入共享缓存。生成的目录列表、重定向和错误响应同样不进入公共缓存。

文件系统安全边界

服务器路径 必须是绝对路径,并指向可见的普通文件或目录。网关拒绝文件系统根目录、隐藏目标、父目录穿越、控制字符、Windows UNC / 设备命名空间,以及与 fn-knock 配置、数据、日志、密钥或系统目录重叠的路径。过于宽泛、会把受保护目录包含在内的父目录也会被拒绝。

文件系统名称会按精确拼写处理。在 POSIX 平台(Linux、macOS 等),路径分量开头或结尾的空格不会被自动裁掉,因此 /srv/docs/srv/docs 是两个不同目标;只有完全由空白组成的输入会被拒绝。应优先避免这类容易混淆的名称,并在复制路径时保留真实字符。Windows 仍会拒绝以空格或点结尾的名称、保留设备名和其他不安全名称。

目录内只响应可见的普通文件和子目录;点文件、点目录和 .well-known 不可用。符号链接必须在静态根目录内解析到安全目标;逃出根目录、进入隐藏位置或在校验期间发生变化时,请求会失败。FIFO、Socket、设备文件等特殊类型不会作为下载内容打开。

这些限制不能判断业务内容是否适合公开。仍应为每个站点准备独立的最小目录,使用只读权限,并避免把备份、环境变量、私钥、数据库或应用配置复制到静态根目录。公开目录列表前,应先检查所有子目录和 README 中的链接与图片。

Docker 与平台路径

路径始终从 fn-knock 进程的视角解释:

  • Docker 必须先把宿主机内容只读挂载到容器,再填写容器内路径;宿主机路径本身不可直接使用。
  • Linux、macOS、OpenWrt、飞牛 FPK / Lite 和群晖需要让对应软件包账号拥有目录遍历与文件读取权限。
  • Windows 使用本机盘符绝对路径,例如 C:\Sites\docs;网络共享路径和设备命名空间不受支持。

Docker Compose 示例:

yaml
services:
  fn-knock:
    volumes:
      - /srv/public-site:/srv/public-site:ro

修改挂载后重新创建容器,再在管理后台点击 浏览。路径浏览器应能看到 /srv/public-site;进入该目录并点击 使用当前文件夹,然后保存映射。不要为了读取静态内容而把宿主机根目录、/etc 或 fn-knock 数据卷整体挂载进容器。

静态映射只读取已有文件,不会创建 DNS 记录、开放防火墙端口或改变容器挂载。外部可达性仍由当前部署平台的网关入口、DNS、证书、路由器或隧道决定。

状态码与排错

现象检查项
保存时提示路径不可用绝对路径、文件 / 目录类型、读取权限、受保护路径和 Docker 挂载
路径浏览器看不到文件或目录当前查看的是否为网关 / 容器文件系统、名称是否隐藏或保留、读取权限、受保护路径和符号链接目标
路径浏览器提示目录项目过多改用更小的专用内容目录;不要把宽泛的共享目录直接选作静态根目录
根路径返回 503配置根目录或单文件当前不存在、不可读或不再安全;响应带短暂重试提示
子路径返回 404文件不存在、名称被安全规则隐藏、目录列表关闭,或单文件映射收到了非根路径
返回 405静态响应只接受 GETHEAD
目录显示列表而不是站点首页默认文档名称或优先级不正确,或者对应文件不可读
页面刷新后前端路由 404静态目录没有 SPA 回退;改用支持 History Fallback 的上游 Web Server
请求日志没有上游地址静态响应由网关直接读取文件,这是预期行为

排查时先在编辑窗口打开 浏览,重新定位目标并执行 使用当前文件夹使用所选文件,再从 fn-knock 运行环境确认权限和挂载,最后查看请求日志中的 Host、路由类型、认证结果、WAF 动作与状态码。不要通过扩大到系统目录或授予不必要的 root 权限来绕过路径检查。

相关配置见子域映射Docker Compose 部署WAF安全边界与基线

QQ群:1081609274