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)的样子。
为什么要这么做?
- SEO友好:搜索引擎更喜欢静态链接
- 用户体验:链接更简洁美观
- WordPress依赖:WordPress从3.0开始全面采用REST API架构,后台的很多操作(包括发布文章)都需要通过 /wp-json/ 这个API接口完成。而这些API接口的访问,依赖伪静态规则!
Apache和.htaccess的关系
Apache 是世界上使用最广泛的Web服务器软件之一。它实现伪静态主要靠两个东西:
- mod_rewrite模块:Apache的“重写引擎”,负责把动态URL转换成静态形式。
- .htaccess文件:放在网站根目录的配置文件,告诉Apache:“嘿,访问这个网站的时候,要按我写的规则来!”
.htaccess 和 WordPress 的关系:
· WordPress安装后,默认不会生成 .htaccess
· 当你在后台 设置 → 固定链接 选择任意一种漂亮链接格式时,WordPress会尝试自动写入 .htaccess 文件
· 这个文件里写的就是让Apache正确解析WordPress链接的规则
没有 .htaccess 会怎样?
· 前台链接可能打不开(取决于服务器配置)
· 后台的REST API全部404——这就是我遇到的问题!
为什么1panel部署的WordPress有.htaccess,手动安装的没有?
1panel这种面板工具,在一键部署完成后,会自动帮你做两件事:
- 设置好文件权限
- 模拟登录后台,去“固定链接”页面保存一次设置
这就触发了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小时
· 关键配置:
- 证书必须挂载且权限正确(644)
- Postfix的 smtpd_tls_chain_files 顺序是私钥在前,证书在后
- Dovecot要在 /var/spool/postfix/private/auth 创建socket
- 用自定义配置文件覆盖默认行为
成本:
· 虚拟主机:0元/年(白嫖)
· 美国服务器:9.9元/月
· CDN:0元(Cloudflare免费版)
· Orange Pi:已有
· 总计:9.9元/月
? 一些教训
- 永远先看面板:很多问题其实面板里有一键配置,比如伪静态、SSL证书等。我要是早点发现虚拟主机的“伪静态设置”,能省两小时。
- 日志是最好的老师:每次报错都看日志,Postfix和Dovecot的日志会告诉你一切。这次如果没有 docker logs,我根本找不到问题根源。
- 了解你的服务器环境:不同的Web服务器(Apache、Nginx、Kangle)处理伪静态的方式不同。我这次用的Kangle虽然兼容Apache规则,但需要通过面板开启支持。
- 证书顺序很重要:Postfix的 smtpd_tls_chain_files 参数,私钥必须在第一位。这是我卡最久的地方。
- 认证socket是桥梁:Postfix和Dovecot通过socket通信,必须让它们在同一个频道上。检查 smtpd_sasl_path 和 Dovecot的 unix_listener 是否匹配。
- 垃圾箱是第一站:自建邮局发的邮件,第一次进垃圾箱很正常。配好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 "内容"
愿你的邮件永不进垃圾箱,愿你的服务器永不宕机。 ?

Comments NOTHING