====== 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 重写规则 =====
我最初添加了类似下面的规则:
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;
}
页面访问没有问题,但媒体文件无法访问。
后来发现,问题出在 Nginx 的静态资源缓存规则上。
配置里还有这样的规则:
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 30d;
error_log /dev/null;
access_log /dev/null;
}
而 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,并放在静态资源缓存规则之前。**
最终使用的规则如下:
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;
}
这里使用了:
^~
表示只要匹配到这个前缀,就不再继续匹配后面的正则 location。
这样 ''/_media/logo.png'' 就不会被图片缓存规则截走,而是会正确交给 DokuWiki 的 ''fetch.php'' 处理。
----
===== 四、不要直接开放 data 目录 =====
DokuWiki 的 ''data''、''conf''、''inc''、''vendor'' 等目录不应该被外部直接访问。
可以保留这样的安全规则:
location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md|data|conf|bin|inc|vendor)
{
return 404;
}
这样可以防止访问:
/data/media/logo.png
/conf/local.php
/inc/
媒体文件应通过:
/_media/logo.png
由 DokuWiki 控制输出。
----
===== 五、Logo 和缩略图仍然无法显示 =====
媒体文件可以直接打开后,我又遇到了第二个问题。
页面中的 Logo 和缩略图仍然无法显示,例如:
以及:
但奇怪的是,某些带参数的图片又可以访问:
/_media/logo.png?t=1706014361&w=64&h=64&tok=e2dbf1
为了进一步判断问题,我在终端使用 `curl -I` 测试了几个地址:
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"
结果发现:
/_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 后台:
缓存 → 配置 → 清除所有内容
清理后再次测试:
curl -I "https://www.example.com/_media/logo.png"
返回变成:
HTTP/2 200
content-type: image/png
此时 Logo 和缩略图也恢复正常。
----
===== 七、最终推荐配置片段 =====
下面是最终比较稳定的 DokuWiki 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;
}
修改完成后检查配置并重载 Nginx:
----
===== 八、DokuWiki 后台配置 =====
DokuWiki 后台还需要开启 URL 重写。
进入:管理 → 配置设置 → 高级设置
设置:
使用更整洁的URL''userewrite'' 为''.htaccess''
启用在 URL 中使用斜杠作为命名空间的分隔符''useslash''
----
===== 九、排查经验总结 =====
这次问题主要分为三个阶段:
第一,页面 URL 重写正常,但媒体文件 404。
原因是 ''/_media/*.png'' 被 Nginx 的图片缓存 location 提前匹配,导致 Nginx 直接去文件系统寻找 ''/_media/'' 目录。
解决方法是给 ''/_media/'' 单独写:
location ^~ /_media/
并放在图片缓存规则之前。
第二,媒体文件直接访问恢复,但 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}}