迁移后固定链接(permalink,指文章的 URL 结构规则)全部 404,原因集中在两处:Web 服务器的伪静态规则没有跟着迁移,或者数据库里还留着旧域名。按「先查伪静态 → 再换域名 → 最后刷新重写规则」这三步走,绝大多数站点 10 分钟内就能恢复。
迁移后固定链接 404,先查哪两处?
结论:先确认服务器伪静态规则和数据库里的 siteurl、home 两个配置项,这两项覆盖了迁移后固定链接失效的绝大多数场景。
固定链接并不是 WordPress 自己“记住”的路径,而是每次访问都由 Web 服务器把 /archives/123 这类请求重写交给 index.php 处理。换了服务器之后,Nginx 的 try_files、Apache 的 .htaccess 往往没有一起搬过去,请求直接落到目录上,服务器找不到文件就直接返回 404。第二处是数据库:wp_options 表里的 siteurl 和 home 如果仍指向旧域名,WordPress 生成的所有链接都会指回老地址。
查库最快的方式是用 WP-CLI(WordPress 命令行工具,装在服务器上直接操作站点):
wp option get home
wp option get siteurl
wp option get permalink_structure
permalink_structure 返回 /archives/%post_id%、/%postname%/ 这类值,说明结构本身没丢,问题在服务器配置或域名。返回空值则说明结构被清空了,后面第 5 节有恢复办法。
Nginx 和 Apache 的伪静态规则该怎么写?
结论:Nginx 必须显式写 try_files,Apache 必须有 mod_rewrite 加 .htaccess 两样都到位。
Nginx 在站点的 server {} 块里加这一段,改完执行 nginx -t && nginx -s reload:
location / {
try_files $uri $uri/ /index.php?$args;
}
Apache 则检查三件事:mod_rewrite 是否启用(apache2ctl -M | grep rewrite 或 httpd -M | grep rewrite)、站点配置里目录段是否写了 AllowOverride All(写成 None 时 .htaccess 会被完全忽略)、网站根目录下是否存有 WordPress 标准规则:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
用宝塔、aaPanel 这类面板的,直接在「网站 → 设置 → 伪静态」选 WordPress 模板,注意模板里的 RewriteBase 是否与子目录部署一致。站点放在 /blog 子目录时,RewriteBase /blog/ 和 try_files $uri $uri/ /blog/index.php?$args; 都要带上子目录。
数据库里的旧域名怎么安全替换?
结论:用 WP-CLI 的 search-replace 做全表替换,它会正确反序列化再重新序列化,避免主题选项、小工具里的数据被打断。
先备份再动手:
wp db export backup-$(date +%F).sql
wp search-replace 'old.com' 'new.com' --all-tables --precise --dry-run
--dry-run 只报告将影响多少行、不落库,确认数字符合预期后去掉它再跑一次。加 --precise 可以避免误伤相似字符串。站点已上 HTTPS 的,要同时替换协议:
wp search-replace 'http://new.com' 'https://new.com' --all-tables --precise
没有 WP-CLI 环境时,用 Better Search Replace 插件处理,单次建议只勾选一张表,wp_posts 和 wp_options 两张必做。替换完执行 wp cache flush 清对象缓存,再清一遍 CDN 和浏览器缓存,否则看到的还是旧内容。
改完配置还是 404,怎么刷新重写规则?
结论:WordPress 的重写规则缓存在数据库 wp_options 的 rewrite_rules 字段里,改配置后必须手动刷新一次。
三种刷新方式,任选其一:后台「设置 → 固定链接」页面,不动任何选项直接点「保存更改」,这一步就会重建规则;或用 WP-CLI 执行 wp rewrite flush --hard;或删掉 wp_options 表中的 rewrite_rules 记录,下一个请求会自动重建。
刷新后仍有个别页面 404 的,按这个顺序排查:分页链接 /page/2 失效 → Nginx 缺少对 $args 的透传;只有文章页失效、首页正常 → permalink_structure 为空;后台正常、前台全 404 → 检查是否开了「站点地址」与「WordPress 地址」不一致;全部页面都 404 → 回看第 2 节的 try_files 与 AllowOverride。
迁移后固定链接结构变了,怎么恢复成原来的样子?
结论:/archives/%post_id% 与 /%postname%/ 互转不需要重发文章,改结构后旧 URL 会 404,必须配 301 跳转。
恢复原结构直接执行 wp option update permalink_structure '/archives/%post_id%/' 再 wp rewrite flush --hard。如果原站用的是 /%postname%/,新站因为没有中文别名被转成了 ID 形式,改回后要给老链接做 301:Nginx 用 rewrite ^/archives/(\d+)/?$ /?p=$1 permanent;,Apache 用 RedirectMatch 301 ^/archives/([0-9]+)/?$ /?p=$1。跳转规则务必放在 try_files 之前,否则会被 index.php 先截获。
从 Typecho、ZBlog 换到 WordPress 的,除了伪静态,还要注意原站的 /archives/{cid}/ 与 WordPress 的 ?p= 编号不一定对应,需要用插件的重定向表逐条映射。
迁移属于典型的高频踩坑场景,遇到规则对不上时,把 nginx -t 的报错、wp option get home 的返回值和实际 404 的 URL 一起贴到 GJ 站长论坛的问答版块,信息给全基本一轮就能定位。发帖注意 30 秒冷却间隔,账号先上传头像才能发主题。
一句话总结:固定链接 404 不是数据丢了,是「服务器路由 + 数据库域名 + 重写缓存」这三层里断了一层,按顺序各查一遍,配好 301 再刷新一次规则,链接就回来了。