diff --git a/.env.example b/.env.example index c71ab8d..d767be0 100644 --- a/.env.example +++ b/.env.example @@ -1,27 +1,10 @@ -# ========== 后端(Go)========== -# 服务端口 PORT=8080 -# Gin 模式:debug / release -GIN_MODE=debug -# SQLite 数据库路径(相对 backend 工作目录,或写绝对路径) +JWT_SECRET=your_very_secure_jwt_secret_here_change_me_in_production DB_PATH=data/app.db -# JWT 密钥(生产务必更换) -JWT_SECRET=affiliate-dash-dev-secret-change-me - -# 皮肤源头开放接口鉴权 -# X-Api-Key 标识(可给对接方) +MODE=release OPEN_API_KEY=sk_source_dev_key_change_me -# HMAC 签名密钥(仅服务端与对接方本地使用,不要放前端) OPEN_API_SECRET=sk_source_dev_secret_change_me -# 签名时间戳允许偏差(秒) OPEN_SIGN_SKEW=300 -# 开放接口详细调试日志:1 开启 / 0 关闭(默认 GIN_MODE=debug 时开启) -OPEN_API_DEBUG=1 -# 日志文件(相对 backend 工作目录);非空则控制台 + 文件双写,留空则仅控制台 +OPEN_API_DEBUG=false LOG_FILE=logs/app.log - -# ========== 前端(Vite / 一键启动)========== -# 前端开发端口 -FRONTEND_PORT=5173 -# 开发代理到后端地址(可选,默认 http://localhost:8080) -VITE_API_PROXY_TARGET=http://localhost:8080 +# For Caddy production, no need for frontend env since built static \ No newline at end of file diff --git a/Caddyfile b/Caddyfile new file mode 100644 index 0000000..a999cb3 --- /dev/null +++ b/Caddyfile @@ -0,0 +1,14 @@ +{ + # admin off # disable admin if wanted +} + +skin.khhao.com { + # Reverse proxy all /api* requests to the backend service + reverse_proxy /api* backend:8080 + + # Serve static files for the frontend (SPA) + file_server / { + root * /usr/share/caddy + try_files {path} {path}/index.html + } +} \ No newline at end of file diff --git a/Dockerfile.backend b/Dockerfile.backend new file mode 100644 index 0000000..bf1f9a6 --- /dev/null +++ b/Dockerfile.backend @@ -0,0 +1,27 @@ +FROM golang:1.26-alpine AS builder + +WORKDIR /app + +# Copy Go files +COPY backend/go.mod backend/go.sum ./ +RUN go mod download + +COPY backend ./backend +WORKDIR /app/backend + +# Build the Go binary +RUN CGO_ENABLED=0 GOOS=linux go build -o /server ./cmd/server + +# Final stage +FROM alpine:latest + +RUN apk --no-cache add ca-certificates tzdata + +WORKDIR /app + +COPY --from=builder /server ./server +# Expose port +EXPOSE 8080 + +# Run the server +CMD ["./server"] \ No newline at end of file diff --git a/Makefile b/Makefile index dd10411..bd69ecb 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: start dev backend frontend install stop +.PHONY: start dev backend frontend install stop docker-build docker-up docker-down # 一键启动前后端(推荐) start dev: @@ -19,3 +19,22 @@ stop: @-lsof -tiTCP:8080 -sTCP:LISTEN | xargs kill 2>/dev/null || true @-lsof -tiTCP:5173 -sTCP:LISTEN | xargs kill 2>/dev/null || true @echo "已尝试停止 8080 / 5173 端口服务" + +# Docker deployment targets +docker-build: + @echo "Building backend Docker image..." + docker build -f Dockerfile.backend -t affiliate-backend:latest . + @echo "Frontend must be built separately: cd frontend && npm run build" + @echo "Then run: docker compose up -d --build" + +docker-up: + @echo "Starting services with docker-compose..." + docker compose up -d --build + +docker-down: + @echo "Stopping and removing containers..." + docker compose down + +docker-logs: + @echo "Showing backend and caddy logs..." + docker compose logs -f backend caddy \ No newline at end of file diff --git a/backend/internal/router/router.go b/backend/internal/router/router.go index 04726a8..0fd6898 100644 --- a/backend/internal/router/router.go +++ b/backend/internal/router/router.go @@ -27,7 +27,7 @@ func Setup(h *Handlers) *gin.Engine { r := gin.Default() r.Use(cors.New(cors.Config{ - AllowOrigins: []string{"http://localhost:5173", "http://127.0.0.1:5173"}, + AllowOrigins: []string{"*"}, AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"}, AllowHeaders: []string{"Origin", "Content-Type", "Authorization", "X-Api-Key", "X-Timestamp", "X-Nonce", "X-Sign"}, ExposeHeaders: []string{"Content-Length"}, diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..01aab09 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,43 @@ +version: '3.8' + +services: + backend: + build: + context: . + dockerfile: Dockerfile.backend + ports: + - "8080:8080" + environment: + - PORT=8080 + - JWT_SECRET=${JWT_SECRET} + - DB_PATH=/data/app.db + - MODE=release + - OPEN_API_KEY=${OPEN_API_KEY} + - OPEN_API_SECRET=${OPEN_API_SECRET} + - OPEN_SIGN_SKEW=${OPEN_SIGN_SKEW:-300} + - OPEN_API_DEBUG=${OPEN_API_DEBUG:-false} + - LOG_FILE=/data/app.log + volumes: + - backend-data:/data + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8080/health"] + interval: 30s + timeout: 10s + retries: 3 + + caddy: + image: caddy:2 + ports: + - "80:80" + - "443:443" + volumes: + - ./Caddyfile:/etc/caddy/Caddyfile + - ./frontend/dist:/usr/share/caddy + command: caddy run --config /etc/caddy/Caddyfile --adapter caddyfile + depends_on: + - backend + restart: unless-stopped + +volumes: + backend-data: \ No newline at end of file