朝まだき 頁の奥で 文字めざむ
mkdir -p /home/ubuntu/mx-space /home/ubuntu/yohaku /home/ubuntu/migration
chmod 700 /home/ubuntu/migration
sudo apt update
sudo apt install -y nginx certbot python3-certbot-nginx unzip curl
sudo docker compose versionTZ=Asia/Shanghai
ALLOWED_ORIGINS=example.com
PG_USER=mx
PG_PASSWORD=实际数据库密码
PG_DATABASE=mx_core
SNOWFLAKE_WORKER_ID=1
ENCRYPT_ENABLE=true
ENCRYPT_KEY=旧服务实际使用的原密钥
JWT_SECRET=旧服务实际使用的原值sudo docker compose stop mx-core
umask 077
mkdir -p migration-backup
sudo docker compose exec -T postgres sh -c 'pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Fc' > migration-backup/mx-core.dump
sudo tar -czf migration-backup/mx-space-files.tar.gz -C data mx-spacecd /home/ubuntu/mx-space
mkdir -p data
sudo tar -xzf /home/ubuntu/migration/mx-space-files.tar.gz -C data
sudo docker compose up -d postgres redis
sudo docker compose pssudo docker compose exec -T postgres sh -c 'pg_restore -U "$POSTGRES_USER" -d "$POSTGRES_DB" --no-owner --no-privileges --exit-on-error' < /home/ubuntu/migration/mx-core.dumpmap $http_upgrade $mx_connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name example.com;
client_max_body_size 50m;
proxy_http_version 1.1;
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 $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $mx_connection_upgrade;
location /api/v3/ {
proxy_buffering off;
proxy_pass http://127.0.0.1:2333;
}
location /ws/ {
proxy_read_timeout 300s;
proxy_send_timeout 300s;
proxy_buffering off;
proxy_pass http://127.0.0.1:2333;
}
location /render {
proxy_pass http://127.0.0.1:2333;
}
location /proxy {
proxy_pass http://127.0.0.1:2333;
}
location / {
proxy_buffering off;
proxy_pass http://127.0.0.1:2323;
}
}sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d example.com --redirect
sudo certbot renew --dry-runmkdir -p ~/.ssh
chmod 700 ~/.ssh
ssh-keygen -t ed25519 -C "yohaku-actions-deploy" -f ~/.ssh/yohaku_actions -N ""
pbcopy < ~/.ssh/yohaku_actions.pubsudo ls -l /home/ubuntu/yohaku/.env
sudo chown ubuntu:ubuntu /home/ubuntu/yohaku/.env
sudo chmod 600 /home/ubuntu/yohaku/.env
sudo -u ubuntu test -r /home/ubuntu/yohaku/.env && echo "env readable"
记录日期:2026-09-24。
本次将已有 mx-space 数据迁移到 AWS,并通过 Yohaku Deploy Action 部署前端。本文记录部署顺序、配置方法,以及部署期间遇到的问题。
一、部署环境
同一域名按照路径分配请求:
Yohaku 构建时需要访问后端聚合接口,因此必须先完成后端迁移、域名和 HTTPS 配置,再部署前端。服务器只有 2 GB 内存,前端在 GitHub Actions 中构建,服务器负责运行产物。
二、自动部署项目的作用
部署工作流默认获取官方私有仓库 innei-dev/Yohaku 的源码,在 GitHub Actions 中安装依赖并构建,然后通过 SSH 上传服务器,由 PM2 启动或重新加载 Yohaku。
需要准备能够读取官方私有仓库及必要子模块的 GH_PAT。公开仓库 Innei/Yohaku 是设计存档,不包含完整部署代码。
工作流先读取上次构建哈希,再比较源码提交。如果源码发生变化,就构建、上传、更新服务器入口,最后写回成功构建的哈希。
三、准备新服务器
以 ubuntu 用户执行:
安全组和防火墙允许 HTTP、HTTPS 和部署所需的 SSH 流量。PostgreSQL、Redis 不开放公网端口;2333 绑定本机地址,由 Nginx 对外提供访问。前端模板默认监听所有接口,因此安全组不开放 2323。
四、准备后端 Compose 和环境变量
使用旧服务器上的 Compose 原文件作为基础,保存到 /home/ubuntu/mx-space/docker-compose.yml。
不要将聊天复制时出现的 HTML 实体、转义下划线和 Markdown 链接写入 YAML。修改后的关键配置如下:
保留迁移服务及依赖关系。mx-migrate 执行 node migrate.mjs,成功退出后再启动后端。
latest 会随发布变化,因此部署时应确认实际版本,后续升级单独安排。
在同目录创建 .env:
数据库用户名、数据库名和其他有效参数根据旧环境配置。ENCRYPT_KEY 必须保留原值,否则已有的加密配置可能无法解密。
在旧服务器查询实际环境变量:
如果容器已经停止,使用:
也可以在旧 Compose 目录查询配置文件:
输出仅用于安全复制,不提交仓库。如果原密钥为空,应继续确认实际配置来源,不直接生成新值替代。
在新服务器检查配置并下载镜像:
五、备份并迁移旧数据
正式迁移时,在旧 Compose 目录停止后端,避免备份期间继续产生文章、评论或上传文件:
确认每条命令成功后,将两个备份文件通过 SCP 或 SFTP 复制到新服务器的 /home/ubuntu/migration/。
同时保留旧 Compose、环境配置和镜像版本。数据库使用逻辑备份,不直接复制运行中的 PostgreSQL 数据目录。
新服务器的 Redis 重新初始化。如果旧环境还有队列任务,先处理完成再停止后端;旧 Redis 数据保留在旧服务器。
六、在新服务器恢复数据
先恢复应用文件,再启动 PostgreSQL 和 Redis:
确认 PostgreSQL 健康后,将备份恢复到新建的空数据库:
恢复成功后启动后端:
mx-migrate 是一次性任务,正常结果是退出码 0。恢复或迁移失败时,应先处理错误,不在部分恢复的数据库上重复导入。
七、配置域名、Nginx 和 HTTPS
在 Cloudflare 将 example.com 的 A 记录指向新服务器公网 IP。配置期间先使用 DNS only;如有旧 AAAA 记录,也要检查其目标。
创建 /etc/nginx/sites-available/example.com:
启用站点并申请证书。如果符号链接已经存在,不重复创建:
Certbot 会修改配置以启用 HTTPS,后续修改需要保留证书设置。
先访问后端健康检查和管理后台:
此时前端尚未启动,首页可能返回 502;先确认后端正常,再继续部署前端。
八、配置 Node.js 和前端环境
本次通过 nvm 安装 Node.js 24。使用 ubuntu 用户安装全局依赖:
因为 Node.js 位于用户目录,所以这里不使用 sudo。PM2 进程也由 ubuntu 用户管理。
非交互式 SSH 不一定执行 .bashrc 末尾的初始化。在部署工作流远程脚本的 source $HOME/.bashrc 后添加:
将修改提交到实际执行部署的 GitHub 仓库。
创建 /home/ubuntu/yohaku/.env:
其他必填变量以当前私有源码仓库的环境模板为准。设置文件权限:
工作流使用 shell 加载配置,因此带特殊字符的值需要正确引用。
九、准备 SSH 部署密钥
在本机 Mac 执行。如果目标文件已存在,不覆盖原密钥:
当前工作流没有解锁带口令私钥的步骤,因此使用专用的无口令密钥。
在服务器以 ubuntu 身份执行:
在末尾新增一行公钥,保留原有内容。保存后,在本机测试:
首次连接如需确认主机指纹,先去掉 BatchMode 参数,核对指纹并连接,再执行测试。返回 ubuntu 表示认证成功。
十、配置 GitHub Actions Secrets
进入部署仓库的 Settings,再进入 Secrets and variables、Actions,创建 Repository secrets。
在本机复制私钥:
私钥保存到 Actions Secret KEY。PASSWORD 和 SSH_PROXY 留空;如有旧值,应删除。
URL 必须填写完整字符串,GitHub Secret 不会自动将 ${BASE_URL}/api/v3 展开为实际地址。
源码仓库、构建命令和产物路径使用项目默认值。工作流通过 GITHUB_TOKEN 写回构建哈希,因此仓库权限和分支规则需要允许这一提交。
十一、首次部署与验证
清空 .github/deploy_build_hash 内容并提交,保留文件。否则继承的哈希可能与官方源码一致,导致首次部署被跳过。
确认后台配置了 theme/shiro,并检查聚合接口:
如果返回 404,检查主题配置,以及是否存在已发布、可见的记录。
在 GitHub Actions 中选择 Build and Deploy,手动触发 Run workflow。完成后以 ubuntu 用户执行:
执行 startup 输出的 sudo 命令,然后保存进程列表:
最后检查首页、文章、图片、登录、评论和实时连接。
十二、问题记录:
1. sudo 找不到 npm
执行 sudo npm install -g pm2 pnpm sharp 时,出现 sudo: npm: command not found。
原因是 nvm 将 Node.js 安装在 ubuntu 用户目录,而 sudo 的命令搜索路径不包含该目录。因此使用:
2. SSH 主机名包含无效字符
将多行 SSH 命令复制成一行,却保留参数间的反斜杠,会出现 hostname contains invalid characters。
反斜杠用于续行时必须位于行末。改用单行命令即可:
公网 IP 从 AWS 控制台获取,不使用服务器提示符中的内网地址。
3. Actions 无权读取环境文件
日志显示 Node.js 已加载,但随后出现 .env: Permission denied。因此需要检查文件归属和读取权限:
如仍失败,检查各级目录权限:
修正后重新执行失败的 Actions 任务。环境文件只需要读取权限,不需要执行权限或 777 权限。
4. 文件库仍显示旧图片地址
迁移后的文件链接仍使用旧前缀:
v14.13.0 根据后台 serverUrl 动态生成文件库链接,因此在设置中的 Site URLs 更新以下配置:
保存并刷新文件库后,链接应使用新前缀:
修改 ALLOWED_ORIGINS 或前端环境变量不能替代这项后台设置。如果新地址仍返回 404,需要检查实际文件是否已迁移。
文章正文、封面和主题配置中保存的绝对 URL 需要单独检查。后台设置不会自动改写这些引用。
十三、后续维护
十四、参考资料