release(main): 集成 nginx 同域入口恢复

This commit is contained in:
Cheng Zhou
2026-03-31 09:17:12 +08:00
parent 38b9838d63
commit e5e97e640b
8 changed files with 122 additions and 30 deletions
+7 -9
View File
@@ -4,14 +4,14 @@
- 生产入口:`docker-compose.yaml`
- 初始化方式:`docker compose run --rm backend-init`
- 启动方式:`docker compose up -d --build`
- 运行拓扑:`frontend``backend``db`
- 对外入口:仓库外部统一反向代理;建议将 `/` 转发到 `frontend`,将 `/api``/health` 转发到 `backend`
- 运行拓扑:`nginx``backend``db`
- 对外入口:`nginx` 提供前端静态资源,并同域反代后端 API
- 数据库 schema 来源:Alembic migration,不再依赖 `database/init.sql`
- 默认无任何 demo 数据;生产初始化只确保固定管理员 `admin@huapont.cn / admin123` 存在
- 验证方式:
- `docker compose config`
- `curl -i http://127.0.0.1:4173/`
- `curl -i http://127.0.0.1:8000/health`
- `curl -i http://127.0.0.1/`
- `curl -i http://127.0.0.1/health`
## 账号与注册
- 初始化管理员:`admin@huapont.cn / admin123`(通过生产初始化命令显式创建)
@@ -28,11 +28,9 @@
- 普通成员(无项目角色):仅浏览
## 访问方式
- 前端:`http://localhost:4173`
- 后端 API`http://localhost:8000/api/v1/*`
- 生产环境建议通过外部反向代理提供同域访问,前端代码默认请求同域 `/api/v1/*`
- 如果本地直接访问 `http://localhost:4173`,可在 `frontend/.env` 中设置 `VITE_API_BASE_URL=http://localhost:8000`,让前端直连后端 API
- `docker compose` 构建前端容器时,默认不注入 `VITE_API_BASE_URL`,生产会走同域 `/api/v1/*`;仅在本地直连后端时才显式设置 `VITE_API_BASE_URL=http://localhost:8000`
- 前端:`http://localhost`
- 后端 API同域 `/api/v1/*`
- `nginx` 负责托管前端静态资源,并将 `/api``/health` 转发到 `backend`
## 仓库治理文档
- 分支治理规范:`docs/branch-governance.md`
+12 -7
View File
@@ -50,16 +50,21 @@ services:
networks:
- ctms_net
frontend:
nginx:
build:
context: ./frontend
dockerfile: Dockerfile
args:
VITE_API_BASE_URL: ${VITE_API_BASE_URL:-}
container_name: ctms_frontend
context: .
dockerfile: nginx/Dockerfile
container_name: ctms_nginx
restart: always
ports:
- "4173:4173"
- "80:80"
- "443:443"
- "8888:8888"
volumes:
- ./nginx/certs:/etc/nginx/certs:ro
- ./frontend/public/favicon.ico:/usr/share/nginx/html/favicon.ico:ro
depends_on:
- backend
networks:
- ctms_net
@@ -103,8 +103,8 @@ Expected: PASS
**Step 3: Check HTTP endpoints**
Run: `curl -i http://127.0.0.1:4173/`
Run: `curl -i http://127.0.0.1/`
Expected: `200 OK` and HTML payload
Run: `curl -i http://127.0.0.1:8000/health`
Run: `curl -i http://127.0.0.1/health`
Expected: successful backend health response
@@ -0,0 +1,19 @@
# Restore In-Repo Nginx Design
**Goal:** Restore the repository-managed Nginx entrypoint on `dev` by writing back the earlier removal diff, so frontend static hosting and backend API proxying return to a single same-origin entry.
**Decisions**
- Restore `nginx/nginx.conf` and `nginx/Dockerfile` from the pre-removal topology.
- Replace the `frontend` runtime service in `docker-compose.yaml` with an `nginx` service that serves the built SPA and proxies `/api` and `/health` to `backend`.
- Remove the Caddy-specific runtime file because the repository will no longer use a separate frontend web server.
- Keep later non-nginx fixes that remain valid, especially the frontend API base URL fallback logic for optional local direct access.
**Architecture**
- `db` remains unchanged.
- `backend` remains unchanged and is reachable internally on `backend:8000`.
- `nginx` becomes the public entrypoint again, serving the frontend bundle and reverse proxying API traffic to `backend`.
- The browser returns to same-origin access through the Nginx entrypoint.
**Operational Notes**
- This is an in-place restoration based on the previous removal footprint, not a fresh redesign.
- The current Tencent Cloud/private registry removal remains intact and is not being reintroduced.
-5
View File
@@ -1,5 +0,0 @@
:4173
root * /srv
try_files {path} /index.html
file_server
+3 -7
View File
@@ -2,18 +2,14 @@ FROM node:20-alpine AS build
WORKDIR /app
ARG VITE_API_BASE_URL
ENV VITE_API_BASE_URL=${VITE_API_BASE_URL}
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM caddy:2-alpine
FROM alpine:3.21
COPY Caddyfile /etc/caddy/Caddyfile
COPY --from=build /app/dist /srv
WORKDIR /opt/frontend
EXPOSE 4173
COPY --from=build /app/dist ./dist
+14
View File
@@ -0,0 +1,14 @@
FROM node:20-alpine AS frontend-build
WORKDIR /app
COPY frontend/package*.json ./
RUN npm ci
COPY frontend/ ./
RUN npm run build
FROM nginx:1.27-alpine
COPY nginx/nginx.conf /etc/nginx/nginx.conf
COPY --from=frontend-build /app/dist /usr/share/nginx/html
+65
View File
@@ -0,0 +1,65 @@
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
resolver 127.0.0.11 valid=10s ipv6=off;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
root /usr/share/nginx/html;
index index.html;
upstream backend {
zone backend 64k;
server backend:8000 resolve;
}
server {
listen 80;
server_name _;
client_max_body_size 20m;
location = /favicon.ico {
root /usr/share/nginx/html;
try_files /favicon.ico =204;
access_log off;
log_not_found off;
expires 1d;
add_header Cache-Control "public, max-age=86400" always;
}
location /api/ {
proxy_pass http://backend;
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 /health {
proxy_pass http://backend;
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 / {
try_files $uri $uri/ /index.html;
}
}
}