negiix 更换成 caddy
This commit is contained in:
@@ -14,6 +14,10 @@ REDIS_DB=0
|
|||||||
|
|
||||||
JWT_SECRET=change-me
|
JWT_SECRET=change-me
|
||||||
|
|
||||||
|
# API 限流:默认开启,每个 IP 每分钟 300 次。
|
||||||
|
RATE_LIMIT_ENABLED=true
|
||||||
|
RATE_LIMIT_REQUESTS_PER_MINUTE=300
|
||||||
|
|
||||||
LOG_LEVEL=info
|
LOG_LEVEL=info
|
||||||
LOG_DIR=logs
|
LOG_DIR=logs
|
||||||
LOG_ENABLE_CONSOLE=true
|
LOG_ENABLE_CONSOLE=true
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
APP_ENV=production
|
APP_ENV=production
|
||||||
APP_ADDR=:8080
|
APP_ADDR=:8080
|
||||||
|
|
||||||
|
# Caddy 自动申请和续签 HTTPS 证书使用。
|
||||||
|
CADDY_DOMAIN=hfb.221329.cc.cd
|
||||||
|
CADDY_EMAIL=admin@example.com
|
||||||
|
|
||||||
# MySQL 容器初始化变量,同时供后端 DSN 使用。
|
# MySQL 容器初始化变量,同时供后端 DSN 使用。
|
||||||
MYSQL_ROOT_PASSWORD=change-root-password
|
MYSQL_ROOT_PASSWORD=change-root-password
|
||||||
MYSQL_DATABASE=hfb_sys
|
MYSQL_DATABASE=hfb_sys
|
||||||
@@ -15,6 +19,10 @@ REDIS_DB=0
|
|||||||
|
|
||||||
JWT_SECRET=change-to-a-long-random-secret
|
JWT_SECRET=change-to-a-long-random-secret
|
||||||
|
|
||||||
|
# API 限流:默认开启,每个 IP 每分钟 300 次。
|
||||||
|
RATE_LIMIT_ENABLED=true
|
||||||
|
RATE_LIMIT_REQUESTS_PER_MINUTE=300
|
||||||
|
|
||||||
LOG_LEVEL=info
|
LOG_LEVEL=info
|
||||||
LOG_DIR=/app/logs
|
LOG_DIR=/app/logs
|
||||||
LOG_ENABLE_CONSOLE=true
|
LOG_ENABLE_CONSOLE=true
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ func New(cfg config.Config, deps Dependencies, logger *zap.Logger) *gin.Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
engine := gin.New()
|
engine := gin.New()
|
||||||
|
// 生产环境前置 Caddy,已用实测对端地址覆盖 X-Real-IP,
|
||||||
|
// 直接据此取真实客户端 IP,避免客户端伪造 X-Forwarded-For。
|
||||||
|
engine.TrustedPlatform = "X-Real-IP"
|
||||||
engine.Use(middleware.RequestID())
|
engine.Use(middleware.RequestID())
|
||||||
engine.Use(middleware.RequestLogger(logger))
|
engine.Use(middleware.RequestLogger(logger))
|
||||||
engine.Use(middleware.Recovery(logger))
|
engine.Use(middleware.Recovery(logger))
|
||||||
|
|||||||
+23
-8
@@ -3,10 +3,17 @@
|
|||||||
目标访问地址:
|
目标访问地址:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
http://hfb.221329.cc.cd:7890
|
https://hfb.221329.cc.cd
|
||||||
```
|
```
|
||||||
|
|
||||||
生产部署只暴露宿主机 `7890` 端口,避免和服务器已有的 `80`、`443` 服务冲突。后端、MySQL、Redis、MinIO 均通过 Docker 内网通信。
|
生产部署使用 Caddy 作为公网入口,只暴露宿主机 `80`、`443` 端口。Caddy 会自动申请和续签 HTTPS 证书,并直接托管前端静态资源(前端 `dist` 在构建 Caddy 镜像时打入);后端、MySQL、Redis、MinIO 均通过 Docker 内网通信。
|
||||||
|
|
||||||
|
部署前请确认:
|
||||||
|
|
||||||
|
- 域名 A 记录已解析到服务器公网 IP。
|
||||||
|
- 服务器安全组或防火墙已放行 `80/tcp` 和 `443/tcp`。
|
||||||
|
- 服务器上没有其他服务占用 `80`、`443`。
|
||||||
|
- 国内服务器如需对外访问,请先确认域名备案和云厂商限制。
|
||||||
|
|
||||||
## 1. 准备环境变量
|
## 1. 准备环境变量
|
||||||
|
|
||||||
@@ -17,6 +24,8 @@ cp backend/.env.prod.example backend/.env
|
|||||||
编辑 `backend/.env`,至少替换以下占位值:
|
编辑 `backend/.env`,至少替换以下占位值:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
|
CADDY_DOMAIN
|
||||||
|
CADDY_EMAIL
|
||||||
MYSQL_ROOT_PASSWORD
|
MYSQL_ROOT_PASSWORD
|
||||||
MYSQL_PASSWORD
|
MYSQL_PASSWORD
|
||||||
MYSQL_DSN
|
MYSQL_DSN
|
||||||
@@ -39,9 +48,10 @@ STORAGE_SECRET_ACCESS_KEY
|
|||||||
|
|
||||||
- 检查 `backend/.env` 是否仍指向 `127.0.0.1`、`localhost` 或占位值。
|
- 检查 `backend/.env` 是否仍指向 `127.0.0.1`、`localhost` 或占位值。
|
||||||
- 构建并启动生产容器。
|
- 构建并启动生产容器。
|
||||||
|
- 通过 Caddy 自动申请或续签 HTTPS 证书。
|
||||||
- 等待 MySQL、Redis、MinIO 就绪。
|
- 等待 MySQL、Redis、MinIO 就绪。
|
||||||
- 按顺序执行尚未应用的数据库迁移。
|
- 按顺序执行尚未应用的数据库迁移。
|
||||||
- 重启后端并检查 `http://127.0.0.1:7890/api/health`。
|
- 重启后端并检查 `https://你的域名/api/health`。
|
||||||
|
|
||||||
如需部署完成后直接跟随查看后端日志:
|
如需部署完成后直接跟随查看后端日志:
|
||||||
|
|
||||||
@@ -64,9 +74,14 @@ backend/logs/app-YYYY-MM-DD.log
|
|||||||
## 3. 手动启动服务
|
## 3. 手动启动服务
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
set -a
|
||||||
|
source backend/.env
|
||||||
|
set +a
|
||||||
docker compose -f deploy/docker-compose.prod.yml up -d --build
|
docker compose -f deploy/docker-compose.prod.yml up -d --build
|
||||||
```
|
```
|
||||||
|
|
||||||
|
手动执行 `docker compose` 时需要先导出 `CADDY_DOMAIN` 和 `CADDY_EMAIL`,否则 Caddy 无法读取证书域名配置。优先推荐使用一键部署脚本,它会自动从 `backend/.env` 导出这两个变量。
|
||||||
|
|
||||||
## 4. 手动执行数据库迁移
|
## 4. 手动执行数据库迁移
|
||||||
|
|
||||||
通常直接使用一键部署脚本即可。确实需要手动迁移时,使用后端镜像内置的 goose:
|
通常直接使用一键部署脚本即可。确实需要手动迁移时,使用后端镜像内置的 goose:
|
||||||
@@ -86,15 +101,15 @@ docker compose -f deploy/docker-compose.prod.yml run --rm --no-deps backend \
|
|||||||
## 5. 验证
|
## 5. 验证
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl http://127.0.0.1:7890/health
|
curl https://你的域名/health
|
||||||
curl http://127.0.0.1:7890/api/health
|
curl https://你的域名/api/health
|
||||||
```
|
```
|
||||||
|
|
||||||
浏览器访问:
|
浏览器访问:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
http://hfb.221329.cc.cd:7890
|
https://hfb.221329.cc.cd
|
||||||
http://hfb.221329.cc.cd:7890/admin/login
|
https://hfb.221329.cc.cd/admin/login
|
||||||
```
|
```
|
||||||
|
|
||||||
服务器安全组或防火墙需要放行 `7890/tcp`。
|
Caddy 证书和 ACME 账号数据保存在 Docker 卷 `caddy_data`、`caddy_config` 中。不要随意删除这两个卷,否则 Caddy 会重新申请证书,频繁重建可能触发证书签发频率限制。
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
{
|
||||||
|
email {$CADDY_EMAIL}
|
||||||
|
}
|
||||||
|
|
||||||
|
# 反代到后端时,用 Caddy 实测到的对端地址覆盖 X-Real-IP,
|
||||||
|
# 防止客户端伪造 X-Forwarded-For 影响限流、审计和支付下单的 client_ip。
|
||||||
|
(backend_proxy) {
|
||||||
|
header_up X-Real-IP {remote_host}
|
||||||
|
}
|
||||||
|
|
||||||
|
{$CADDY_DOMAIN} {
|
||||||
|
encode zstd gzip
|
||||||
|
|
||||||
|
header {
|
||||||
|
Strict-Transport-Security "max-age=31536000"
|
||||||
|
X-Content-Type-Options "nosniff"
|
||||||
|
X-Frame-Options "DENY"
|
||||||
|
Referrer-Policy "strict-origin-when-cross-origin"
|
||||||
|
Permissions-Policy "camera=(), microphone=(), geolocation=()"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 聊天 SSE 长连接:关闭缓冲,逐条推送。
|
||||||
|
@api_sse {
|
||||||
|
path /api/chats/events /api/admin/chats/events
|
||||||
|
}
|
||||||
|
|
||||||
|
handle @api_sse {
|
||||||
|
reverse_proxy backend:8080 {
|
||||||
|
flush_interval -1
|
||||||
|
import backend_proxy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handle /api/* {
|
||||||
|
# 后端上传上限 10MB,这里前置拦掉超大请求体(留 1MB 余量)。
|
||||||
|
request_body {
|
||||||
|
max_size 11MB
|
||||||
|
}
|
||||||
|
reverse_proxy backend:8080 {
|
||||||
|
import backend_proxy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handle /health {
|
||||||
|
reverse_proxy backend:8080 {
|
||||||
|
import backend_proxy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# 其余流量返回前端静态资源,未命中的路径交给 SPA 处理。
|
||||||
|
handle {
|
||||||
|
root * /srv/dist
|
||||||
|
try_files {path} /index.html
|
||||||
|
file_server
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# 第一阶段:构建前端静态资源
|
||||||
|
FROM node:24-alpine AS build
|
||||||
|
|
||||||
|
WORKDIR /src
|
||||||
|
COPY frontend/package*.json ./
|
||||||
|
RUN npm install
|
||||||
|
COPY frontend/ .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# 第二阶段:Caddy 作为公网入口,同时托管前端 dist
|
||||||
|
FROM caddy:2.10-alpine
|
||||||
|
|
||||||
|
COPY --from=build /src/dist /srv/dist
|
||||||
|
EXPOSE 80 443
|
||||||
@@ -1,4 +1,31 @@
|
|||||||
services:
|
services:
|
||||||
|
caddy:
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: deploy/caddy/Dockerfile
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
TZ: Asia/Shanghai
|
||||||
|
CADDY_DOMAIN: ${CADDY_DOMAIN:?请先导出 CADDY_DOMAIN,或使用 scripts/deploy-prod.sh 部署}
|
||||||
|
CADDY_EMAIL: ${CADDY_EMAIL:?请先导出 CADDY_EMAIL,或使用 scripts/deploy-prod.sh 部署}
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- ./caddy/Caddyfile:/etc/caddy/Caddyfile:ro
|
||||||
|
- caddy_data:/data
|
||||||
|
- caddy_config:/config
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 256M
|
||||||
|
cpus: '0.5'
|
||||||
|
reservations:
|
||||||
|
memory: 128M
|
||||||
|
cpus: '0.25'
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
|
|
||||||
mysql:
|
mysql:
|
||||||
image: mysql:8.4
|
image: mysql:8.4
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
@@ -95,25 +122,9 @@ services:
|
|||||||
expose:
|
expose:
|
||||||
- "8080"
|
- "8080"
|
||||||
|
|
||||||
frontend:
|
|
||||||
build:
|
|
||||||
context: ..
|
|
||||||
dockerfile: frontend/Dockerfile
|
|
||||||
restart: unless-stopped
|
|
||||||
deploy:
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
memory: 256M
|
|
||||||
cpus: '0.5'
|
|
||||||
reservations:
|
|
||||||
memory: 128M
|
|
||||||
cpus: '0.25'
|
|
||||||
depends_on:
|
|
||||||
- backend
|
|
||||||
ports:
|
|
||||||
- "7890:80"
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
|
caddy_data:
|
||||||
|
caddy_config:
|
||||||
mysql_data:
|
mysql_data:
|
||||||
redis_data:
|
redis_data:
|
||||||
minio_data:
|
minio_data:
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name hfb.221329.cc.cd;
|
|
||||||
|
|
||||||
client_max_body_size 20m;
|
|
||||||
|
|
||||||
root /usr/share/nginx/html;
|
|
||||||
index index.html;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
try_files $uri $uri/ /index.html;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /api/ {
|
|
||||||
proxy_pass http://backend:8080/api/;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_buffering off;
|
|
||||||
proxy_read_timeout 3600s;
|
|
||||||
proxy_set_header Host $http_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 X-Forwarded-Host $http_host;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /health {
|
|
||||||
proxy_pass http://backend:8080/health;
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
FROM node:24-alpine AS build
|
|
||||||
|
|
||||||
WORKDIR /src
|
|
||||||
COPY frontend/package*.json ./
|
|
||||||
RUN npm install
|
|
||||||
COPY frontend/ .
|
|
||||||
RUN npm run build
|
|
||||||
|
|
||||||
FROM nginx:1.29-alpine
|
|
||||||
|
|
||||||
COPY --from=build /src/dist /usr/share/nginx/html
|
|
||||||
COPY deploy/nginx/default.conf /etc/nginx/conf.d/default.conf
|
|
||||||
EXPOSE 80
|
|
||||||
+57
-13
@@ -5,8 +5,8 @@ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|||||||
COMPOSE_FILE="${ROOT_DIR}/deploy/docker-compose.prod.yml"
|
COMPOSE_FILE="${ROOT_DIR}/deploy/docker-compose.prod.yml"
|
||||||
BACKEND_ENV="${ROOT_DIR}/backend/.env"
|
BACKEND_ENV="${ROOT_DIR}/backend/.env"
|
||||||
BACKEND_LOG_DIR="${ROOT_DIR}/backend/logs"
|
BACKEND_LOG_DIR="${ROOT_DIR}/backend/logs"
|
||||||
HEALTH_URL="${PROD_HEALTH_URL:-http://127.0.0.1:7890/api/health}"
|
HEALTH_URL="${PROD_HEALTH_URL:-}"
|
||||||
PUBLIC_URL="${PROD_PUBLIC_URL:-http://hfb.221329.cc.cd:7890}"
|
PUBLIC_URL="${PROD_PUBLIC_URL:-}"
|
||||||
READY_TIMEOUT="${PROD_READY_TIMEOUT:-120}"
|
READY_TIMEOUT="${PROD_READY_TIMEOUT:-120}"
|
||||||
|
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
@@ -66,9 +66,9 @@ show_help() {
|
|||||||
-h, --help 显示帮助信息
|
-h, --help 显示帮助信息
|
||||||
|
|
||||||
环境变量:
|
环境变量:
|
||||||
PROD_HEALTH_URL=http://127.0.0.1:7890/api/health
|
PROD_HEALTH_URL=https://你的域名/api/health
|
||||||
部署后健康检查地址
|
部署后健康检查地址,默认使用 CADDY_DOMAIN
|
||||||
PROD_PUBLIC_URL=http://hfb.221329.cc.cd:7890
|
PROD_PUBLIC_URL=https://你的域名
|
||||||
输出给用户看的访问地址
|
输出给用户看的访问地址
|
||||||
PROD_READY_TIMEOUT=120
|
PROD_READY_TIMEOUT=120
|
||||||
等待服务就绪秒数
|
等待服务就绪秒数
|
||||||
@@ -127,8 +127,10 @@ validate_env() {
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local app_env mysql_dsn redis_addr storage_endpoint
|
local app_env caddy_domain caddy_email mysql_dsn redis_addr storage_endpoint
|
||||||
app_env="$(require_env APP_ENV)"
|
app_env="$(require_env APP_ENV)"
|
||||||
|
caddy_domain="$(require_env CADDY_DOMAIN)"
|
||||||
|
caddy_email="$(require_env CADDY_EMAIL)"
|
||||||
mysql_dsn="$(require_env MYSQL_DSN)"
|
mysql_dsn="$(require_env MYSQL_DSN)"
|
||||||
redis_addr="$(require_env REDIS_ADDR)"
|
redis_addr="$(require_env REDIS_ADDR)"
|
||||||
storage_endpoint="$(require_env STORAGE_ENDPOINT)"
|
storage_endpoint="$(require_env STORAGE_ENDPOINT)"
|
||||||
@@ -146,6 +148,19 @@ validate_env() {
|
|||||||
log_warn "APP_ENV 当前是 ${app_env},生产部署建议改为 production"
|
log_warn "APP_ENV 当前是 ${app_env},生产部署建议改为 production"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ "${caddy_domain}" == http://* || "${caddy_domain}" == https://* || "${caddy_domain}" == */* ]]; then
|
||||||
|
log_error "CADDY_DOMAIN 只填写域名本身,不要包含 http(s):// 或路径,当前值:${caddy_domain}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [[ "${caddy_domain}" == *"127.0.0.1"* || "${caddy_domain}" == *"localhost"* || "${caddy_domain}" != *"."* ]]; then
|
||||||
|
log_error "CADDY_DOMAIN 必须填写可公网解析到本机的正式域名,当前值:${caddy_domain}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [[ "${caddy_email}" == "admin@example.com" || "${caddy_email}" != *"@"* ]]; then
|
||||||
|
log_error "CADDY_EMAIL 需要填写真实邮箱,用于 ACME 证书通知"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ "${mysql_dsn}" == *"127.0.0.1"* || "${mysql_dsn}" == *"localhost"* ]]; then
|
if [[ "${mysql_dsn}" == *"127.0.0.1"* || "${mysql_dsn}" == *"localhost"* ]]; then
|
||||||
log_error "MYSQL_DSN 仍指向本机,请改为 tcp(mysql:3306)"
|
log_error "MYSQL_DSN 仍指向本机,请改为 tcp(mysql:3306)"
|
||||||
exit 1
|
exit 1
|
||||||
@@ -168,6 +183,29 @@ compose() {
|
|||||||
docker compose -f "${COMPOSE_FILE}" "$@"
|
docker compose -f "${COMPOSE_FILE}" "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export_caddy_env() {
|
||||||
|
export CADDY_DOMAIN
|
||||||
|
export CADDY_EMAIL
|
||||||
|
CADDY_DOMAIN="$(require_env CADDY_DOMAIN)"
|
||||||
|
CADDY_EMAIL="$(require_env CADDY_EMAIL)"
|
||||||
|
}
|
||||||
|
|
||||||
|
public_url() {
|
||||||
|
if [[ -n "${PUBLIC_URL}" ]]; then
|
||||||
|
printf "%s" "${PUBLIC_URL}"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
printf "https://%s" "$(require_env CADDY_DOMAIN)"
|
||||||
|
}
|
||||||
|
|
||||||
|
health_url() {
|
||||||
|
if [[ -n "${HEALTH_URL}" ]]; then
|
||||||
|
printf "%s" "${HEALTH_URL}"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
printf "%s/api/health" "$(public_url)"
|
||||||
|
}
|
||||||
|
|
||||||
prepare_log_dir() {
|
prepare_log_dir() {
|
||||||
mkdir -p "${BACKEND_LOG_DIR}"
|
mkdir -p "${BACKEND_LOG_DIR}"
|
||||||
}
|
}
|
||||||
@@ -246,16 +284,18 @@ run_migrations() {
|
|||||||
|
|
||||||
wait_http_ready() {
|
wait_http_ready() {
|
||||||
local attempt
|
local attempt
|
||||||
|
local url
|
||||||
|
url="$(health_url)"
|
||||||
log "等待接口健康检查通过..."
|
log "等待接口健康检查通过..."
|
||||||
for ((attempt = 1; attempt <= READY_TIMEOUT; attempt++)); do
|
for ((attempt = 1; attempt <= READY_TIMEOUT; attempt++)); do
|
||||||
if curl -fsS --max-time 3 "${HEALTH_URL}" >/dev/null 2>&1; then
|
if curl -fsS --max-time 5 "${url}" >/dev/null 2>&1; then
|
||||||
log_success "健康检查通过:${HEALTH_URL}"
|
log_success "健康检查通过:${url}"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
|
|
||||||
log_error "健康检查超时:${HEALTH_URL}"
|
log_error "健康检查超时:${url}"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,6 +304,7 @@ main() {
|
|||||||
need_cmd docker
|
need_cmd docker
|
||||||
need_cmd curl
|
need_cmd curl
|
||||||
validate_env
|
validate_env
|
||||||
|
export_caddy_env
|
||||||
prepare_log_dir
|
prepare_log_dir
|
||||||
|
|
||||||
log "检查 Docker Compose 配置..."
|
log "检查 Docker Compose 配置..."
|
||||||
@@ -276,8 +317,8 @@ main() {
|
|||||||
log "构建后端镜像..."
|
log "构建后端镜像..."
|
||||||
compose build backend
|
compose build backend
|
||||||
|
|
||||||
log "构建前端镜像..."
|
log "构建 Caddy 镜像(含前端静态资源)..."
|
||||||
compose build frontend
|
compose build caddy
|
||||||
|
|
||||||
log "启动生产服务..."
|
log "启动生产服务..."
|
||||||
compose up -d --no-build
|
compose up -d --no-build
|
||||||
@@ -286,16 +327,19 @@ main() {
|
|||||||
wait_service_healthy mysql "MySQL"
|
wait_service_healthy mysql "MySQL"
|
||||||
wait_service_healthy redis "Redis"
|
wait_service_healthy redis "Redis"
|
||||||
wait_service_healthy minio "MinIO"
|
wait_service_healthy minio "MinIO"
|
||||||
|
wait_service_healthy caddy "Caddy"
|
||||||
reset_database
|
reset_database
|
||||||
run_migrations
|
run_migrations
|
||||||
|
|
||||||
log "重启后端以加载最新数据库状态..."
|
log "重启后端以加载最新数据库状态..."
|
||||||
compose up -d --no-deps --force-recreate backend
|
compose up -d --no-deps --force-recreate backend
|
||||||
wait_service_healthy backend "后端"
|
wait_service_healthy backend "后端"
|
||||||
|
compose up -d --no-deps --force-recreate caddy
|
||||||
|
wait_service_healthy caddy "Caddy"
|
||||||
wait_http_ready
|
wait_http_ready
|
||||||
|
|
||||||
log_success "部署完成:${PUBLIC_URL}"
|
log_success "部署完成:$(public_url)"
|
||||||
log "常用命令:docker compose -f deploy/docker-compose.prod.yml logs -f backend"
|
log "常用命令:docker compose -f deploy/docker-compose.prod.yml logs -f caddy backend"
|
||||||
|
|
||||||
if [[ "${FOLLOW_LOGS}" == "1" ]]; then
|
if [[ "${FOLLOW_LOGS}" == "1" ]]; then
|
||||||
compose logs -f backend
|
compose logs -f backend
|
||||||
|
|||||||
Reference in New Issue
Block a user