适用场景:Nuxt 3 / Nuxt 4 项目,构建后需要通过 Node.js 运行
.output/server/index.mjs。
部署方式:GitHub + Self-hosted Runner + Docker Compose + 宝塔/Nginx。
示例项目:jiali-blog-web
示例端口:3004
1. 最终效果
完成后,整个部署流程会变成:
本地修改 Nuxt 项目
↓
git push main
↓
GitHub Actions 自动触发
↓
服务器上的 Self-hosted Runner 接收任务
↓
拉取最新代码
↓
Docker 构建 Nuxt
↓
npm ci
↓
npm run build
↓
生成 .output
↓
node .output/server/index.mjs
↓
启动新容器
↓
检查首页 /
↓
部署完成
以后发布新版本,基本只需要:
git push origin main
服务器会自动更新,不需要再登录宝塔手动构建。
2. 准备工作
开始之前,服务器需要已经安装:
Docker
Docker Compose
Git
SSH
同时建议准备一个专门负责部署的 Linux 用户:
deploy
不要让 GitHub Actions 长期使用 root。
本教程约定服务器目录结构:
/www/git/
└── jiali-blog-web/
/www/env/
└── jiali-blog-web.env
/home/deploy/
├── runner-cache/
│ └── actions-runner-linux-x64-2.336.0.tar.gz
└── runners/
└── jiali-blog-web/
其中:
/www/git/
存项目源码。
/www/env/
存生产环境变量。
/home/deploy/runners/
存 GitHub Self-hosted Runner。
3. 创建 deploy 用户
如果服务器已经有 deploy 用户,可以跳过这一节。
root 执行:
useradd -m -s /bin/bash deploy
把 deploy 加入 docker 用户组:
usermod -aG docker deploy
确认:
id deploy
然后切换:
su - deploy
测试 Docker:
docker ps
如果可以正常执行,说明 Docker 权限没有问题。
4. 配置 deploy 用户访问 GitHub
服务器需要自己从 GitHub 拉代码,所以 deploy 用户需要 GitHub SSH 权限。
切换到 deploy:
su - deploy
生成 SSH Key:
ssh-keygen \
-t ed25519 \
-C "deploy@server" \
-f ~/.ssh/id_ed25519 \
-N ""
查看公钥:
cat ~/.ssh/id_ed25519.pub
复制输出内容。
然后进入 GitHub:
Settings
→ SSH and GPG keys
→ New SSH key
类型选择:
Authentication Key
保存以后,在服务器测试:
ssh -T git@github.com
如果看到类似:
Hi xxx! You've successfully authenticated...
说明配置完成。
不要把
~/.ssh/id_ed25519私钥发给别人,也不要提交到 Git 仓库。
5. 给 /www/git 配置权限
推荐让 root 管理 /www/git 本身,同时允许 deploy 在里面创建项目目录。
root 执行:
chown root:deploy /www/git
chmod 775 /www/git
确认:
ls -ld /www/git
正常类似:
drwxrwxr-x root deploy ... /www/git
这样 deploy 用户就可以直接 clone 项目。
6. 克隆 Nuxt 项目
切换到 deploy:
su - deploy
进入源码目录:
cd /www/git
克隆项目:
git clone \
--depth=1 \
--branch main \
--single-branch \
git@github.com:LeviQin/jiali-blog-web.git
进入项目:
cd /www/git/jiali-blog-web
检查:
git remote -v
再测试:
git fetch --depth=1 origin main
如果没有报错,说明服务器可以正常拉取 GitHub 代码。
7. 一个很重要的 Git 权限规则
以后 /www/git/jiali-blog-web 统一让 deploy 用户操作 Git。
不要在 root 下直接:
git pull
否则可能出现:
fatal: detected dubious ownership in repository
正确做法:
su - deploy
cd /www/git/jiali-blog-web
git fetch --depth=1 origin main
git reset --hard origin/main
也可以在 root 下直接指定 deploy:
sudo -u deploy \
git -C /www/git/jiali-blog-web \
fetch --depth=1 origin main
推荐还是统一切到 deploy,比较不容易混乱。
8. 确认 Nuxt 的 Node 版本
先看 package.json。
例如:
{
"engines": {
"node": ">=22.19.0"
}
}
那么 Dockerfile 就不要使用:
FROM node:20
否则可能出现依赖或构建兼容问题。
本教程示例项目要求:
Node >= 22.19.0
所以使用:
node:22.19-alpine
9. Nuxt 生产环境应该怎么运行
Nuxt 开发时通常是:
npm run dev
但生产环境不是运行 npm run dev,也不建议使用 npm run preview。
正式部署应该:
npm run build
Nuxt 构建以后会生成:
.output/
最终 Node 服务入口:
.output/server/index.mjs
生产启动命令:
node .output/server/index.mjs
10. Dockerfile
在项目根目录创建:
Dockerfile
完整示例:
# ==============================
# Build Stage
# ==============================
FROM node:22.19-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
ENV NODE_ENV=production
RUN npm run build
# ==============================
# Production Stage
# ==============================
FROM node:22.19-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV HOST=0.0.0.0
ENV PORT=3004
COPY --from=builder /app/.output ./.output
EXPOSE 3004
CMD ["node", ".output/server/index.mjs"]
这里使用的是 Docker 多阶段构建。
第一阶段 builder 负责:
安装依赖
↓
构建 Nuxt
↓
生成 .output
第二阶段 runner 只复制:
.output
所以正式运行的镜像不会包含完整源码和开发依赖。
11. .dockerignore
项目根目录创建:
.dockerignore
推荐:
node_modules
.nuxt
.output
.git
.github
.env
.env.*
!.env.example
.idea
.vscode
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
README.md
这样可以避免无用文件进入 Docker build context。
特别注意:.env、.env.production 不要直接打进 Docker 镜像。
12. 创建生产环境变量文件
推荐把生产环境变量放在服务器:
/www/env/jiali-blog-web.env
而不是提交到 GitHub。
root 执行:
mkdir -p /www/env
touch /www/env/jiali-blog-web.env
修改权限:
chown root:deploy /www/env/jiali-blog-web.env
chmod 640 /www/env/jiali-blog-web.env
编辑:
vim /www/env/jiali-blog-web.env
或者用宝塔文件管理器编辑。
例如:
NUXT_PUBLIC_API_BASE=https://api.example.com
不要把真实密码、Token、数据库密码、Secret 提交到 GitHub。
13. Nuxt 环境变量需要注意什么
Nuxt 环境变量大致分两类:
运行时变量
构建时变量
推荐优先使用 Nuxt runtimeConfig。
例如:
export default defineNuxtConfig({
runtimeConfig: {
apiSecret: '',
public: {
apiBase: ''
}
}
})
生产环境可以使用:
NUXT_API_SECRET=xxx
NUXT_PUBLIC_API_BASE=https://api.example.com
这些变量可以通过 Docker Compose 的 env_file 在容器运行时注入。
但如果某个变量在 npm run build 阶段就被 Vite 直接编译进前端代码,那么仅仅设置 env_file 可能不够。
这种情况需要通过 Docker build.args 或构建阶段环境变量处理。
如果不确定,优先把配置放进 Nuxt runtimeConfig。
14. docker-compose.yml
项目根目录创建:
docker-compose.yml
完整示例:
services:
jiali-blog-web:
build:
context: .
dockerfile: Dockerfile
image: jiali-blog-web:latest
container_name: jiali-blog-web
restart: unless-stopped
ports:
- "127.0.0.1:3004:3004"
env_file:
- /www/env/jiali-blog-web.env
environment:
NODE_ENV: production
HOST: 0.0.0.0
PORT: 3004
healthcheck:
test:
[
"CMD",
"node",
"-e",
"fetch('http://127.0.0.1:3004/').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))"
]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
stop_grace_period: 10s
这里:
127.0.0.1:3004:3004
表示:
服务器 127.0.0.1:3004
↓
Docker 容器 3004
↓
Nuxt Nitro 3004
只绑定 127.0.0.1,意味着 3004 不直接暴露到公网。
公网访问统一通过宝塔 Nginx 反向代理。
15. 前端项目一定要 /health 吗
不需要。
Nuxt 前端项目可以直接检查首页 /。
Docker Healthcheck:
healthcheck:
test:
[
"CMD",
"node",
"-e",
"fetch('http://127.0.0.1:3004/').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))"
]
只要首页返回 2xx,Docker 就会认为容器 healthy。
如果首页 SSR 强依赖第三方服务,第三方服务故障可能导致首页返回 500,这时 Docker 也会变成 unhealthy。
简单博客、个人站点一般直接检查 / 就够用了。
16. 第一次手动 Docker 部署
正式接入自动部署之前,建议先手动跑一次。
切换 deploy:
su - deploy
进入项目:
cd /www/git/jiali-blog-web
先检查端口有没有被占用:
ss -lntp | grep ':3004'
没有输出,说明 3004 当前没有进程监听。
检查 Compose:
docker compose config
docker compose config可能会展开环境变量。不要把包含真实 Secret 的完整输出复制到公开日志或 GitHub Actions。
开始第一次构建:
docker compose up \
-d \
--build \
--wait \
--wait-timeout 90
第一次构建通常会比较慢,因为需要:
下载 Node 镜像
↓
npm ci
↓
Nuxt build
↓
创建生产镜像
↓
启动容器
17. 检查容器状态
执行:
docker compose ps
正常应该类似:
NAME IMAGE STATUS
jiali-blog-web jiali-blog-web:latest Up ... (healthy)
也可以:
docker inspect jiali-blog-web \
--format='Status={{.State.Status}} Health={{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}'
正常:
Status=running Health=healthy
18. 测试 Nuxt 首页
服务器执行:
curl -I http://127.0.0.1:3004/
正常应该看到:
HTTP/1.1 200 OK
如果不是 200,查看日志:
docker compose logs --tail=200
或者:
docker logs --tail=200 jiali-blog-web
19. 创建 GitHub Self-hosted Runner
这里使用 Self-hosted Runner,让服务器主动连接 GitHub,不需要 GitHub Runner SSH 登录服务器。
如果服务器已经下载过 Runner,可以缓存到:
/home/deploy/runner-cache/
例如:
/home/deploy/runner-cache/actions-runner-linux-x64-2.336.0.tar.gz
这样每增加一个项目,不用重新下载。
20. 创建项目 Runner 目录
root:
mkdir -p /home/deploy/runners/jiali-blog-web
设置权限:
chown -R deploy:deploy /home/deploy/runners/jiali-blog-web
切换 deploy:
su - deploy
进入:
cd /home/deploy/runners/jiali-blog-web
确认:
pwd
必须是:
/home/deploy/runners/jiali-blog-web
然后解压:
tar xzf \
/home/deploy/runner-cache/actions-runner-linux-x64-2.336.0.tar.gz
成功后:
ls -la
应该看到:
bin/
externals/
config.sh
env.sh
run.sh
svc.sh
21. Runner 解压出现 Permission denied
如果看到:
tar: ./bin: Cannot mkdir: Permission denied
tar: ./config.sh: Cannot open: Permission denied
说明 Runner 目录权限不属于 deploy。
退出:
exit
root 重新设置:
chown -R deploy:deploy \
/home/deploy/runners/jiali-blog-web
如果这个 Runner 还没有注册,也可以直接重建:
rm -rf /home/deploy/runners/jiali-blog-web
mkdir -p /home/deploy/runners/jiali-blog-web
chown -R deploy:deploy \
/home/deploy/runners/jiali-blog-web
然后再切换 deploy 解压。
22. 在 GitHub 注册 Runner
进入:
GitHub 仓库
→ Settings
→ Actions
→ Runners
→ New self-hosted runner
选择:
Linux
x64
如果已经有 Runner 缓存,Download 部分不用再执行。
只执行 GitHub 提供的注册命令,例如:
./config.sh \
--url https://github.com/LeviQin/jiali-blog-web \
--token GitHub临时Token
Runner 注册 Token 是临时 Token,不要截图发到公开地方,也不要写进配置文件。
23. Runner 注册时怎么填写
Runner group:直接按 Enter,使用 Default。
Runner name:
jiali-blog-web-runner
Additional labels:
jiali-blog-web,docker
Work folder:直接 Enter,使用默认 _work。
最终:
Runner group:
Default
Runner name:
jiali-blog-web-runner
Labels:
jiali-blog-web,docker
Work folder:
_work
24. Runner 安装成 systemd 服务
注册以后不要把 ./run.sh 作为正式运行方式。
退出到 root:
exit
进入 Runner:
cd /home/deploy/runners/jiali-blog-web
安装:
./svc.sh install deploy
启动:
./svc.sh start
查看:
./svc.sh status
正常:
Active: active (running)
GitHub:
Settings
→ Actions
→ Runners
应该看到:
jiali-blog-web-runner
Idle
说明 Runner 正在等待部署任务。
Runner 已经安装 systemd 后,不要再执行:
./run.sh
否则可能出现:
A session for this runner already exists
日常管理使用:
./svc.sh status
./svc.sh stop
./svc.sh start
25. 创建 GitHub Actions deploy.yml
项目创建:
.github/workflows/deploy.yml
完整示例:
name: Deploy Jiali Blog Web
on:
push:
branches:
- main
concurrency:
group: jiali-blog-web-production
cancel-in-progress: false
jobs:
deploy:
name: Deploy Production
runs-on:
- self-hosted
- Linux
- X64
- jiali-blog-web
timeout-minutes: 30
steps:
- name: Update source code
run: |
set -e
cd /www/git/jiali-blog-web
echo "========== 更新代码 =========="
git fetch --depth=1 origin main
git reset --hard origin/main
echo ""
echo "========== 当前部署版本 =========="
git log -1 --oneline
- name: Deploy Docker
run: |
set -e
cd /www/git/jiali-blog-web
echo "========== 构建并更新 Nuxt 容器 =========="
if ! docker compose up \
-d \
--build \
--remove-orphans \
--wait \
--wait-timeout 90; then
echo ""
echo "========== 部署失败 =========="
echo ""
echo "========== Docker Compose 状态 =========="
docker compose ps || true
echo ""
echo "========== 容器日志 =========="
docker compose logs --tail=200 || true
echo ""
echo "========== 容器状态 =========="
docker inspect jiali-blog-web \
--format='Status={{.State.Status}} ExitCode={{.State.ExitCode}}' || true
echo ""
echo "========== 健康检查详情 =========="
docker inspect jiali-blog-web \
--format='{{json .State.Health}}' || true
exit 1
fi
- name: Check container
run: |
set -e
cd /www/git/jiali-blog-web
echo "========== Docker Compose 状态 =========="
docker compose ps
echo ""
echo "========== jiali-blog-web 状态 =========="
docker inspect jiali-blog-web \
--format='Status={{.State.Status}} Health={{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}'
- name: Verify website
run: |
set -e
echo "========== Nuxt 首页检查 =========="
curl \
--fail \
--silent \
--show-error \
--output /dev/null \
http://127.0.0.1:3004/
echo "Nuxt 首页访问正常"
- name: Cleanup Docker images
run: |
set -e
echo "========== 清理无用 Docker 镜像 =========="
docker image prune -f
- name: Deployment completed
run: |
set -e
cd /www/git/jiali-blog-web
echo ""
echo "========================================"
echo "jiali-blog-web 部署成功"
echo "========================================"
echo ""
echo "========== 部署版本 =========="
git log -1 --oneline
echo ""
echo "========== 最终容器状态 =========="
docker compose ps
echo ""
echo "========== 网站地址 =========="
echo "http://127.0.0.1:3004/"
26. 为什么 deploy.yml 不使用 actions/checkout
Self-hosted Runner 本身就在服务器,服务器已经有:
/www/git/jiali-blog-web
所以没必要再 checkout 一份到 Runner 的 _work 目录。
我们直接:
cd /www/git/jiali-blog-web
git fetch --depth=1 origin main
git reset --hard origin/main
这样部署目录固定,也可以继续使用服务器现有的 GitHub SSH Key。
27. 提交部署文件
本地项目确认包含:
Dockerfile
.dockerignore
docker-compose.yml
.github/workflows/deploy.yml
提交:
git add .
git commit -m "ci: add nuxt docker deployment"
git push origin main
GitHub Actions 会自动触发。
28. 第一次 Actions 怎么检查
进入:
GitHub
→ jiali-blog-web
→ Actions
→ Deploy Jiali Blog Web
正常步骤:
Update source code ✅
Deploy Docker ✅
Check container ✅
Verify website ✅
Cleanup Docker images ✅
Deployment completed ✅
如果 Runner 还没启动,可能显示:
Waiting for a runner to pick up this job
启动 Runner systemd 后,它会自动接任务。
29. 宝塔 Nginx 反向代理
Docker 只监听:
127.0.0.1:3004
所以公网需要通过宝塔 Nginx。
假设网站:
https://example.com
反向代理目标:
http://127.0.0.1:3004
Nginx 核心配置类似:
location / {
proxy_pass http://127.0.0.1:3004;
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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
SSL 继续由宝塔/Nginx 管理。
Docker 内部不需要自己配置 HTTPS。
完整链路:
浏览器
↓
HTTPS :443
↓
Nginx
↓
127.0.0.1:3004
↓
Docker
↓
Nuxt
30. 发布新版本
全部配置完成以后,日常流程非常简单。
本地:
git add .
git commit -m "feat: update website"
git push origin main
后面的事情自动完成:
GitHub
↓
Runner
↓
拉代码
↓
重新构建镜像
↓
更新容器
↓
检查网站
↓
上线
31. 常用服务器命令
进入项目:
su - deploy
cd /www/git/jiali-blog-web
查看容器:
docker compose ps
查看日志:
docker compose logs --tail=200
持续看日志:
docker compose logs -f
重新构建:
docker compose up -d --build
带健康检查等待:
docker compose up \
-d \
--build \
--wait \
--wait-timeout 90
停止:
docker compose stop
停止并删除容器:
docker compose down
检查首页:
curl -I http://127.0.0.1:3004/
检查 Docker Health:
docker inspect jiali-blog-web \
--format='Status={{.State.Status}} Health={{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}'
清理无用镜像:
docker image prune -f
32. 常见问题:端口被占用
错误:
Bind for 127.0.0.1:3004 failed:
port is already allocated
检查:
ss -lntp | grep ':3004'
或者:
docker ps --filter publish=3004
如果是旧容器:
docker stop 旧容器名
docker rm 旧容器名
再部署:
docker compose up -d --build
33. 常见问题:容器 unhealthy
查看:
docker compose ps
如果是:
unhealthy
先不要重新 build。
查看日志:
docker compose logs --tail=200
再看 Healthcheck:
docker inspect jiali-blog-web \
--format='{{json .State.Health}}'
手动检查:
curl -I http://127.0.0.1:3004/
如果 Nuxt 本身可以正常运行但首页不是 2xx,需要检查:
SSR 报错
API 请求失败
环境变量错误
路由重定向
运行端口错误
34. 常见问题:容器一直 Restarting
如果:
Restarting (1)
这通常不是 Docker Healthcheck 的问题,而是 Node 进程启动后直接崩了。
查看:
docker logs --tail=200 jiali-blog-web
重点看最前面的:
Error
ReferenceError
TypeError
Cannot find module
先修 Node/Nuxt 报错,再重新构建。
35. 常见问题:npm ci 失败
如果 Dockerfile:
RUN npm ci
报错,通常是 package.json 和 package-lock.json 不同步。
本地执行:
npm install
确认 package-lock.json 有更新,然后提交:
git add package-lock.json
git commit -m "chore: update package lock"
git push
36. 常见问题:Node 版本不够
如果 package.json:
"engines": {
"node": ">=22.19.0"
}
Dockerfile 却是:
FROM node:20
可能出现:
Unsupported engine
Build failed
依赖安装失败
直接把 Docker Node 版本和项目要求统一,例如:
FROM node:22.19-alpine
37. 常见问题:Git dubious ownership
错误:
fatal: detected dubious ownership in repository
不要随手执行:
git config --global --add safe.directory ...
如果项目本来就应该由 deploy 管理,更合理的处理方式:
chown -R deploy:deploy /www/git/jiali-blog-web
之后:
su - deploy
cd /www/git/jiali-blog-web
git pull
38. 常见问题:Runner Permission denied
Runner 解压出现:
Permission denied
检查:
ls -ld /home/deploy/runners/jiali-blog-web
应该是:
deploy deploy
不是:
root root
修复:
chown -R deploy:deploy \
/home/deploy/runners/jiali-blog-web
39. 常见问题:Runner duplicate session
看到:
A session for this runner already exists
通常是 systemd 已经启动,你又执行了一次:
./run.sh
检查:
pgrep -af "Runner.Listener"
Runner 已经 systemd 托管后不要再手动 ./run.sh。
40. 常见问题:Runner 显示 Offline
root:
cd /home/deploy/runners/jiali-blog-web
./svc.sh status
如果没启动:
./svc.sh start
也可以在 GitHub:
Settings
→ Actions
→ Runners
确认 Runner 是否在线。
41. 更新环境变量以后怎么办
如果只是 Nuxt 运行时环境变量,修改:
/www/env/jiali-blog-web.env
然后重建容器配置:
cd /www/git/jiali-blog-web
docker compose up -d --force-recreate
如果变量属于构建期变量,则需要重新:
docker compose up -d --build
42. 多个 Nuxt 项目怎么部署
可以继续使用同一台服务器。
例如:
/www/git/
├── jiali-blog-web
├── project-a-web
└── project-b-web
/www/env/
├── jiali-blog-web.env
├── project-a-web.env
└── project-b-web.env
/home/deploy/runners/
├── jiali-blog-web
├── project-a-web
└── project-b-web
端口不要重复:
jiali-blog-web → 3004
project-a-web → 3005
project-b-web → 3006
每个项目都有自己的 Runner、Runner Label、Compose、Container、Image、端口和 env 文件。
43. 新 Nuxt 项目部署检查表
以后新增项目,可以按这个顺序做:
1. 确认 package.json 的 Node 版本
2. 添加 Dockerfile
3. 添加 .dockerignore
4. 添加 docker-compose.yml
5. 准备 /www/env/<project>.env
6. deploy 用户 clone 项目
7. 创建 /home/deploy/runners/<project>
8. 解压 Runner 缓存
9. GitHub 注册 Runner
10. 安装 systemd
11. 手动 docker compose up -d --build
12. 检查容器 healthy
13. curl 检查首页
14. 添加 deploy.yml
15. push main
16. 检查 GitHub Actions
17. 宝塔配置 Nginx 反向代理
18. 完成
44. 推荐的最终目录结构
/home/deploy/
├── runner-cache/
│ └── actions-runner-linux-x64-2.336.0.tar.gz
└── runners/
├── jiali-blog-web/
├── project-a-web/
└── project-b-web/
/www/git/
├── jiali-blog-web/
├── project-a-web/
└── project-b-web/
/www/env/
├── jiali-blog-web.env
├── project-a-web.env
└── project-b-web.env
项目仓库:
jiali-blog-web/
├── .github/
│ └── workflows/
│ └── deploy.yml
├── .dockerignore
├── Dockerfile
├── docker-compose.yml
├── package.json
├── package-lock.json
├── nuxt.config.ts
└── ...
45. 一套可以长期复用的规则
建议以后统一保持:
Git 操作:deploy 用户
Docker 操作:deploy 用户
Runner 服务:systemd
Runner 运行用户:deploy
源码:/www/git/<project>
环境变量:/www/env/<project>.env
Runner:/home/deploy/runners/<project>
镜像名:<project>:latest
容器名:<project>
Runner label:<project>
这样部署多个项目时不会越来越乱。
46. 最终总结
Nuxt 和普通 Node/Koa 后端最大的区别,是 Nuxt 部署前需要先构建:
源码
↓
npm ci
↓
npm run build
↓
.output
↓
node .output/server/index.mjs
所以 Docker 推荐使用多阶段构建,生产容器只保留 .output。
自动部署则继续使用:
GitHub Actions
+
Self-hosted Runner
+
Docker Compose
完成一次以后,后续发布基本就只剩:
git push origin main
其余步骤全部由服务器自动完成。
private note
交流
文章暂不开放公开评论。如果你有想法、问题或建议,欢迎私下联系站长。
联系站长 →