WordPress换域名后永久链接404的完整修复指南:从数据库替换到伪静态配置
2026/9/20 9:19:15 网站建设 项目流程

接手过很多次“站点换域名”的活儿,每次最头疼的不是换域名本身,而是换完以后整站文章页、分类页集体404。首页明明能打开,后台有时候能进有时候进不去,进去了发文章、改固定链接又提示一堆错。这篇文章就把我处理这类问题的完整思路写出来:从永久链接失效的根源,到数据库替换、序列化数据避坑、Web服务器配置、最终清理缓存和旧域名跳转,一次讲透。

1. 换域名后永久链接失效:先定位坏在哪一层

1.1 问题现象:不是所有页面都打不开

很多朋友遇到的情况是:换完域名,新域名能打开首页,但点进任何一篇文章或者分类页,直接给出404。更迷惑的是,有时候后台能登录,有时候登录后又被弹回去,或者页面CSS样式全丢,图片全部不显示。

这些现象背后的原因其实各不相同:

  • 首页能打开,文章页404:说明Web服务器运行正常,WordPress程序文件也没问题,但 URL 重写规则没有正确工作。要么是.htaccess(Apache环境)里的规则不对,要么是 Nginx 的try_files配置缺失,要么是固定链接规则根本没生效。
  • 后台登录后反复跳回登录页:这通常是siteurlhome这两个选项不一致,或者数据库里存的还是旧域名,导致 WordPress 生成的 Cookie 作用域、重定向地址全部基于旧域名。
  • 图片、样式全丢:页面HTML能加载,但里面所有静态资源的URL还是旧域名,这100%是数据库里存的是旧地址,浏览器去请求旧域名当然全部失败。

1.2 永久的根因:WordPress的URL都来自数据库,不是自动识别的

很多人误以为“我把域名解析到服务器,WordPress就会自动用新域名生成链接”,这是最大的误区。WordPress 里所有链接的生成都依赖于两个选项:siteurlhome,它们存放在wp_options表中。你后台上传图片、发文章、生成文章链接时,WordPress 会拿这两个值去拼绝对地址。

我把站点迁移理解为三层结构,排查时必须按层走,不能一上来就乱改:

  1. 数据库层:存着siteurlhome、文章内容里的旧域名、插件选项里的旧域名。
  2. 配置文件层:wp-config.php.htaccess或 Nginx 配置,决定请求如何被转发到index.php
  3. 服务器层:域名解析、SSL证书、Web服务器监听指向。

永久链接(固定链接)失效,本质上是第三层没接到第一层。.htaccess里的规则原本是“把所有请求转发给index.php”,如果路径有问题,请求根本没到 WordPress 手里,自然无法根据文章的 URL 别名(slug)去数据库里匹配文章。

1.3 和“固定链接”设置有什么关系

WordPress 后台“设置 → 固定链接”里选择的那种结构,比如/archives/%post_id%.html/%postname%/,只是告诉 WordPress“用这种格式造URL”。它会不会生效,还要看 PHP 进程是否具备写.htaccess的权限。换域名后,如果你没去后台保存过固定链接,WordPress 的重写规则还是旧的。而且很多人换了域名以后根本进不去后台,规则就一直没刷新,于是404一直持续。

所以,解决思路应该是:先把数据库里的旧域名统一改成新域名,再确保 Web 服务器规则正确,最后进后台手动保存一次固定链接,让规则重新生成。

2. 动手之前:备份、表结构和“序列化数据”的坑

2.1 先备份再动刀,这不是废话

我见过不少人在 phpMyAdmin 里直接执行“替换域名”的SQL,结果整站数据库损坏,最后只能恢复备份。如果你不想在凌晨翻车,开工前一定要做两件事:

  • 用主机面板的数据库备份功能,或者命令mysqldump -u用户名 -p 数据库名 > backup.sql导出一份完整数据库。
  • 把整个wp-content目录打包下载。主题、插件丢了可以重下,但uploads目录里的图片、附件丢了基本找不回。

这里多说一句:备份出来的 SQL 文件建议先下载到本地,不要只在服务器上存一份。因为某些“批量替换”操作会把数据改得半死不活,你需要在本地留一份完好的原始文件随时恢复。

2.2 wp_options 和永久链接相关的关键行

wp_options表里和永久链接、站点域名直接相关的选项主要有这几个:

option_name作用
siteurlWordPress 程序文件所在的完整地址,后台登录、接口请求都依赖它
home站点对外访问的完整地址,文章链接、前端页面URL都基于它
permalink_structure固定链接结构,如/%postname%/
rewrite_rules已经生成的重写规则缓存,保存固定链接设置时重新生成

手动处理时,很多人只改了前两个,以为就完事了。实际上文章内容、自定义菜单、小工具、插件配置里可能存着大量旧地址,这些同样会造成图片失效、跳转异常等问题。

2.3 序列化数据的坑:为什么直接写SQL替换会白屏

这是换域名时最容易踩的雷。WordPress 里的很多字段,特别是wp_options里的小工具配置、主题选项,以及wp_postmeta里的页面构建器数据,都是用 PHP 的serialize()函数序列化后存储的。

序列化字符串长这样:

a:2:{s:8:"siteurl";s:22:"https://old-domain.com/";}

其中s:22表示后面字符串的长度是22个字符。如果你用一行简单的 SQL 去做全局替换:

UPDATE wp_options SET option_value = REPLACE(option_value, 'https://old-domain.com', 'https://new-domain.com');

假设旧域名是https://old-domain.com(20个字符),新域名是https://new-domain-long.com(26个字符),替换完之后字符串里的s:20还是原来的数字,但实际内容已经变成26个字符。PHP 反序列化的时候发现长度对不上,直接返回false,WordPress 加载这个选项就会报错,严重时整站白屏。

所以这里必须明确一件事:只要涉及批量替换URL,优先使用带反序列化处理能力的工具,而不是 phpMyAdmin 里裸奔 SQL。

2.4 什么工具能安全处理序列化数据

我个人常用的方案有三种,按推荐程度排序:

  1. WP-CLI(命令行):wp search-replace命令会自动处理序列化数据,还支持--precise精确匹配,速度非常快。
  2. Better Search Replace 插件:后台可视化操作,不需要命令行权限,执行前还能开 Dry Run 预览,适合新手。
  3. 自己写 PHP 脚本:调用 WordPress 的$wpdb遍历表,对每个字段尝试unserialize()serialize(),但脚本必须处理好各种边界情况,工作量较大。

如果是几十篇文章的小站,用插件就够了。如果是日更的大型站点,或者数据库里有几十万条记录,建议直接用 WP-CLI。我一般会在替换前先跑一遍--dry-run,看清楚会替换多少处,再真正执行。

3. 正确更新数据库:从 URL 替换到固定链接刷新

3.1 用 WP-CLI 完成核心替换(推荐)

如果你的服务器能通过 SSH 访问,这是最高效的方式。进入 WordPress 根目录后:

wp search-replace 'https://old-domain.com' 'https://new-domain.com' --all-tables --precise --recurse-objects --dry-run

参数说明:

  • --all-tables:处理数据库中所有表,而不是只处理 WordPress 核心表。
  • --precise:要求精确匹配,避免old-domain.com.evil.com这种模糊值被误替换。
  • --recurse-objects:递归处理序列化数组和对象内部的值,解决前面提到的序列化长度问题。
  • --dry-run:只统计会替换多少处,不实际修改。

确认结果符合预期后,去掉--dry-run再执行一遍:

wp search-replace 'https://old-domain.com' 'https://new-domain.com' --all-tables --precise --recurse-objects

这条命令会把wp_optionswp_postswp_postmetawp_comments等所有表里的旧域名统一替换掉,同时调整序列化字符串里的长度数字,不会再出现白屏问题。

执行完之后,再确认一下站点地址和首页地址:

wp option get siteurl wp option get home

如果还是旧域名,手动更新:

wp option update siteurl 'https://new-domain.com' wp option update home 'https://new-domain.com'

3.2 用 Better Search Replace 插件(适合虚拟主机)

没有 SSH 权限时,可以在旧域名还打得开后台的情况下,先安装一个 Better Search Replace 插件(或者把旧站点做成维护模式,通过插件临时访问),然后按以下步骤操作:

  1. 后台进入“工具 → Better Search Replace”。
  2. “Search for”填旧域名,如https://old-domain.com
  3. “Replace with”填新域名,如https://new-domain.com
  4. 选择所有数据表。
  5. 勾选“Dry run”先跑一次,查看需要替换的数量。
  6. 确认无误后取消勾选“Dry run”,执行替换。

这个插件的核心逻辑就是安全处理序列化数据,它会先尝试反序列化,再进行字符串替换并重新序列化。整个过程比手写SQL稳得多。

3.3 文章内容和上传文件里残留的旧URL

wp search-replace已经覆盖了wp_posts.post_contentwp_postmeta,所以文章正文里的链接、媒体库附件路径都会一起被替换。不过,有一个细节经常被忽略:旧的文章缩略图、特色图片的_wp_attached_file元数据,以及图集里引用的附件ID,通常也都被替换干净了,但如果当初是通过外部URL插入的图片,那就不会被处理。这时候需要去“媒体库”里重新上传或修改链接。

另外,如果你用了 Elementor、WPBakery 这类页面构建器,它们很多配置会存成 JSON 或序列化数据,也会被 WP-CLI 的--recurse-objects一并处理。我遇到过一次 Elementor CSS 文件迟迟不更新的情况,是因为 Elementor 在wp-content/uploads/elementor/css下生成了带哈希的 CSS 文件,但页面引用的还是新域名下的旧哈希路径。做完数据库替换后,去“Elementor → 工具 → Regenerate CSS”点一次重建就好。

3.4 刷新永久链接规则

数据库替换完成后,需要让 WordPress 重新生成重写规则。这一步可以在后台操作,也可以用命令行:

  • 后台方式:登录后进入“设置 → 固定链接”,不修改任何选项,直接点“保存更改”。这会让 WordPress 调用flush_rewrite_rules()重新生成规则并尝试写入.htaccess
  • 命令行方式:
wp rewrite flush --hard

之所以要保存固定链接,是因为rewrite_rules这个选项里缓存了旧域名生成的重写规则。如果不刷新,即使数据库里其他值都改好了,部分配置了缓存的站点依然会404。

4. 服务器这一层:.htaccess 与 Nginx 规则不能漏

4.1 Apache 环境的 .htaccess 默认规则

如果网站运行在 Apache 下,WordPress 根目录的.htaccess里至少要有下面这段:

# BEGIN 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

这段规则的意思是:如果一个请求对应的文件或目录在磁盘上不存在,就把它统一交给根目录下的index.php去处理。WordPress 拿到这个请求后,再按照你的固定链接结构去匹配具体的文章、分类、标签页。

如果你更换域名时还把网站从一个子目录搬到了根目录,比如原来在https://old.com/blog/下,现在要放到https://new.com,那.htaccess里的RewriteBase /必须跟着调整。否者请求会被错误地转发到/blog/index.php,而那个目录其实已经不存在了,404自然就来了。

换完域名后,如果.htaccess被系统重建过,但权限没给够,WordPress 无法自动写入文件,固定链接也会失效。遇到这种情况,手动把上面那段规则放进去,并确认文件可写即可。

4.2 Nginx 环境的伪静态配置

Nginx 下没有.htaccess,所有规则写在站点配置里。核心是location块里的try_files

server { listen 80; server_name new-domain.com www.new-domain.com; root /var/www/wordpress; index index.php index.html; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; } }

try_files $uri $uri/ /index.php?$query_string;是 Nginx 实现 WordPress 伪静态的关键。它的意思是:先尝试用当前请求路径找真实文件,找不到就找目录,再找不到就把请求转给index.php,并把原来的查询字符串带上。

很多人在 Nginx 下换完域名后404,检查点通常就这么几个:

  • 新域名的 server 块是否真的存在,且server_name写的是新域名。
  • root指向的目录有没有放 WordPress 文件。
  • PHP 的fastcgi_pass路径是否和当前 PHP 版本匹配。
  • 配置改动后有没有执行nginx -t检查语法,并systemctl reload nginx重载。

4.3 旧域名做301跳转,别让权重和流量流失

换新域名,旧域名不要直接废弃。正确的做法是把旧域名所有请求301到新域名对应路径,既能保住搜索引擎积累的权重,也能让老访客通过旧链接自动落到新站。

Apache 环境可以在旧域名站点根目录的.htaccess最前面放:

<IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{HTTP_HOST} ^old-domain\.com$ [NC,OR] RewriteCond %{HTTP_HOST} ^www\.old-domain\.com$ [NC] RewriteRule ^(.*)$ https://new-domain.com/$1 [R=301,L] </IfModule>

Nginx 环境给旧域名单独建一个 server 块:

server { listen 80; server_name old-domain.com www.old-domain.com; return 301 https://new-domain.com$request_uri; } server { listen 443 ssl; server_name old-domain.com www.old-domain.com; # 这里配置旧域名的 SSL 证书,如果没有证书,可以只做 80 跳转 return 301 https://new-domain.com$request_uri; }

很多人忽略了一点:旧域名如果启用了HTTPS,但没有为旧域名续期SSL证书,https://old-domain.com会直接证书报错,根本到不了跳转逻辑。所以稳妥的做法是:如果旧域名没有证书,只保留80端口跳转;如果有证书,再配置443跳转。

4.4 域名解析和CDN回源的问题

更换域名后,首先要确认新域名已经解析到服务器IP,解析生效后再去动搜索引擎收录的事。如果你还用了CDN,比如Cloudflare,记得把新域名添加到CDN,并更新回源地址,否则用户访问新域名时CDN回源到旧域名,会出现无限跳转或证书不匹配。

CDN域名之间还有一层冷门坑:如果原先图片是由CDN域名提供的,比如cdn.old-domain.com,数据库替换时如果直接用old-domain.comnew-domain.com,会把cdn.old-domain.com也变成cdn.new-domain.com。如果你的CDN已经配置了对应的新域名CNAME,那没问题;如果没有,所有图片都会404。处理这种场景,我建议数据库里只替换主站域名,CDN访问地址的切换放到CDN管理后台去做,不要把CDN域名一起SQL替换掉。

5. 换完域名后常见的“玄学”问题排查

5.1 后台登录一直循环,进不去怎么办

换完域名后最抓狂的就是后台根本进不去。你输入新域名/wp-admin,页面跳转到https://new-domain.com/wp-login.php,登录后又被弹回wp-login.php?redirect_to=...,始终进不去。

这通常有几个原因:

  • siteurlhome没有改干净,或者一个改了另一个没改。解决方法是先确保这两个值都是新域名,并清理浏览器Cookie和站点缓存。
  • 服务器或CDN层有强制HTTPS跳转,但新域名的SSL证书还没生效。访问时页面一直在HTTP和HTTPS之间来回跳。先确认浏览器地址栏的小锁是否正常。
  • 插件缓存了旧的重定向规则。到wp-content/plugins里暂时把缓存类插件(WP Rocket、W3 Total Cache 等)改名禁用,登录成功后再启用。
  • 反向代理配置问题,比如 Cloudflare 的 SSL 模式是“灵活”,但源站没有部署证书,导致无限跳转。这时候把 Cloudflare SSL 改成“完全”或“完全(严格)”,并确保源站也有证书。

如果确实进不去后台,最快的救急方式是在wp-config.php里加两行强制覆盖:

define('WP_HOME', 'https://new-domain.com'); define('WP_SITEURL', 'https://new-domain.com');

加在/* That's all, stop editing! Happy blogging. */这一行之前。这会强制 WordPress 使用新地址,数据库里的值暂时被忽略。登录后台后,再去“设置 → 常规”里确认地址正确,然后可以把这两行删掉,或者保留作为固定配置(实际很多人选择保留)。

5.2 页面能打开但图片不显示

页面HTML正常,但图片全是裂图,打开新标签页访问图片URL又跳回旧域名,或者404。这种情况基本可以断定:媒体库中的URL没有替换干净,或者浏览器/CDN缓存了旧资源。

处理方式:

  1. 确认数据库里的_wp_attached_file_wp_attachment_metadata中的路径没有旧域名残留。用 Better Search Replace 或 WP-CLI 再全库搜一次。
  2. 如果图片上传用的是相对路径/wp-content/uploads/...,那一般不受域名影响;如果存的是绝对路径https://old-domain.com/wp-content/uploads/...,就必须要替换。
  3. 检查是否有对象缓存、页面缓存插件。比如 WP Rocket 的预生成缓存文件里还写着旧URL,需要在设置里清空缓存并重新预加载。
  4. 如果有CDN,还要去CDN控制台“刷新缓存”或“提交URL刷新”。

替换完成以后,还可以在后台“媒体库”里看图片是否正常显示预览。如果还是不显示,用浏览器的开发者工具(F12)查看具体资源的请求地址,是旧域名还是新域名,能直接判断是缓存问题还是数据库没改干净。

5.3 HTTPS 换域名后混合内容

如果旧站本来就是HTTPS,通常问题不大。如果旧站是HTTP,新域名部署了HTTPS,就要小心“混合内容”问题:页面主体通过HTTPS加载,资源却还是HTTP地址,浏览器会默认阻止部分HTTP请求。

解决方案是在数据库替换时直接把URL从http://old-domain.com替换成https://new-domain.com,一步到位。如果已经换完了才发现历史数据里还有HTTP,就再跑一遍:

wp search-replace 'http://new-domain.com' 'https://new-domain.com' --all-tables --precise --recurse-objects --dry-run

确认替换数量合理后去掉--dry-run执行。注意:如果数据库里已经存在https://new-domain.com这样的新地址,这步替换不会动它们,因为搜索的是http://而不是https://。另外,也要检查主题、插件里有写死HTTP资源的情况,比如某些主题的Customizer里保存了Google Fonts地址。

5.4 文章里旧链接全部要跳转,有更细的规则吗

如果旧站仍然在线,数据库替换后文章里的链接已经变成新域名,所以文章内的旧跳转需求通常已经不存在。但如果是“新域名刚启用、旧域名还得继续跑一段时间”的过渡期,比如还在等用户更新收藏夹,那么除了旧域名301之外,还可以对某个特定的旧文章路径做跳转,例如旧地址https://old.domain.com/?p=123应该跳到新地址对应的文章。WordPress 原生就支持?p=123这种查询,只要你配置了“文章ID”样式的固定链接结构,旧查询就能自动匹配到新文章。这个原理适用于新旧固定链接结构一致的情况。

如果旧站用的是/index.php/2024/10/hello-world/这种路径,新站用的是/%postname%/,数据库替换后页面URL已经变化,旧站301跳转也只能跳到新站首页,具体到每篇文章的跳转映射关系就要额外写重定向规则了。这种情况建议旧站先不要直接停,把文章逐一迁移后再通过爬虫数据或日志统计去做定向跳转。

6. 迁移操作清单:我每次换域名都按这个顺序来

最后整理一份我自己的标准操作顺序,按这个顺序来,翻车概率会低很多。强烈建议把它保存成自己的迁移SOP:

  1. 备份数据库和wp-content目录,下载到本地。
  2. 新域名完成DNS解析,确认解析生效(ping new-domain.com或使用在线工具)。
  3. 在新域名对应的服务器目录放好 WordPress 文件,导入数据库。
  4. 修改wp-config.php里的数据库连接信息(如果数据库名、用户名变了)。
  5. 用 WP-CLI 或 Better Search Replace 做一次全库 URL 替换,先 Dry Run 再执行。
  6. 确认siteurlhome已经是新域名。
  7. 检查.htaccess或 Nginx 伪静态规则;需要的话在wp-config.php里临时加上WP_HOMEWP_SITEURL强制覆盖。
  8. 访问新域名首页,看是否正常;能进后台的话,去“设置 → 固定链接”保存一次。
  9. 检查文章页、分类页、标签页、搜索结果页是否能正常打开。
  10. 检查媒体库图片是否显示,必要时在 Elementor 或主题设置里重建CSS缓存。
  11. 清空所有缓存:WordPress缓存插件、CDN缓存、浏览器缓存。
  12. 旧域名配置301跳转到新域名。
  13. 在百度站长平台、谷歌Search Console提交新域名和站点地图,必要时做改版工具里的“站点换地址”操作。

我在实际操作中还总结了几条额外经验:

  • 数据库替换前,先把全站首页的HTML源码保存一份。替换后对比源码里的URL,哪里没改,一目了然。
  • 如果wp search-replace替换后出现了页面风格全丢的问题,先别慌,去后台点一下“保存固定链接”,再把主题缓存插件清掉,八成能恢复。这是最容易忽略的一步。
  • 多站点网络(Multisite)换域名,除了siteurlhome,还要修改wp_blogs表里的domain字段、wp_site表里的domain字段,同时更新wp-config.php里的DOMAIN_CURRENT_SITE。每张子站的表里也可能存着旧的子站路径。这块比单站点麻烦很多,建议单独规划迁移窗口。

换域名这事,看着是个小操作,实际牵涉数据库、重写规则、缓存、CDN、SSL好几个层面。只要把数据库里的绝对地址处理干净,服务器伪静态规则没问题,再让固定链接重新生成一次,大部分问题都能迎刃而解。希望这份清单能帮你少折腾几个小时。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询