From df125181cefd2a05ff06ebd03801c4ea49866a99 Mon Sep 17 00:00:00 2001 From: zhang1106 <849185023@qq.com> Date: Thu, 5 Mar 2026 11:13:38 +0800 Subject: [PATCH] feat: add Zeabur deployment configuration --- DEPLOYMENT.md | 128 +++++++++++++++++++++++++++++++++++++++ backend/.dockerignore | 19 ++++++ backend/Dockerfile | 15 +++++ frontend/.dockerignore | 19 ++++++ frontend/Dockerfile | 23 +++++++ frontend/nginx.conf | 41 +++++++++++++ frontend/vite.config.mjs | 1 + zeabur.yaml | 70 +++++++++++++++++++++ 8 files changed, 316 insertions(+) create mode 100644 backend/.dockerignore create mode 100644 backend/Dockerfile create mode 100644 frontend/.dockerignore create mode 100644 frontend/Dockerfile create mode 100644 frontend/nginx.conf create mode 100644 zeabur.yaml diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md index a66d24c..eeabb44 100644 --- a/DEPLOYMENT.md +++ b/DEPLOYMENT.md @@ -676,6 +676,134 @@ sudo certbot renew --dry-run --- +## Zeabur 云平台部署(推荐免费方案)⭐ + +Zeabur 是国内团队开发的云平台,国内访问速度快,提供免费额度。 + +### 1. 准备工作 + +- GitHub 账号 +- 项目代码已推送到 GitHub 仓库 + +### 2. 注册 Zeabur + +1. 访问 [Zeabur 官网](https://zeabur.com) +2. 点击「Sign in with GitHub」使用 GitHub 登录 +3. 授权 Zeabur 访问你的仓库 + +### 3. 创建项目 + +1. 进入 Zeabur Dashboard +2. 点击「New Project」创建新项目 +3. 选择区域(推荐:Hong Kong 或 Singapore) + +### 4. 部署 MySQL 数据库 + +1. 在项目中点击「Add Service」→「Prebuilt」 +2. 搜索并选择「MySQL」 +3. 点击部署 +4. 记录数据库连接信息(稍后配置后端使用) + +### 5. 部署后端服务 + +1. 点击「Add Service」→「Git」 +2. 选择你的 GitHub 仓库 +3. 选择 `backend` 目录 +4. 配置环境变量: + +```env +NODE_ENV=production +PORT=8000 +DB_TYPE=mysql +JWT_SECRET=your-strong-jwt-secret-at-least-32-characters +TOKEN_EXPIRY=24h +``` + +5. 配置数据库连接(从 MySQL 服务获取): + +```env +MYSQL_HOST=${mysql:MYSQL_HOST} +MYSQL_PORT=${mysql:MYSQL_PORT} +MYSQL_USERNAME=${mysql:MYSQL_USERNAME} +MYSQL_PASSWORD=${mysql:MYSQL_PASSWORD} +MYSQL_DATABASE=${mysql:MYSQL_DATABASE} +``` + +6. 点击部署 + +### 6. 部署前端服务 + +1. 点击「Add Service」→「Git」 +2. 选择同一个仓库 +3. 选择 `frontend` 目录 +4. 配置环境变量: + +```env +VITE_API_URL=${idc-backend:ZEABUR_WEB_URL} +``` + +5. 点击部署 + +### 7. 配置域名 + +1. 进入前端服务 →「Domains」 +2. 点击「Generate Domain」生成免费域名 +3. 或绑定自定义域名 + +### 8. 部署完成 + +访问生成的域名即可使用系统。 + +### Zeabur 配置文件说明 + +项目根目录的 `zeabur.yaml` 文件定义了服务配置: + +```yaml +services: + - name: idc-backend + type: prebuilt + source: + type: static + path: backend + env: + NODE_ENV: production + PORT: 8000 + DB_TYPE: mysql + + - name: idc-frontend + type: prebuilt + source: + type: static + path: frontend + env: + NODE_ENV: production + + - name: mysql + type: prebuilt + source: + type: image + url: mysql:8.0 + env: + MYSQL_DATABASE: idc_management +``` + +### 常见问题 + +**Q: 部署失败怎么办?** +- 检查构建日志,确认依赖安装成功 +- 确认环境变量配置正确 +- 检查 Dockerfile 是否存在 + +**Q: 数据库连接失败?** +- 确认 MySQL 服务已启动 +- 检查环境变量引用格式:`${mysql:MYSQL_HOST}` + +**Q: 前端无法访问后端 API?** +- 检查 `VITE_API_URL` 环境变量 +- 确认后端服务已启动并分配域名 + +--- + ## 数据库配置 ### SQLite(开发环境/小规模) diff --git a/backend/.dockerignore b/backend/.dockerignore new file mode 100644 index 0000000..6cb6447 --- /dev/null +++ b/backend/.dockerignore @@ -0,0 +1,19 @@ +node_modules +npm-debug.log +.env +.env.local +.env.*.local +dist +.git +.gitignore +*.md +.DS_Store +Thumbs.db +*.log +coverage +.nyc_output +.vscode +.idea +*.swp +*.swo +*~ diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..62cf188 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,15 @@ +FROM node:20-alpine + +WORKDIR /app + +COPY package*.json ./ + +RUN npm ci --only=production + +COPY . . + +RUN mkdir -p uploads/avatars temp + +EXPOSE 8000 + +CMD ["node", "server.js"] diff --git a/frontend/.dockerignore b/frontend/.dockerignore new file mode 100644 index 0000000..6cb6447 --- /dev/null +++ b/frontend/.dockerignore @@ -0,0 +1,19 @@ +node_modules +npm-debug.log +.env +.env.local +.env.*.local +dist +.git +.gitignore +*.md +.DS_Store +Thumbs.db +*.log +coverage +.nyc_output +.vscode +.idea +*.swp +*.swo +*~ diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..97058d3 --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,23 @@ +FROM node:20-alpine AS builder + +WORKDIR /app + +COPY package*.json ./ + +RUN npm ci + +COPY . . + +ARG VITE_API_URL +ENV VITE_API_URL=$VITE_API_URL + +RUN npm run build + +FROM nginx:alpine + +COPY --from=builder /app/dist /usr/share/nginx/html +COPY nginx.conf /etc/nginx/templates/default.conf.template + +EXPOSE 80 + +CMD ["sh", "-c", "envsubst '${BACKEND_URL}' < /etc/nginx/templates/default.conf.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"] diff --git a/frontend/nginx.conf b/frontend/nginx.conf new file mode 100644 index 0000000..37b8e1c --- /dev/null +++ b/frontend/nginx.conf @@ -0,0 +1,41 @@ +server { + listen 80; + server_name localhost; + root /usr/share/nginx/html; + index index.html; + + gzip on; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + gzip_min_length 1000; + + location / { + try_files $uri $uri/ /index.html; + } + + location /api { + proxy_pass ${BACKEND_URL}; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + 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_cache_bypass $http_upgrade; + proxy_read_timeout 86400; + } + + location /uploads { + proxy_pass ${BACKEND_URL}; + 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; + } + + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|hdr)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } +} diff --git a/frontend/vite.config.mjs b/frontend/vite.config.mjs index 7aadd5d..c8df52e 100644 --- a/frontend/vite.config.mjs +++ b/frontend/vite.config.mjs @@ -35,6 +35,7 @@ const getFrontendPort = () => { const port = getFrontendPort(); export default defineConfig({ + base: '/', plugins: [ react(), Components({ diff --git a/zeabur.yaml b/zeabur.yaml new file mode 100644 index 0000000..2a4c827 --- /dev/null +++ b/zeabur.yaml @@ -0,0 +1,70 @@ +services: + - name: idc-backend + type: prebuilt + source: + type: static + path: backend + env: + NODE_ENV: production + PORT: 8000 + DB_TYPE: mysql + JWT_SECRET: ${JWT_SECRET} + TOKEN_EXPIRY: 24h + configs: + - type: env + name: MYSQL_HOST + valueFrom: + type: service + serviceName: mysql + serviceConfigKey: host + - type: env + name: MYSQL_PORT + valueFrom: + type: service + serviceName: mysql + serviceConfigKey: port + - type: env + name: MYSQL_USERNAME + valueFrom: + type: service + serviceName: mysql + serviceConfigKey: username + - type: env + name: MYSQL_PASSWORD + valueFrom: + type: service + serviceName: mysql + serviceConfigKey: password + - type: env + name: MYSQL_DATABASE + valueFrom: + type: service + serviceName: mysql + serviceConfigKey: database + + - name: idc-frontend + type: prebuilt + source: + type: static + path: frontend + env: + NODE_ENV: production + configs: + - type: env + name: BACKEND_URL + valueFrom: + type: service + serviceName: idc-backend + serviceConfigKey: url + + - name: mysql + type: prebuilt + source: + type: image + url: mysql:8.0 + env: + MYSQL_DATABASE: idc_management + MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} + volumes: + - name: mysql-data + mountPath: /var/lib/mysql