9块9自建邮局:从WordPress搬家到邮箱发信,我用了8小时踩遍所有坑

skl 发布于 2026-03-01 53 次阅读


9块9自建邮局:从WordPress搬家到邮箱发信,我用了8小时踩遍所有坑

2026年2月28日,一个普通的周六,我从下午3点折腾到晚上11点,经历了从WordPress搬家到自建邮局的九九八十一难。当看到QQ邮箱弹出那封测试邮件时——虽然它躺在垃圾箱里——我差点哭出来。


? 缘起:美国小鸡要到期了

先交代一下背景。

我有一台美国云服务器,9.9元/月,1核1G内存,3Mbps带宽,送20G防御。上面跑着一个WordPress博客,常年内存占用80%+,用户一多直接飙到95%。更坑的是,这台机器3月8号就要到期了,而同款的日本服务器(也是9.9元)早就卖断货,根本抢不到。

本来想换日本服务器,结果发现日本机房封25端口——邮箱梦碎。于是我只好另寻出路。


? 最终方案:分而治之

经过一番折腾(和DeepSeek助手的无数轮对话),我决定采用三权分立架构:

· 免费虚拟主机:跑WordPress(白嫖一年,配置:500MB空间、100连接、50G流量、PHP+MySQL 5.6)
· 美国服务器:跑邮箱系统(只发信,不收信,利用出站25端口开放的优势)
· Cloudflare CDN:套在前面防DDoS(免费版)
· Orange Pi Zero3:内网穿透,做备份和监控(已有)

一个月总成本:9.9元,比一杯奶茶还便宜。


? WordPress搬家:第一个坑

下午3:00 - 4:00 备份与恢复

从美国服务器备份:

· 数据库:用phpMyAdmin导出SQL文件
· WordPress文件:压缩 /var/www/html 整个目录

上传到虚拟主机:

· 解压WordPress文件到网站根目录
· 创建新数据库,导入SQL文件
· 修改 wp-config.php 里的数据库连接信息(数据库名、用户名、密码)

访问网站,首页正常显示!我以为这就搞定了,美滋滋地去倒了杯水。

下午4:30 翻车现场

回来想发篇新文章,结果点击“发布”按钮后,页面一直转圈,最后弹出一个错误:

发布失败。此响应不是合法的json响应。

我人傻了。网站能正常访问,后台能进,能写文章,就是发不出去。这是什么鬼?

打开浏览器开发者工具(F12),看到满屏的红色报错:

POST https://skl.cc/wp-json/wp/v2/posts/210 404 (Not Found)
GET https://skl.cc/wp-json/wp/v2/taxonomies/post_tag 404 (Not Found)
...

所有的 /wp-json/ 请求全部返回404。

下午5:00 - 7:00 疯狂排查

第一阶段:怀疑权限问题
WordPress需要写 wp-content/uploads/ 目录。检查文件夹权限,755,没问题。手动创建了2025/02文件夹,还是不行。

第二阶段:怀疑PHP配置
检查PHP上传限制,upload_max_filesize 是64M,够用。post_max_size 也正常。

第三阶段:怀疑插件冲突
把所有插件都禁用了,切换到默认主题,问题依旧。

第四阶段:发现真相
这时候我发现一个关键细节:网站根目录下没有 .htaccess 文件。


? 科普时间:伪静态和 .htaccess 是什么?

什么是伪静态?

伪静态,全称是“伪静态网页技术”,指的是把动态网页(比如 article.php?id=123)伪装成静态网页(比如 article/123.html)的样子。

为什么要这么做?

  1. SEO友好:搜索引擎更喜欢静态链接
  2. 用户体验:链接更简洁美观
  3. WordPress依赖:WordPress从3.0开始全面采用REST API架构,后台的很多操作(包括发布文章)都需要通过 /wp-json/ 这个API接口完成。而这些API接口的访问,依赖伪静态规则!

Apache和.htaccess的关系

Apache 是世界上使用最广泛的Web服务器软件之一。它实现伪静态主要靠两个东西:

  1. mod_rewrite模块:Apache的“重写引擎”,负责把动态URL转换成静态形式。
  2. .htaccess文件:放在网站根目录的配置文件,告诉Apache:“嘿,访问这个网站的时候,要按我写的规则来!”

.htaccess 和 WordPress 的关系:

· WordPress安装后,默认不会生成 .htaccess
· 当你在后台 设置 → 固定链接 选择任意一种漂亮链接格式时,WordPress会尝试自动写入 .htaccess 文件
· 这个文件里写的就是让Apache正确解析WordPress链接的规则

没有 .htaccess 会怎样?

· 前台链接可能打不开(取决于服务器配置)
· 后台的REST API全部404——这就是我遇到的问题!

为什么1panel部署的WordPress有.htaccess,手动安装的没有?

1panel这种面板工具,在一键部署完成后,会自动帮你做两件事:

  1. 设置好文件权限
  2. 模拟登录后台,去“固定链接”页面保存一次设置

这就触发了WordPress自动生成 .htaccess 的动作。所以用面板部署的人,从来没意识到还有这个文件存在。

而手动安装WordPress,需要你自己去后台保存一次固定链接,或者手动创建 .htaccess 文件。


? 真相大白:虚拟主机面板上有现成的!

在我折腾了两小时,查了无数资料,准备手动创建 .htaccess 文件的时候,突然发现虚拟主机控制面板里有一个选项:

“伪静态设置” → 选择程序:WordPress → 开启”

我点了一下,保存,再去WordPress后台保存固定链接,然后试了试发布文章——

成功了!所有的404消失了,文章顺利发布!

那一刻我差点哭出来。原来这破虚拟主机用的Web服务器是kangle(冷门但兼容Apache规则),面板里直接集成了常见程序的伪静态配置。我要是早点发现,能省两小时!


? 邮箱搭建:第二个更大的坑

晚上7:30 开始搭建Mailserver

WordPress搞定了,接下来是邮箱。我的需求很简单:只需要发信(收验证码、定时发邮件),不需要收信。美国服务器的优势是:出站25端口开放(云厂商通常关入站25,但出站一般不管)。

在1panel应用商店里找到了 docker-mailserver(简称DMS),开始安装。

安装配置:

· 域名填:skl.moe(我想用主域名做邮箱,显得专业)
· SSL证书:Let's Encrypt 手动模式,指定证书路径
· 环境变量:按官方文档配了一堆

晚上8:00 第一个报错:TLS不可用

安装完后,用 swaks 测试发信:

swaks --to qingtong33@qq.com --from skl@skl.moe --server 172.18.0.2:587 --auth LOGIN --auth-user skl@skl.moe --auth-password "xxx" --tls

返回:

454 4.7.0 TLS not available due to local problem

看日志:

warning: error loading private keys and certificates from: /etc/dms/tls/key /etc/dms/tls/cert ... disabling TLS support

明明在环境变量里指定了证书路径,为什么还在用默认的fallback证书?

晚上8:30 排查:证书没加载

检查容器内证书:

docker exec -it 1Panel-mailserver-FWZC ls -l /etc/letsencrypt/live/skl.moe/fullchain.pem

文件存在!说明挂载没问题。

检查Postfix配置:

docker exec 1Panel-mailserver-FWZC postconf -n | grep smtpd_tls_chain_files

输出却是 /etc/dms/tls/…,不是Let's Encrypt路径。

真相:环境变量虽然设了,但Postfix没读到,或者被默认配置覆盖了。

晚上9:00 解决方案:自定义配置文件

在容器内创建 /tmp/docker-mailserver/postfix-main.cf,强制指定证书路径:

smtpd_tls_chain_files = /etc/letsencrypt/live/skl.moe/privkey.pem /etc/letsencrypt/live/skl.moe/fullchain.pem

重启容器。再次检查,证书路径对了!

晚上9:30 新报错:认证socket找不到

再测587端口:

warning: SASL: Connect to Dovecot auth socket 'private/auth' failed: No such file or directory
fatal: no SASL authentication mechanisms

TLS有了,但认证机制没了。Postfix需要和Dovecot通信进行SASL认证,但socket不存在。

晚上10:00 分析:Dovecot的socket配置

查看Dovecot配置:

doveconf -a | grep -A15 "service auth"

输出显示,Dovecot只在 /dev/shm/sasl-auth.sock 创建了监听器。而Postfix期望的路径是 /var/spool/postfix/private/auth(因为Postfix运行在chroot环境,根目录是 /var/spool/postfix)。

问题:Dovecot没在Postfix能访问的位置创建socket。

晚上10:30 终极修复:让Dovecot在正确位置创建socket

创建自定义Dovecot配置文件 /tmp/docker-mailserver/dovecot.cf:

service auth {
  unix_listener /dev/shm/sasl-auth.sock {
    group = postfix
    mode = 0666
  }
  unix_listener /var/spool/postfix/private/auth {
    mode = 0666
    user = postfix
    group = postfix
  }
}

同时简化Postfix自定义配置,只保留证书顺序行:

smtpd_tls_chain_files = /etc/letsencrypt/live/skl.moe/privkey.pem /etc/letsencrypt/live/skl.moe/fullchain.pem

重启容器。

检查socket:

ls -l /var/spool/postfix/private/auth

出现了!srw-rw-rw- 1 postfix postfix,完美!

晚上11:00 最终测试

swaks --to qingtong33@qq.com \
      --from skl@skl.moe \
      --server 172.18.0.2:587 \
      --auth LOGIN \
      --auth-user skl@skl.moe \
      --auth-password "skl6519940!" \
      --tls \
      --header "Subject: 终于通了" \
      --body "见证奇迹的时刻"

几秒后,手机QQ邮箱弹出通知——虽然显示“发件人无法验证,可能存在假冒”,但邮件真的收到了!(虽然进了垃圾箱)


? 最终成果

WordPress搬家:

· 耗时:2小时(主要是排查伪静态问题)
· 关键教训:虚拟主机面板上一般都有“伪静态设置”,点一下就能解决90%的问题

邮箱系统搭建:

· 耗时:3.5小时
· 关键配置:

  1. 证书必须挂载且权限正确(644)
  2. Postfix的 smtpd_tls_chain_files 顺序是私钥在前,证书在后
  3. Dovecot要在 /var/spool/postfix/private/auth 创建socket
  4. 用自定义配置文件覆盖默认行为

成本:

· 虚拟主机:0元/年(白嫖)
· 美国服务器:9.9元/月
· CDN:0元(Cloudflare免费版)
· Orange Pi:已有
· 总计:9.9元/月


? 一些教训

  1. 永远先看面板:很多问题其实面板里有一键配置,比如伪静态、SSL证书等。我要是早点发现虚拟主机的“伪静态设置”,能省两小时。
  2. 日志是最好的老师:每次报错都看日志,Postfix和Dovecot的日志会告诉你一切。这次如果没有 docker logs,我根本找不到问题根源。
  3. 了解你的服务器环境:不同的Web服务器(Apache、Nginx、Kangle)处理伪静态的方式不同。我这次用的Kangle虽然兼容Apache规则,但需要通过面板开启支持。
  4. 证书顺序很重要:Postfix的 smtpd_tls_chain_files 参数,私钥必须在第一位。这是我卡最久的地方。
  5. 认证socket是桥梁:Postfix和Dovecot通过socket通信,必须让它们在同一个频道上。检查 smtpd_sasl_path 和 Dovecot的 unix_listener 是否匹配。
  6. 垃圾箱是第一站:自建邮局发的邮件,第一次进垃圾箱很正常。配好SPF、DKIM、DMARC,慢慢养IP信誉,就会进收件箱。

? 最后的话

写这篇博客,一是记录自己踩过的坑,二是希望帮助遇到同样问题的人。如果你正在从零开始搭建WordPress和自建邮局,希望这篇文章能让你少走弯路。

特别感谢DeepSeek助手——虽然最后一段我已经迷糊了,基本就是“照抄代码”状态,但前面大部分问题都是在他的帮助下解决的。没有他,我可能还在纠结为什么REST API返回404。

现在,我可以自豪地说:我是一个9块9自建邮局的男人了! 虽然邮件进了垃圾箱,但毕竟是我的垃圾箱。


—— 写于2026年2月28日23:30,一个刚解决完bug、激动得睡不着觉的程序员


? 附:完整技术配置清单

WordPress伪静态(kangle服务器)

在虚拟主机控制面板找到“伪静态设置” → 选择WordPress → 开启

docker-mailserver 关键环境变量

SSL_TYPE=manual
SSL_CERT_PATH=/etc/letsencrypt/live/skl.moe/fullchain.pem
SSL_KEY_PATH=/etc/letsencrypt/live/skl.moe/privkey.pem
PERMIT_DOCKER=none
ENABLE_OPENDKIM=1
ENABLE_OPENDMARC=1
ENABLE_POLICYD_SPF=1

Postfix自定义配置(/tmp/docker-mailserver/postfix-main.cf)

smtpd_tls_chain_files = /etc/letsencrypt/live/skl.moe/privkey.pem /etc/letsencrypt/live/skl.moe/fullchain.pem
mydestination = localhost

Dovecot自定义配置(/tmp/docker-mailserver/dovecot.cf)

service auth {
  unix_listener /dev/shm/sasl-auth.sock {
    group = postfix
    mode = 0666
  }
  unix_listener /var/spool/postfix/private/auth {
    mode = 0666
    user = postfix
    group = postfix
  }
}

测试发信命令

swaks --to 你的邮箱@qq.com \
      --from skl@skl.moe \
      --server 你的容器IP:587 \
      --auth LOGIN \
      --auth-user skl@skl.moe \
      --auth-password "你的密码" \
      --tls \
      --header "Subject: 测试" \
      --body "内容"

愿你的邮件永不进垃圾箱,愿你的服务器永不宕机。 ?