这篇记录一下我自己实操的一套迁移流程:
内网有一套 WordPress(Docker),公网 VPS 上也跑着 Trojan-go + Caddy(梯子),我希望“梯子不坏”的前提下,把 WordPress 迁到公网,并用 v.nightfarer.one 访问。

最终我采用了比较稳的 方案A:导出 SQL + wp-content 打包,不用插件,迁移更可控。


最终架构(迁完就是这个形态)

访问链路大概是:

浏览器 → https://v.nightfarer.one:443 → Caddy(入口 TLS) → Nginx Proxy Manager(NPM 统一反代管理) → WordPress(Apache/PHP) → MySQL

关键点:

  • Caddy 继续做入口(443/80),梯子逻辑不动大框架
  • Trojan-go 让出 443,改到 8443(客户端端口也要改)
  • NPM 只负责管理转发(更方便以后加站点/改反代),不强求它签证书

0)准备:先把变量记清楚(很重要)

下面这些名字你按自己机器上的实际情况替换(看 docker ps):

  • 公网 Trojan/Caddy 容器:
    • trojan-trojan-1
    • trojan-caddy-1
  • 公网 WordPress 栈:
    • wp-stack-wordpress-1
    • wp-stack-db-1
    • wp-stack-npm-1

建议先在两台机器(内网旧服务器 / 公网新服务器)都跑一遍:

docker ps

确认容器名对得上。


1)公网 VPS:先把 Trojan 挪走(释放 443 给 Caddy)

因为 443 只能被一个东西占用。如果 Trojan 占着 443,Caddy 就没法做入口 TLS。

我的做法是:Trojan 映射到 8443:443(Trojan 容器内部仍然是 443,只是宿主机端口换成 8443)。

1.1 修改 Trojan 的 docker-compose.yml(公网服务器)

把 Trojan 的 ports 改成:

ports:
  - "8443:443"
  - "8443:443/udp"

然后重建:

cd ~/trojan
docker compose down
docker compose up -d

验证端口有没有符合预期:

ss -lntp | egrep ':(443|8443)\b'
  • 看到 :8443 有监听(docker-proxy)说明 Trojan 映射成功
  • :443 后面应该留给 Caddy/反代入口用

2)DNS:v.nightfarer.one 指向公网 VPS

DNS(例如 Cloudflare)里把:

  • A v → 公网VPS_IP

然后验证解析是否生效:

dig v.nightfarer.one +short

3)公网 VPS:Caddy 入口反代到 NPM(别踩 127.0.0.1 的坑)

一个经典坑:容器内的 127.0.0.1 不是宿主机 127.0.0.1

所以 Caddy 容器里写:

reverse_proxy 127.0.0.1:8080

大概率会翻车(除非你很明确用 host network 或特殊桥接)。

3.1 让 Caddy 能“看见” NPM(公网服务器)

我这里验证 Caddy 容器能解析 NPM 容器名:

docker exec -it trojan-caddy-1 sh -c "getent hosts wp-stack-npm-1 || ping -c 1 wp-stack-npm-1"

如果能输出 wp-stack-npm-1 的 IP,说明网络可达。

如果你这里解析不到,大概率是两个 compose 不在同一个 docker network。
最简单的补救方式之一是:
docker network connect wp-stack_backend trojan-caddy-1
(把 Caddy 容器挂到 wp-stack 的网络里)

3.2 配 Caddyfile(公网服务器)

我用的示例(入口站点 v.nightfarer.one → NPM):

v.nightfarer.one {
    reverse_proxy wp-stack-npm-1:80
}

重启 Caddy:

docker restart trojan-caddy-1

验证:

curl -I https://v.nightfarer.one

4)NPM:反代到 WordPress,并传递 HTTPS 头

在 NPM 面板里新建 Proxy Host:

  • Domain Namesv.nightfarer.one
  • Forward Hostname / IPwp-stack-wordpress-1
  • Forward Port80
  • Schemehttp

4.1 强烈建议加 NPM Advanced(避免 WordPress 识别不到 HTTPS)

在 NPM 的 “Advanced / 自定义 Nginx 配置” 填:

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Port 443;

解释一下:
WordPress 很依赖这些头来判断自己是不是在 HTTPS 下。没有的话就容易出现登录跳转、后台循环跳转等问题。


5)迁移方案A:导出 SQL + 打包 wp-content(最稳)

这个方案就是 WordPress “本体迁移”:

  • **数据库:**导出 wordpress.sql
  • **内容:**打包 wp-content(主题、插件、上传文件都在里面)

5.1 内网旧服务器:导出数据库(MySQL 在 Docker 里)

如果你直接在宿主机跑:

mysqldump -u wpuser -p wordpress > wordpress.sql

很多时候会报 Access denied 或连不上(因为数据库不是 localhost,而是在容器网络里)。

正确姿势:进 MySQL 容器里 dump

✅ 推荐(MySQL 8 常见权限坑:tablespaces):

docker exec wp-stack-db-1 \
  mysqldump -u wpuser -pwppass --no-tablespaces wordpress \
  > /root/wordpress.sql

ls -lh /root/wordpress.sql

如果你看到类似 PROCESS privilege 报错,就是 --no-tablespaces 这个参数没加导致的。


5.2 内网旧服务器:打包 wp-content

wp-content 在 WordPress 容器里,一般路径是 /var/www/html/wp-content

打包:

docker exec wp-stack-wordpress-1 \
  tar -czf /tmp/wp-content.tar.gz -C /var/www/html wp-content

拷到宿主机:

docker cp wp-stack-wordpress-1:/tmp/wp-content.tar.gz /root/wp-content.tar.gz
ls -lh /root/wp-content.tar.gz

5.3 把文件从内网传到公网 VPS

我用 scp(你也可以 rsync):

scp /root/wordpress.sql /root/wp-content.tar.gz root@公网IP:/root/

5.4 公网 VPS:导入数据库(重点:别让 < 在宿主机被解析)

先把 SQL 放进 MySQL 容器:

docker cp /root/wordpress.sql wp-stack-db-1:/tmp/wordpress.sql
docker exec -it wp-stack-db-1 ls -lh /tmp/wordpress.sql

然后导入(✅关键写法):

docker exec -i wp-stack-db-1 sh -c \
"mysql -u wpuser -pwppass wordpress < /tmp/wordpress.sql"

为什么要这样写?
因为如果你写成:
docker exec -it wp-stack-db-1 mysql ... < /tmp/wordpress.sql
那个 < /tmp/wordpress.sql 会被 宿主机 shell 先解析,容器里根本读不到,就会出现 “No such file”。

验证导入是否成功(随便查个数量):

docker exec -it wp-stack-db-1 mysql -u wpuser -pwppass wordpress -e \
"SELECT COUNT(*) AS posts FROM wp_posts;"

5.5 公网 VPS:恢复 wp-content

把压缩包丢进 WordPress 容器:

docker cp /root/wp-content.tar.gz wp-stack-wordpress-1:/tmp/wp-content.tar.gz

解压覆盖(注意先删旧 wp-content):

docker exec -it wp-stack-wordpress-1 sh -c \
"cd /var/www/html && rm -rf wp-content && tar -xzf /tmp/wp-content.tar.gz"

修权限(不修的话,后台可能无法上传/装插件):

docker exec -it wp-stack-wordpress-1 \
  chown -R www-data:www-data /var/www/html/wp-content

重启:

docker restart wp-stack-wordpress-1

6)确认域名(home / siteurl)正确

虽然我最终内外网都用同域名 v.nightfarer.one,但迁移后依然建议确认一下。

docker exec -it wp-stack-db-1 mysql -u wpuser -pwppass wordpress -e \
"SELECT option_name, option_value FROM wp_options WHERE option_name IN ('home','siteurl');"

必要时更新:

docker exec -it wp-stack-db-1 mysql -u wpuser -pwppass wordpress -e \
"UPDATE wp_options SET option_value='https://v.nightfarer.one' WHERE option_name IN ('home','siteurl');"

7)检查上传大小限制(我这里已经到 256MB)

后台一般会显示 “最大上传文件大小:xxx MB”。

更“底层”的方式(看 PHP 配置):

docker exec -it wp-stack-wordpress-1 php -i | egrep \
'upload_max_filesize|post_max_size|memory_limit|max_execution_time|max_input_time'

如果你想改得更大(例如 512MB),一般要通过挂载自定义 php ini 文件来做(不建议在容器里手改)。


8)常见坑(我踩过的,顺手写一下)

  • 坑1:容器里写 127.0.0.1 反代宿主机
    基本不行,除非你用 host network 或做特殊桥接。
    更稳的是用 容器名:端口,前提是两个容器在同一个 Docker network。
  • 坑2:NPM 申请证书失败(HTTP-01)
    因为 80/443 并不在 NPM 手里(入口在 Caddy),Let’s Encrypt 验证自然失败。
    我这里的策略是:证书交给 Caddy 自动签,NPM 只做内部转发。
  • 坑3:导入 SQL 用 < 会报文件找不到
    记住:< 会在宿主机先解析。正确姿势是:
    docker exec -i ... sh -c "mysql ... < /tmp/file.sql"

结尾

迁完之后,我这边表现是:

  • 首页内容正常
  • /wp-admin/ 正常登录
  • 上传限制显示 256MB(也能从 PHP 配置验证)

整个流程属于“尽量少动梯子、稳稳把 WordPress 搬过去”的方式,后面要再挂新站点也很轻松:基本就是 NPM 里加一个 Proxy Host、Caddy 入口加一个站点块。

此作者没有提供个人介绍。
最后更新于 2026-02-05