目录

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 的 dataconfincvendor 等目录不应该被外部直接访问。

可以保留这样的安全规则:

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 和缩略图仍然无法显示,例如:

<img id="dw__logo" src="/_media/logo.png">

以及:

<img src="/_media/capture_2025-11-11_185838.png?w=90&h=90&tok=68fe3f">

但奇怪的是,某些带参数的图片又可以访问:

/_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 重写。

进入:管理 → 配置设置 → 高级设置

设置:

使用更整洁的URLuserewrite.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 缓存
浏览器缓存

这次最终的关键点在于

  1. Nginx 使用 ^~ /_media/ 防止媒体请求被静态图片规则截走
  2. Cloudflare 清理旧的 404 缓存

完成这两步后,DokuWiki 的 URL 重写、媒体文件、Logo 和缩略图都恢复正常。