blog:url重写

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
blog:url重写 [2026/05/22 17:38] – 移除 - 外部编辑 (未知日期) 127.0.0.1blog:url重写 [2026/05/22 19:23] (当前版本) – [一、环境说明] doge24190
行 1: 行 1:
 +====== DokuWiki 配置 URL 重写后媒体文件、Logo 和缩略图无法显示的排查记录 ======
  
 +最近我在给自己的 DokuWiki 配置 URL 重写,也就是让原本类似:
 +
 +  /doku.php?id=start
 +
 +这样的地址变成更简洁的:
 +
 +  /start
 +
 +配置过程中,页面本身很快就能正常访问了,但随后遇到了一个比较隐蔽的问题:**上传的媒体文件、网站 Logo 和部分缩略图无法正常显示**。
 +
 +这篇文章记录一下完整排查过程和最终解决方案。
 +
 +
 +----
 +
 +
 +===== 一、环境说明 =====
 +
 +
 +我的 DokuWiki 安装路径为:
 +
 +  /www/wwwroot/dokuwiki
 +
 +
 +媒体文件实际存放路径为:
 +
 +  /www/wwwroot/dokuwiki/data/media
 +
 +
 +网站使用:Nginx + PHP + DokuWiki + Cloudflare
 +
 +DokuWiki 媒体文件并不是直接通过 ''/data/media/xxx.png'' 访问,而是通过 DokuWiki 的 PHP 程序处理,例如:
 +
 +  /_media/logo.png
 +
 +最终会被重写到:
 +
 +  /lib/exe/fetch.php?media=logo.png
 +
 +这点非常重要,不能为了让图片能访问就直接开放 ''/data/media'' 目录。
 +
 +----
 +
 +===== 二、最初的 Nginx 重写规则 =====
 +
 +
 +我最初添加了类似下面的规则:
 +
 +<code nginx>
 +location / {
 +    try_files $uri $uri/ @dokuwiki;
 +}
 +
 +location @dokuwiki {
 +    rewrite ^/_media/(.*) /lib/exe/fetch.php?media=$1 last;
 +    rewrite ^/_detail/(.*) /lib/exe/detail.php?media=$1 last;
 +    rewrite ^/_export/([^/]+)/(.*) /doku.php?do=export_$1&id=$2 last;
 +    rewrite ^/(.*) /doku.php?id=$1&$args last;
 +}
 +</code>
 +
 +页面访问没有问题,但媒体文件无法访问。
 +
 +后来发现,问题出在 Nginx 的静态资源缓存规则上。
 +
 +配置里还有这样的规则:
 +
 +<code nginx>
 +location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
 +{
 +    expires 30d;
 +    error_log /dev/null;
 +    access_log /dev/null;
 +}
 +</code>
 +
 +而 DokuWiki 的媒体 URL 是这样的:
 +
 +  /_media/logo.png
 +
 +因为它以 ''.png'' 结尾,所以请求会被上面的图片缓存规则提前匹配,Nginx 会尝试直接寻找:
 +
 +  /www/wwwroot/dokuwiki/_media/logo.png
 +
 +但实际文件并不在这个位置,而是在:
 +
 +  /www/wwwroot/dokuwiki/data/media/logo.png
 +
 +因此返回 404。
 +
 +----
 +
 +===== 三、修复媒体文件无法访问 =====
 +
 +解决方法是:**给 ''/_media/''、''/_detail/''、''/_export/'' 单独写高优先级 location,并放在静态资源缓存规则之前。**
 +
 +最终使用的规则如下:
 +
 +<code nginx>
 +location ^~ /_media/ {
 +    rewrite ^/_media/(.*)$ /lib/exe/fetch.php?media=$1 last;
 +}
 +
 +location ^~ /_detail/ {
 +    rewrite ^/_detail/(.*)$ /lib/exe/detail.php?media=$1 last;
 +}
 +
 +location ^~ /_export/ {
 +    rewrite ^/_export/([^/]+)/(.*)$ /doku.php?do=export_$1&id=$2 last;
 +}
 +
 +location / {
 +    try_files $uri $uri/ @dokuwiki;
 +}
 +
 +location @dokuwiki {
 +    rewrite ^/(.*) /doku.php?id=$1&$args last;
 +}
 +</code>
 +
 +这里使用了:
 +
 +<code nginx>
 +^~
 +</code>
 +
 +表示只要匹配到这个前缀,就不再继续匹配后面的正则 location。
 +
 +这样 ''/_media/logo.png'' 就不会被图片缓存规则截走,而是会正确交给 DokuWiki 的 ''fetch.php'' 处理。
 +
 +----
 +
 +===== 四、不要直接开放 data 目录 =====
 +
 +DokuWiki 的 ''data''、''conf''、''inc''、''vendor'' 等目录不应该被外部直接访问。
 +
 +可以保留这样的安全规则:
 +
 +<code nginx>
 +location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md|data|conf|bin|inc|vendor)
 +{
 +    return 404;
 +}
 +</code>
 +
 +这样可以防止访问:
 +
 +  /data/media/logo.png
 +  /conf/local.php
 +  /inc/
 +
 +媒体文件应通过:
 +
 +  /_media/logo.png
 +
 +由 DokuWiki 控制输出。
 +
 +----
 +
 +===== 五、Logo 和缩略图仍然无法显示 =====
 +
 +
 +媒体文件可以直接打开后,我又遇到了第二个问题。
 +
 +页面中的 Logo 和缩略图仍然无法显示,例如:
 +
 +<code html>
 +<img id="dw__logo" src="/_media/logo.png">
 +</code>
 +
 +以及:
 +
 +<code html>
 +<img src="/_media/capture_2025-11-11_185838.png?w=90&h=90&tok=68fe3f">
 +</code>
 +
 +但奇怪的是,某些带参数的图片又可以访问:
 +
 +  /_media/logo.png?t=1706014361&w=64&h=64&tok=e2dbf1
 +
 +为了进一步判断问题,我在终端使用 `curl -I` 测试了几个地址:
 +
 +<code bash>
 +curl -I "https://www.example.com/_media/logo.png"
 +curl -I "https://www.example.com/_media/logo.png?t=1706014361&w=64&h=64&tok=e2dbf1"
 +curl -I "https://www.example.com/lib/exe/fetch.php?media=logo.png"
 +curl -I "https://www.example.com/lib/exe/fetch.php?media=logo.png&t=1706014361&w=64&h=64&tok=e2dbf1"
 +</code>
 +
 +结果发现:
 +
 +  /_media/logo.png
 +
 +返回:
 +
 +  HTTP/2 404
 +  cf-cache-status: HIT
 +
 +而:
 +
 +  /lib/exe/fetch.php?media=logo.png
 +
 +返回:
 +
 +  HTTP/2 200
 +  content-type: image/png
 +
 +这说明源站和 DokuWiki 本身已经正常,真正的问题是:**Cloudflare 缓存了之前的 404 页面。**
 +
 +===== 六、最终解决:清理 Cloudflare 缓存 =====
 +
 +进入 Cloudflare 后台:
 +
 +  缓存 → 配置 → 清除所有内容
 +
 +
 +清理后再次测试:
 +
 +<code bash>
 +curl -I "https://www.example.com/_media/logo.png"
 +</code>
 +
 +返回变成:
 +
 +  HTTP/2 200
 +  content-type: image/png
 +
 +此时 Logo 和缩略图也恢复正常。
 +
 +----
 +
 +===== 七、最终推荐配置片段 =====
 +
 +下面是最终比较稳定的 DokuWiki Nginx 伪静态配置片段:
 +
 +<code nginx>
 +# 禁止访问敏感文件和目录
 +location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md|data|conf|bin|inc|vendor)
 +{
 +    return 404;
 +}
 +
 +# SSL 证书验证目录
 +location ^~ /.well-known/ {
 +    allow all;
 +}
 +
 +# DokuWiki 媒体文件
 +location ^~ /_media/ {
 +    rewrite ^/_media/(.*)$ /lib/exe/fetch.php?media=$1 last;
 +}
 +
 +location ^~ /_detail/ {
 +    rewrite ^/_detail/(.*)$ /lib/exe/detail.php?media=$1 last;
 +}
 +
 +location ^~ /_export/ {
 +    rewrite ^/_export/([^/]+)/(.*)$ /doku.php?do=export_$1&id=$2 last;
 +}
 +
 +# DokuWiki 页面 URL 重写
 +location / {
 +    try_files $uri $uri/ @dokuwiki;
 +}
 +
 +location @dokuwiki {
 +    rewrite ^/(.*) /doku.php?id=$1&$args last;
 +}
 +
 +# 静态图片缓存
 +location ~* \.(gif|jpg|jpeg|png|bmp|swf|webp|svg|ico)$
 +{
 +    expires 30d;
 +    error_log /dev/null;
 +    access_log off;
 +}
 +
 +# JS/CSS 缓存
 +location ~* \.(js|css)$
 +{
 +    expires 12h;
 +    error_log /dev/null;
 +    access_log off;
 +}
 +</code>
 +
 +修改完成后检查配置并重载 Nginx:
 +
 +----
 +
 +===== 八、DokuWiki 后台配置 =====
 +
 +DokuWiki 后台还需要开启 URL 重写。
 +
 +进入:管理 → 配置设置 → 高级设置
 +
 +设置:
 +
 +使用更整洁的URL''userewrite'' 为''.htaccess''
 +启用在 URL 中使用斜杠作为命名空间的分隔符''useslash''
 +----
 +
 +===== 九、排查经验总结 =====
 +
 +这次问题主要分为三个阶段:
 +
 +第一,页面 URL 重写正常,但媒体文件 404。
 +
 +原因是 ''/_media/*.png'' 被 Nginx 的图片缓存 location 提前匹配,导致 Nginx 直接去文件系统寻找 ''/_media/'' 目录。
 +
 +解决方法是给 ''/_media/'' 单独写:
 +
 +<code nginx>
 +location ^~ /_media/
 +</code>
 +
 +并放在图片缓存规则之前。
 +
 +第二,媒体文件直接访问恢复,但 Logo 和缩略图仍然异常。
 +
 +这时需要用 ''curl -I'' 分别测试:
 +
 +  /_media/logo.png
 +  /lib/exe/fetch.php?media=logo.png
 +
 +如果 ''fetch.php'' 能返回 200,说明 DokuWiki 正常,问题不在 PHP 层。
 +
 +第三,发现 Cloudflare 返回的是旧的 404 缓存。
 +
 +判断依据是响应头里出现:
 +
 +  cf-cache-status: HIT
 +  age: xxxx
 +  HTTP/2 404
 +
 +说明请求甚至没有回到源站,而是 Cloudflare 直接返回了缓存结果。
 +
 +最终清理 Cloudflare 缓存后,问题全部解决。
 +
 +----
 +
 +===== 十、结论 =====
 +
 +DokuWiki 配置 URL 重写时,媒体文件无法显示并不一定是 DokuWiki 本身的问题,常见原因有:
 +
 +  Nginx location 匹配顺序错误
 +  静态资源缓存规则截走了 /_media/ 请求
 +  Cloudflare 缓存了旧的 404
 +  DokuWiki 页面缓存或缩略图缓存未刷新
 +
 +排查时不要只看浏览器页面显示效果,最好用:''curl -I''
 +
 +分别检查:
 +
 +  /_media/xxx.png
 +  /lib/exe/fetch.php?media=xxx.png
 +
 +这样可以快速判断问题到底出在:
 +
 +  Nginx 重写
 +  DokuWiki PHP 处理
 +  Cloudflare 缓存
 +  浏览器缓存
 +
 +这次最终的关键点在于
 +
 +  - Nginx 使用 ^~ /_media/ 防止媒体请求被静态图片规则截走
 +  - Cloudflare 清理旧的 404 缓存
 +
 +完成这两步后,DokuWiki 的 URL 重写、媒体文件、Logo 和缩略图都恢复正常。
 +
 +{{tag>原创 dokuwiki}}