环境变量配置#

环境变量列表#

后端环境变量#

变量名说明默认值必需
DB_HOST数据库主机localhost
DB_PORT数据库端口5432
DB_NAME数据库名称waterball_academy
DB_USERNAME数据库用户名postgres
DB_PASSWORD数据库密码postgres
JWT_SECRETJWT 签名密钥(>=32字符)-
CORS_ORIGINS允许的跨域来源http://localhost:3000
SERVER_PORT服务器端口8080
GOOGLE_CLIENT_IDGoogle OAuth Client ID-
GOOGLE_CLIENT_SECRETGoogle OAuth Secret-

前端环境变量#

变量名说明默认值必需
NEXT_PUBLIC_API_URL后端 API 地址http://localhost:8080
NEXT_PUBLIC_GOOGLE_CLIENT_IDGoogle OAuth Client ID-

配置文件#

开发环境(docker-compose.yml)#

version: '3.8'

services:
  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: waterball_academy
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

  backend:
    build: ./backend
    ports:
      - "8080:8080"
    environment:
      DB_HOST: postgres
      DB_PORT: 5432
      DB_NAME: waterball_academy
      DB_USERNAME: postgres
      DB_PASSWORD: postgres
      JWT_SECRET: "your-dev-jwt-secret-min-32-chars"
      CORS_ORIGINS: "http://localhost:3000,http://localhost:3001"
      GOOGLE_CLIENT_ID: "${GOOGLE_CLIENT_ID:-}"
      GOOGLE_CLIENT_SECRET: "${GOOGLE_CLIENT_SECRET:-}"
    depends_on:
      - postgres

  frontend:
    build: ./frontend
    ports:
      - "3001:3000"
    environment:
      NEXT_PUBLIC_API_URL: http://localhost:8080
      NEXT_PUBLIC_GOOGLE_CLIENT_ID: "${GOOGLE_CLIENT_ID:-}"
    depends_on:
      - backend

volumes:
  postgres_data:

生产环境(docker-compose.prod.yml)#

version: '3.8'

services:
  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: ${DB_NAME}
      POSTGRES_USER: ${DB_USERNAME}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped

  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile.prod
    ports:
      - "8080:8080"
    environment:
      DB_HOST: postgres
      DB_PORT: 5432
      DB_NAME: ${DB_NAME}
      DB_USERNAME: ${DB_USERNAME}
      DB_PASSWORD: ${DB_PASSWORD}
      JWT_SECRET: ${JWT_SECRET}
      CORS_ORIGINS: ${CORS_ORIGINS}
      GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID}
      GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET}
    depends_on:
      - postgres
    restart: unless-stopped

  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile.prod
      args:
        NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL}
        NEXT_PUBLIC_GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID}
    ports:
      - "3001:3000"
    depends_on:
      - backend
    restart: unless-stopped

volumes:
  postgres_data:

.env 文件(生产环境)#

# .env - 不要提交到 Git!

# 数据库配置
DB_NAME=waterball_academy
DB_USERNAME=postgres
DB_PASSWORD=your_secure_password_here

# JWT 配置(必须 >= 32 字符)
JWT_SECRET=your_very_long_and_secure_secret_key_at_least_32_characters

# CORS 配置(多个域名用逗号分隔)
CORS_ORIGINS=https://waterball.yorukaru.com,https://www.waterball.yorukaru.com

# 前端 API URL
NEXT_PUBLIC_API_URL=https://waterball.yorukaru.com

# Google OAuth(可选)
GOOGLE_CLIENT_ID=656680013665-xxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxxxxxxxxxxxxxxxxxx

本地开发配置#

后端(application.properties)#

# Database
spring.datasource.url=jdbc:postgresql://${DB_HOST:localhost}:${DB_PORT:5432}/${DB_NAME:waterball_academy}
spring.datasource.username=${DB_USERNAME:postgres}
spring.datasource.password=${DB_PASSWORD:postgres}

# JPA/Hibernate
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

# JWT
jwt.secret=${JWT_SECRET}
jwt.expiration=86400000

# CORS
cors.allowed.origins=${CORS_ORIGINS:http://localhost:3000,http://localhost:3001}

# Google OAuth
google.client.id=${GOOGLE_CLIENT_ID:}
google.client.secret=${GOOGLE_CLIENT_SECRET:}

# Server
server.port=${SERVER_PORT:8080}

前端(.env.local)#

# .env.local - 开发环境

NEXT_PUBLIC_API_URL=http://localhost:8080
NEXT_PUBLIC_GOOGLE_CLIENT_ID=your_google_client_id

安全最佳实践#

1. 敏感信息管理#

推荐做法:

# 使用 .env 文件
echo "JWT_SECRET=$(openssl rand -base64 32)" >> .env

# 使用密钥管理服务
# - AWS Secrets Manager
# - Google Secret Manager
# - HashiCorp Vault

禁止做法:

# 不要硬编码在代码中
JWT_SECRET=hardcoded_secret  # ❌

# 不要提交到 Git
git add .env  # ❌

2. .gitignore 配置#

# 环境变量
.env
.env.local
.env.production
.env.development

# 敏感配置
application-secrets.properties

3. JWT Secret 生成#

# 方法 1: OpenSSL
openssl rand -base64 32

# 方法 2: Python
python3 -c "import secrets; print(secrets.token_urlsafe(32))"

# 方法 3: Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"

4. 环境隔离#

开发环境:
  - JWT_SECRET: 简单密钥(开发用)
  - CORS_ORIGINS: localhost
  - DB_PASSWORD: 简单密码

生产环境:
  - JWT_SECRET: 强随机密钥
  - CORS_ORIGINS: 实际域名
  - DB_PASSWORD: 复杂密码

Google OAuth 配置#

1. 创建 OAuth 2.0 凭据#

  1. 访问 Google Cloud Console
  2. 创建项目
  3. 启用 Google+ API
  4. 创建 OAuth 2.0 客户端 ID

授权重定向 URI:

http://localhost:3001              # 开发环境
https://waterball.yorukaru.com    # 生产环境

2. 获取凭据#

复制以下信息到 .env:

  • Client ID
  • Client Secret

3. 测试配置#

# 检查环境变量
echo $GOOGLE_CLIENT_ID
echo $GOOGLE_CLIENT_SECRET

# 启动应用测试 OAuth 登录
docker-compose up

故障排查#

环境变量未生效#

检查步骤:

# 1. 查看容器环境变量
docker-compose exec backend env | grep JWT_SECRET

# 2. 重启容器
docker-compose down
docker-compose up -d

# 3. 检查 .env 文件编码(应为 UTF-8)
file -i .env

JWT Secret 太短#

错误信息:

The specified key byte array is 128 bits which is not secure enough

解决:

# 确保 >= 32 字符
JWT_SECRET=$(openssl rand -base64 32)

CORS 错误#

检查 CORS_ORIGINS:

# 正确格式(无空格)
CORS_ORIGINS=http://localhost:3000,http://localhost:3001

# 错误格式
CORS_ORIGINS=http://localhost:3000, http://localhost:3001  # ❌ 有空格

CI/CD 集成#

GitHub Actions 示例#

name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Set up environment
        run: |
          echo "JWT_SECRET=${{ secrets.JWT_SECRET }}" >> .env
          echo "DB_PASSWORD=${{ secrets.DB_PASSWORD }}" >> .env
          echo "GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }}" >> .env

      - name: Deploy with docker-compose
        run: docker-compose -f docker-compose.prod.yml up -d --build

配置 GitHub Secrets:

  1. Settings → Secrets and variables → Actions
  2. 添加环境变量(JWT_SECRET, DB_PASSWORD 等)