一个 WordPress 新站从"装好能用"到"搜索引擎愿意收录",中间隔着一堆没人告诉你、但漏一件就出事的事。
这篇是我自己踩过一遍之后整理的上线清单。全部在宝塔面板 + nginx + PHP 8.2 + MySQL 5.6 的国内云主机上实测过,每条都写了为什么做和不做会怎样。最后一部分是备份和回滚——这部分我建议你哪怕别的都跳过,也要看完。

顺序错了,做了也白做
清单条目本身不稀奇,网上到处都是。真正的问题是顺序:
① 备份(动手之前)
② 伪静态 / 固定链接(所有 URL 的地基)
③ 站点地图 + robots
④ 速度优化(资源、缓存、图片)
⑤ 安全加固(权限、入口、备份脚本)
⑥ 结构优化(面包屑、低质页处理)
⑦ 内容策略(这才是决定收录的)
为什么备份排第一?因为第②步一旦做错,全站 404。没备份你就只能重装。
一、动手之前:把"能退回去"这件事做掉
这一步九成新手跳过。跳过的人里,有一部分会在两小时后重新建站。
要备份三样东西:
| 对象 | 说明 | 常见遗漏 |
|---|---|---|
| 数据库 | 文章、页面、设置、用户全在这 | 只导出 .sql 不验证内容 |
wp-content |
主题、插件、上传的图片 | 忘了 uploads 目录(图片全丢) |
| 配置文件 | wp-config.php、.htaccess、nginx 规则 |
改完没留原文件副本 |
命令行的做法(SSH 环境下最稳):
# 数据库(MySQL 5.6 会报 PROCESS privilege 警告,属正常,不影响数据完整性)
mysqldump -u 用户名 -p --default-character-set=utf8mb4 \
--add-drop-table --single-transaction 数据库名 > db.sql
# 站点文件(wp-content 体积最大,通常几 MB 到几百 MB)
tar -czf files.tar.gz -C /www/wwwroot/你的站点目录 \
wp-content wp-config.php .htaccess
本地下载一份,别只留在服务器上。 服务器磁盘挂了、误删了、被入侵了,留在同一个盘上的备份没有意义。
verification 也很简单:
grep -c "CREATE TABLE" db.sql # 应等于 information_schema 里的表数量
tar -tzf files.tar.gz | head -20 # 能看到 wp-content/ 开头就对了

一个反直觉的点:mysqldump 在 MySQL 5.6 上几乎必定输出
Warning: Using a password on the command line interface can be insecure和PROCESS privilege ... tablespaces这两条警告。
它们不是错误,导出文件是完整的。别被吓到去反复重来。
二、nginx 伪静态:不补这一条,全站 404
国内主机大多用宝塔面板。宝塔建站时会生成一个"伪静态"配置文件,但新站的这个文件经常是空的。
后果很直接:WordPress 的"固定链接"只能选带 index.php 的那种,也就是:
https://example.com/index.php/2026/09/28/post-name/
这种 URL 对搜索引擎不友好(层级混乱、index.php 是噪音),而且一旦你手动改成漂亮的静态链接,全站立刻 404——因为 nginx 不知道该把 /post-name/ 交给谁处理。
修法是往伪静态文件里加这一句:
location / {
try_files $uri $uri/ /index.php?$args;
}
宝塔的伪静态文件路径一般是:
/www/server/panel/vhost/rewrite/你的域名.conf
(注意:文件名就是完整域名,带点。)
第二步的坑:改完固定链接还是要 404
即使 try_files 加上了,如果你是通过直接改数据库里的 permalink_structure 来设置固定链接,新链接同样会 404。
原因:WordPress 把 URL 重写规则缓存在数据库的 wp_options → rewrite_rules 里。你改了 permalink_structure,但缓存的 rewrite_rules 还是旧的。
必须刷新重写规则:
# 有 wp-cli 的话
wp rewrite flush --hard
# 没有的话,写一个临时 php 文件访问一次,然后删掉
别忘了删掉那个临时文件。 留一个能刷新重写规则的 php 在网站根目录,是安全隐患。
推荐直接用的固定链接格式:
/%postname%.html
理由:中文站点用 .html 后缀在国内搜索引擎里识别度高、看起来像静态页,且不暴露日期(发布日期一改就换 URL 的事故可以避免)。
三、站点地图与 robots.txt
百度、搜狗、必应都靠 sitemap 发现新内容。WordPress 自带一个 /wp-sitemap.xml,但它把附件页、作者页、标签页全都塞进去了——这些恰恰是低质页面。所以要么改装插件(Yoast / Rank Math),要么自己生成一份干净的。
自己生成的好处:零插件、加载快、可控。
思路是写一个读取数据库的 PHP,只输出三类 URL:
首页(priority 1.0)
文章与页面(0.9 / 0.8)
有内容的分类(0.6)
并且加一层文件缓存,1 小时才重新查库一次,避免每次请求都跑 SQL:
$xml_file = __DIR__ . '/sitemap.xml';
if (is_readable($xml_file) && (time() - filemtime($xml_file)) < 3600) {
header('Content-Type: application/xml; charset=UTF-8');
readfile($xml_file);
exit;
}
然后用 nginx 把 /sitemap.xml 指过去:
location = /sitemap.xml {
try_files $uri /sitemap.php?$args;
}
robots.txt 要单独对百度说明一遍。 很多站长只写一个 User-agent: *,但百度的爬虫对独立段落响应更好:
User-agent: *
Allow: /
Disallow: /wp-admin/
Allow: /wp-admin/admin-ajax.php
Disallow: /wp-includes/
Disallow: /*?s=
Disallow: /search
Disallow: /attachment/
User-agent: Baiduspider
Allow: /
Disallow: /wp-admin/
Disallow: /*?s=
Sitemap: https://你的域名/sitemap.xml
注意最后一行——sitemap 地址写进 robots.txt,百度会主动来抓。
四、速度优化:国内主机最容易忽略的三件事
1. 把 Google Fonts 干掉
很多免费主题(包括 GeneratePress 的某些配置)会在 <head> 里加载 Google Fonts。国内访问 fonts.googleapis.com 直接超时,浏览器要等它超时才继续渲染——首屏白屏 3 秒起步。
在 functions.php 或自己写的小插件里屏蔽:
add_action('wp_enqueue_scripts', function () {
global $wp_styles;
if (empty($wp_styles->registered)) return;
foreach ($wp_styles->registered as $handle => $obj) {
$src = isset($obj->src) ? $obj->src : '';
if (strpos($src, 'fonts.googleapis.com') !== false
|| strpos($src, 'fonts.gstatic.com') !== false) {
wp_dequeue_style($handle);
unset($wp_styles->registered[$handle]);
}
}
}, 100);
替代方案是用系统字体栈(-apple-system, "PingFang SC", "Microsoft YaHei"),中文站点本来也不需要衬线英文字体。
2. 关掉 emoji、oEmbed、静态资源版本号
WordPress 默认会为 emoji 加载一段 JS 和一个外部图片请求,为 oEmbed 输出一堆 <link>,给每个 css/js 加 ?ver=x.y.z。
- emoji:中文博客基本用不到,纯浪费
- oEmbed:不做视频嵌入就完全没用
?ver=:让代理层/CDN 无法缓存,每次都回源
前两个用 remove_action 摘掉,第三个用一个 filter 过滤掉 ver 参数,大概能省下 3-5 个请求。
3. 图片:上传前先压
这条最容易被忽略,也最影响体验。一张手机拍的截图 2-3MB,一篇文章放 3 张就是 8MB。自己刚做完速度优化,转头往文章里塞大图,属于自己打自己脸。
标准做法:宽度压到 1200px、格式转 WebP、单图控制在 150KB 以内。
WebP 相比 PNG 在这种"扁平色块 + 线条"的示意图上压缩率极高。实测三张 1200px 的流程图:
| 原图 | WebP 后 | 压缩率 |
|---|---|---|
| 826 KB | 31 KB | 96% |
| 1457 KB | 32 KB | 98% |
| 1527 KB | 26 KB | 98% |
(用 Python 的 Pillow 批量处理,十几行代码,比装一个图片压缩插件更干净。)
from PIL import Image
im = Image.open(src).convert("RGB")
if im.width > 1200:
im = im.resize((1200, int(im.height * 1200 / im.width)), Image.LANCZOS)
im.save(dst, "WEBP", quality=82, method=6)
五、安全加固:权限、入口、自动备份
权限归位
find /www/wwwroot/你的站点 -type d -exec chmod 755 {} \;
find /www/wwwroot/你的站点 -type f -exec chmod 644 {} \;
chmod 600 /www/wwwroot/你的站点/wp-config.php
wp-config.php 里是数据库明文密码,权限必须是 600(只有属主可读写)。默认 644 意味着服务器上任何用户都能读。
wp-config.php 里加这四行
define('DISALLOW_FILE_EDIT', true); // 禁止后台在线编辑主题/插件源码(被入侵后最常被利用)
define('WP_POST_REVISIONS', 5); // 限制修订版本,否则数据库半年就膨胀到几百 MB
define('AUTOSAVE_INTERVAL', 120); // 自动保存改 120 秒,减少写入
define('EMPTY_TRASH_DAYS', 7); // 回收站 7 天清理
DISALLOW_FILE_EDIT 特别重要:留着一个能在后台改 PHP 的入口,等于给入侵者留了后门。
nginx 层拦三样东西
# 上传目录禁止执行 PHP(否则传个伪装成图片的马上去就能跑)
location ~* /(?:uploads|files)/.*\.php$ {
deny all;
}
# 关掉 xmlrpc.php(暴力破解和 pingback 放大攻击的主要入口)
location = /xmlrpc.php {
deny all;
}
# 禁止访问隐藏文件
# ⚠️ 必须排除 .well-known,否则 Let's Encrypt 证书续签会失败
location ~ /\.(?!well-known) {
deny all;
}
最后那条的 (?!well-known) 是我自己踩过的坑,下面单独说。
坑:location ~ /\. 会让 SSL 证书续签失败
我一开始写的是:
location ~ /\. {
deny all;
}
想法很朴素:.git、.env、.htaccess 这些敏感文件不该被访问。
问题在于 nginx 的 location 匹配规则:正则 location 按书写顺序匹配,先命中先执行。我的规则写在宝塔自动生成的这段之前:
location ~ \.well-known {
allow all;
}
结果 /well-known/acme-challenge/xxxx 先被我的规则命中,返回 403。Let's Encrypt 验证服务器拿不到那个 token 文件,证书到期后续签直接失败,网站变成不受信任。
这个坑的可怕之处在于:它不会立刻报错。你做优化的时候一切正常,三个月后证书到期才发现,那时候你早就忘了自己改过什么。
修法就是加一个负向先行断言,把 .well-known 排除掉:
location ~ /\.(?!well-known) {
deny all;
}
改完记得验证一下:
# 应该返回放行后的结果(404 也算正常,说明没被拦)
curl -sI https://你的域名/.well-known/acme-challenge/test | head -1
# .git 之类仍然应该被拦
curl -sI https://你的域名/.git/config | head -1 # 期望 403
改 nginx 前一定要备份原配置,并且 nginx -t 通过才 reload。 一个可靠的流程:

写成一个 shell 脚本,出错自动回滚。手工改配置然后 reload 失败,重灾区就是"以为改好了,其实 nginx 已经起不来"。
下面是这个脚本的核心逻辑,关键是校验不通过就立刻还原,而不是硬 reload:
#!/bin/bash
set -u
CONF="/www/server/panel/vhost/rewrite/你的域名.conf"
BAK="${CONF}.bak-$(date +%Y%m%d%H%M%S)"
# 1. 备份(原文件为空时也要处理)
if [ -s "$CONF" ]; then
cp -a "$CONF" "$BAK"
echo "原规则已备份 → $BAK"
else
echo "原规则为空,无需备份"
fi
# 2. 写入新规则
cat > "$CONF" <<'WPRULES'
location / {
try_files $uri $uri/ /index.php?$args;
}
location = /sitemap.xml {
try_files $uri /sitemap.php?$args;
}
location ~* /(?:uploads|files)/.*\.php$ { deny all; }
location = /xmlrpc.php { deny all; }
# 注意 (?!well-known),见上文
location ~ /\.(?!well-known) { deny all; }
WPRULES
# 3. 语法校验:不通过直接回滚并退出
if nginx -t >/tmp/nginx_test 2>&1; then
echo "nginx -t 通过"
else
echo "nginx -t 失败,回滚"
cat /tmp/nginx_test
if [ -f "$BAK" ]; then cp -a "$BAK" "$CONF"; else : > "$CONF"; fi
exit 1
fi
# 4. 平滑重载
nginx -s reload
这个脚本的每一行都是被坑出来的:第 1 步的 -s 判断(避免对空文件 cp 报错)、第 3 步的失败回滚、以及 .well-known 的排除。
六、结构化数据与站点结构
面包屑 + BreadcrumbList
面包屑不只是给用户看导航,更重要的是给搜索引擎站点层级信息。配合 JSON-LD 输出 BreadcrumbList,百度能知道"这篇文章属于哪个分类、分类属于哪个站",对提升收录质量有实际帮助。
// 输出结构化数据(简化示意)
$json = [
'@context' => 'https://schema.org',
'@type' => 'BreadcrumbList',
'itemListElement' => [
['@type' => 'ListItem', 'position' => 1, 'name' => '首页', 'item' => home_url('/')],
['@type' => 'ListItem', 'position' => 2, 'name' => $cat_name, 'item' => $cat_url],
['@type' => 'ListItem', 'position' => 3, 'name' => get_the_title()],
],
];
文章页还要输出 Article 类型的 JSON-LD(标题、发布时间、修改时间、作者、封面图)。这两块加起来不到 50 行 PHP,比装一个 SEO 插件轻得多。
处理"低质页面"
这一节是针对一个具体问题写的:用 AI 批量产内容的站点特别容易被判垃圾站。
搜索引擎判断低质站的信号里,有几个和内容质量无关,纯粹是结构性问题:
| 信号 | 为什么算低质 | 处理方式 |
|---|---|---|
| 图片附件页 | 只有一张图 + 一行字,典型空壳页 | is_attachment() → 301 跳回所属文章 |
| 标签页 | 内容与分类页/首页高度重复 | noindex, follow |
| 空分类页 | 0 篇文章,纯入口页 | noindex, follow |
| 作者页 | 单作者博客的作者页 ≈ 首页 | noindex, follow |
| 分页第 2 页起 | <title> 与第 1 页完全相同 |
标题补「(第 2 页)」 |
| 归档页输出全文 | 与文章页内容 100% 重复 | 主题设置里改成只输出摘要 |
noindex, follow 是关键:不索引这个页面,但蜘蛛仍然可以顺着页面上的链接抓到文章。如果直接 nofollow 或者屏蔽抓取,反而会切断内链。
对应的几段代码:
// 1. 附件页 301 归集到所属文章
add_action('template_redirect', function () {
if (!is_attachment()) return;
$post = get_queried_object();
$url = home_url('/');
if ($post && $post->post_parent) {
$url = get_permalink($post->post_parent) ?: $url;
}
wp_safe_redirect($url, 301);
exit;
}, 1);
// 2. 低质聚合页 noindex
add_action('wp_head', function () {
$noindex = false;
if (is_tag() || is_author()) {
$noindex = true;
} elseif (is_category()) {
$cat = get_queried_object();
if ($cat && (int) $cat->count === 0) $noindex = true;
}
if ($noindex) echo '<meta name="robots" content="noindex,follow" />' . "\n";
}, 5);
// 3. 分页标题去重
add_filter('document_title_parts', function ($title) {
if (is_paged()) {
$paged = (int) get_query_var('paged');
if ($paged > 1 && isset($title['title'])) {
$title['title'] .= sprintf('(第 %d 页)', $paged);
}
}
return $title;
});
还有一条在主题设置里,不在代码里:归档页只输出摘要,不要输出全文。
用 GeneratePress 的话,后台「外观 → 自定义 → 布局」把归档页的内容改成摘要(Excerpt)。这个选项决定了首页、分类页是输出全文还是摘要——输出全文的情况下,你的首页和每篇文章页内容完全重复,这是搜索引擎判定重复内容最直接的依据。
RSS 同理:设置 → 阅读 → 摘要(而不是全文)。否则整站内容会被采集站一次性抓走。
七、备份与回滚:真正保命的部分
前面六节都是在"做对"。这一节是在"做错之后还能活"。
回滚能力决定你敢不敢动手
很多优化不敢做,原因就一个:怕搞坏。
- 不敢改 nginx,怕站点起不来
- 不敢改固定链接,怕全站 404
- 不敢动主题配置,怕页面乱掉
一旦你知道"随时能退回去",上面这些动作全变成低成本操作。清单里那些条目为什么敢一条条试?因为背后有回滚通道兜着。
所以最该先建立的不是"优化清单",是回滚通道。
三档回滚
| 档位 | 覆盖场景 | 恢复耗时 |
|---|---|---|
| 单文件回滚 | 改坏了某个配置文件 | 秒级(直接 cp 回来) |
| 全站回滚 | 数据库或文件被搞坏 | 分钟级(导入 sql + 解压) |
| 异地恢复 | 服务器磁盘故障 / 被入侵 | 小时级(换机器重建) |
第一档最常用,做法很简单:每次改配置前先 cp 原文件 原文件.bak-时间戳。
STAMP=$(date +%Y%m%d%H%M%S)
cp /www/server/panel/vhost/rewrite/你的域名.conf \
/www/server/panel/vhost/rewrite/你的域名.conf.bak-$STAMP
出问题时:
cp /www/server/panel/vhost/rewrite/你的域名.conf.bak-20260928173012 \
/www/server/panel/vhost/rewrite/你的域名.conf
nginx -t && nginx -s reload
注意时间戳——留一堆 .bak 而不知道哪个是哪次改的,等于没备份。
全站回滚的实际步骤
# 1. 先停掉写入,避免"边导入边有人访问"造成数据不一致
# (宝塔面板可一键停 PHP;或临时把站点目录改名也行,宁可 502 也别写脏数据)
mv /www/wwwroot/你的站点 /www/wwwroot/你的站点.broken
# 2. 解压文件 + 归属权修正(这一步最容易漏)
tar -xzf files.tar.gz -C /www/wwwroot/你的站点
chown -R www:www /www/wwwroot/你的站点
# 3. 导入数据库
mysql -u 用户名 -p --default-character-set=utf8mb4 数据库名 < db.sql
# 4. 恢复 nginx 规则并校验
nginx -t && nginx -s reload
第 2 步的 chown 是重灾区。 用 root 解压出来的文件属主是 root,PHP-FPM 以 www 用户运行,读不到文件 → 全站 500。这个问题现象是"文件明明都在,但网站就是打不开",很多人在这里卡很久。
把备份自动化,并且验证它真的在跑
手工备份一定会忘。配一个 cron:
#!/bin/bash
# /usr/local/bin/wp_site_backup.sh
set -e
STAMP=$(date +%F)
DIR=/root/wp_backups
mkdir -p $DIR
mysqldump -u 用户名 -p密码 --default-character-set=utf8mb4 \
--single-transaction 数据库名 > $DIR/db-$STAMP.sql
tar -czf $DIR/files-$STAMP.tar.gz -C /www/wwwroot/你的站点 \
wp-content wp-config.php 2>/dev/null || true
gzip -f $DIR/db-$STAMP.sql
find $DIR -type f -mtime +7 -delete # 只留 7 天
echo "$(date) backup done" >> /var/log/wp_backup.log
0 3 * * * /usr/local/bin/wp_site_backup.sh
然后一定要验证:
tail /var/log/wp_backup.log # 看有没有今天的记录
ls -lh /root/wp_backups/ # 看文件大小是否合理(几 KB 说明导出失败)
没验证过的备份等于没有备份。定时任务是"配置了"和"在跑"两件事,
而"在跑"和"备份内容可用"又是两件事。三层都要确认。
最后一句:异地
服务器磁盘故障、被入侵删库、误操作 rm -rf——这三种情况下,存在同一台服务器上的备份会一起没。
每周手工下载一次到本地,或者用对象存储(腾讯云 COS / 阿里云 OSS)配一个同步任务。成本几毛钱,换的是"最坏情况下内容资产还在"。
附:完整清单(可直接当 checklist 用)
动手前
- ☐ 数据库导出,验证
CREATE TABLE数量正确 - ☐
wp-content打包(含 uploads) - ☐
wp-config.php/.htaccess/ nginx 规则单独留副本 - ☐ 下载一份到本地或对象存储
URL 与收录
- ☐ 伪静态文件补
try_files $uri $uri/ /index.php?$args - ☐ 固定链接设为
/%postname%.html - ☐ 刷新重写规则(
wp rewrite flush --hard),删掉临时 php - ☐ sitemap 部署并验证输出
<urlset - ☐ robots.txt 写入,含 Sitemap 地址
- ☐ 百度站长平台提交 sitemap + API 推送
速度
- ☐ 屏蔽 Google Fonts
- ☐ 关 emoji / oEmbed /
?ver= - ☐ gzip 开启(宝塔一般已默认开)
- ☐ 静态资源缓存 30 天
- ☐ 图片压到 1200px + WebP + 150KB 内
- ☐ 归档页输出摘要,RSS 输出摘要
安全
- ☐ 目录 755 / 文件 644 /
wp-config.php600 - ☐
DISALLOW_FILE_EDIT等四个常量 - ☐ uploads 禁执行 PHP
- ☐ xmlrpc.php 拦截
- ☐ 隐藏文件拦截 (记得排除 .well-known)
- ☐ 每日备份 cron + 验证日志
- ☐ 后台地址改名、强密码、登录失败限制
结构
- ☐ 面包屑 HTML + BreadcrumbList
- ☐ Article JSON-LD
- ☐ 附件页 301 归集
- ☐ 标签页 / 空分类页 / 作者页 noindex,follow
- ☐ 分页 title 去重
内容(决定收录,比上面所有项都重要)
- ☐ 先积累 8-15 篇原创,再提交收录
- ☐ 每天 1-2 篇稳定节奏,不要一天发 20 篇然后停一周
- ☐ 分类 3-5 个,标签能不用就不用
- ☐ 每篇有真实经验、具体命令、可验证的数据
真正会出事的只有四条
上面这张清单,条目看着多,真出事的就四个:没备份就改配置、nginx 规则挡住 .well-known、uploads 能执行 PHP、归档页输出全文。其余的属于加分项,做了更好,不做也不至于翻车。
还有一条不在清单里,但它决定了上面所有条目的价值:内容得有人味。
第六条那些结构优化,解决的是"结构性低质信号"。可如果内容本身是批量生成的、没有实测数据、没有具体命令、没有任何个人经验,结构改得再干净也只是"包装整齐的批量内容"。搜索引擎识别这个的能力,这两年提升得很快。
我的判断标准是:一篇能被搜索引擎当回事的文章,至少得有一样东西是别人抄不走的——你自己的错误、你自己的数据、你自己的环境细节。这篇里那些"踩过的坑",就是这一类东西。
本站为个人技术记录,内容均为原创实操总结,转载请注明出处。