返回笔记首页

完整部署指南

主题配置

部署概览

本项目支持多种部署方式:

  1. Vercel 部署(推荐,最简单)
  2. Docker 部署(适合自托管)
  3. 传统服务器部署(适合企业)

方案一:Vercel 部署(推荐)

为什么选择 Vercel?

  • ✅ 免费额度充足(100GB 流量/月)
  • ✅ 自动 HTTPS 和 CDN
  • ✅ 与 Next.js 完美集成
  • ✅ Git 提交自动部署
  • ✅ 零配置,开箱即用

部署步骤

1. 准备工作

bash
# 确保代码已提交到 Git
git add .
git commit -m "Ready for deployment"
git push origin main

2. 连接 Vercel

方式 A:通过 Vercel CLI(推荐)
bash
# 安装 Vercel CLI
npm i -g vercel

# 登录
vercel login

# 部署
vercel

# 按提示操作:
# ? Set up and deploy "~/ai-content-studio"? [Y/n] y
# ? Which scope do you want to deploy to? Your Name
# ? Link to existing project? [y/N] n
# ? What's your project's name? ai-content-studio
# ? In which directory is your code located? ./
方式 B:通过 Vercel Dashboard
  1. 访问 https://vercel.com/new
  2. 导入 GitHub 仓库
  3. 配置项目名称
  4. 点击 Deploy

3. 配置环境变量

在 Vercel Dashboard 中设置环境变量:

plain
Settings → Environment Variables

必需的环境变量

bash
# AI 服务
AI_PROVIDER=deepseek
DEEPSEEK_API_KEY=sk-xxxxxxxxxxxxxxxx
DEEPSEEK_BASE_URL=https://api.deepseek.com

# OpenAI(备用)
OPENAI_API_KEY=sk-proj-xxxxxxxxxxxxxxxx

# Supabase
NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGc...
SUPABASE_SERVICE_ROLE_KEY=eyJhbGc...

# 应用配置
NEXT_PUBLIC_APP_URL=https://your-app.vercel.app
NODE_ENV=production

重要提示

  • NEXT_PUBLIC_ 开头的变量会暴露到前端
  • 不要在前端使用 SERVICE_ROLE_KEY
  • 设置后需要重新部署才能生效

4. 自定义域名(可选)

plain
Settings → Domains → Add Domain

输入你的域名(例如:my-ai-app.com),按照提示配置 DNS:

plain
Type: CNAME
Name: @
Value: cname.vercel-dns.com

等待 DNS 生效(通常 10-30 分钟),然后访问你的域名!

5. 验证部署

访问部署的 URL,检查:

  • ✅ 页面正常显示
  • ✅ 可以登录注册
  • ✅ AI 生成功能正常
  • ✅ 数据能够保存

6. 自动部署配置

Vercel 默认会监听 Git 仓库:

  • main 分支推送 → 自动部署到生产环境
  • 其他分支推送 → 自动部署到预览环境

自定义部署分支

plain
Settings → Git → Production Branch

方案二:Docker 部署

Dockerfile

创建 Dockerfile

dockerfile
# ==================== 构建阶段 ====================
FROM node:18-alpine AS builder

# 设置工作目录
WORKDIR /app

# 复制 package 文件
COPY package*.json ./

# 安装依赖
RUN npm ci --only=production

# 复制源代码
COPY . .

# 构建应用
RUN npm run build

# ==================== 运行阶段 ====================
FROM node:18-alpine AS runner

# 设置工作目录
WORKDIR /app

# 设置环境变量
ENV NODE_ENV=production

# 创建非 root 用户
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

# 复制必要文件
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static

# 更改文件所有者
RUN chown -R nextjs:nodejs /app

# 切换到非 root 用户
USER nextjs

# 暴露端口
EXPOSE 3000

# 启动命令
CMD ["node", "server.js"]

docker-compose.yml

yaml
version: '3.8'

services:
  # Next.js 应用
  app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      # AI 配置
      - AI_PROVIDER=deepseek
      - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY}
      - DEEPSEEK_BASE_URL=https://api.deepseek.com

      # Supabase 配置
      - NEXT_PUBLIC_SUPABASE_URL=${SUPABASE_URL}
      - NEXT_PUBLIC_SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY}
      - SUPABASE_SERVICE_ROLE_KEY=${SUPABASE_SERVICE_KEY}

      # 应用配置
      - NEXT_PUBLIC_APP_URL=http://localhost:3000
      - NODE_ENV=production
    restart: unless-stopped
    networks:
      - app-network

  # Nginx 反向代理(可选)
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/nginx/ssl:ro
    depends_on:
      - app
    restart: unless-stopped
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

部署步骤

bash
# 1. 创建 .env 文件
cat > .env << 'EOF'
DEEPSEEK_API_KEY=sk-xxxxxxxx
SUPABASE_URL=https://xxxxx.supabase.co
SUPABASE_ANON_KEY=eyJhbGc...
SUPABASE_SERVICE_KEY=eyJhbGc...
EOF

# 2. 构建镜像
docker-compose build

# 3. 启动服务
docker-compose up -d

# 4. 查看日志
docker-compose logs -f

# 5. 停止服务
docker-compose down

Nginx 配置(可选)

nginx
# nginx.conf

events {
    worker_connections 1024;
}

http {
    upstream app {
        server app:3000;
    }

    server {
        listen 80;
        server_name your-domain.com;

        # 重定向到 HTTPS
        return 301 https://$server_name$request_uri;
    }

    server {
        listen 443 ssl http2;
        server_name your-domain.com;

        # SSL 证书
        ssl_certificate /etc/nginx/ssl/cert.pem;
        ssl_certificate_key /etc/nginx/ssl/key.pem;

        # SSL 配置
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5;

        # 反向代理
        location / {
            proxy_pass http://app;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
            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 /_next/static {
            proxy_pass http://app;
            add_header Cache-Control "public, max-age=31536000, immutable";
        }
    }
}

方案三:传统服务器部署

系统要求

  • Ubuntu 20.04+ / CentOS 7+
  • Node.js 18+
  • Nginx
  • PM2(进程管理)

部署步骤

1. 服务器准备

bash
# 更新系统
sudo apt update && sudo apt upgrade -y

# 安装 Node.js 18
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt install -y nodejs

# 安装 Nginx
sudo apt install -y nginx

# 安装 PM2
sudo npm install -g pm2

2. 上传代码

bash
# 在本地打包
npm run build
tar -czf dist.tar.gz .next public package.json package-lock.json

# 上传到服务器
scp dist.tar.gz user@your-server:/var/www/ai-studio/

# 在服务器上解压
ssh user@your-server
cd /var/www/ai-studio
tar -xzf dist.tar.gz
npm ci --only=production

3. 配置环境变量

bash
# 创建 .env.local
cat > .env.local << 'EOF'
AI_PROVIDER=deepseek
DEEPSEEK_API_KEY=sk-xxxxxxxx
DEEPSEEK_BASE_URL=https://api.deepseek.com

NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGc...
SUPABASE_SERVICE_ROLE_KEY=eyJhbGc...

NEXT_PUBLIC_APP_URL=https://your-domain.com
NODE_ENV=production
EOF

# 设置权限
chmod 600 .env.local

4. PM2 配置

创建 ecosystem.config.js

javascript
module.exports = {
  apps: [{
    name: 'ai-content-studio',
    script: 'node_modules/next/dist/bin/next',
    args: 'start',
    cwd: '/var/www/ai-studio',
    instances: 'max',          // 使用所有 CPU 核心
    exec_mode: 'cluster',      // 集群模式
    env: {
      NODE_ENV: 'production',
      PORT: 3000,
    },
    error_file: '/var/log/ai-studio/error.log',
    out_file: '/var/log/ai-studio/out.log',
    log_date_format: 'YYYY-MM-DD HH:mm:ss',
    merge_logs: true,
    autorestart: true,
    max_memory_restart: '1G',  // 内存超过 1G 自动重启
    watch: false,
  }],
};

5. 启动应用

bash
# 创建日志目录
sudo mkdir -p /var/log/ai-studio
sudo chown $USER:$USER /var/log/ai-studio

# 启动应用
pm2 start ecosystem.config.js

# 查看状态
pm2 status

# 查看日志
pm2 logs

# 设置开机自启
pm2 startup
pm2 save

6. Nginx 配置

bash
# 创建配置文件
sudo nano /etc/nginx/sites-available/ai-studio

# 添加配置
server {
    listen 80;
    server_name your-domain.com;

    # 反向代理到 Next.js
    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

# 启用站点
sudo ln -s /etc/nginx/sites-available/ai-studio /etc/nginx/sites-enabled/

# 测试配置
sudo nginx -t

# 重启 Nginx
sudo systemctl restart nginx

7. SSL 证书(Let's Encrypt)

bash
# 安装 Certbot
sudo apt install -y certbot python3-certbot-nginx

# 获取证书
sudo certbot --nginx -d your-domain.com

# 自动续期
sudo certbot renew --dry-run

性能优化

1. Next.js 配置优化

javascript
// next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
  // 生产环境优化
  compress: true,                    // 启用 gzip 压缩
  poweredByHeader: false,            // 移除 X-Powered-By header
  reactStrictMode: true,             // 严格模式

  // 输出优化
  output: 'standalone',              // 独立输出,减小部署体积

  // 图片优化
  images: {
    formats: ['image/avif', 'image/webp'], // 使用现代格式
    minimumCacheTTL: 60,             // 缓存时间
  },

  // 实验性功能
  experimental: {
    optimizeCss: true,               // CSS 优化
    optimizePackageImports: ['antd'], // 包导入优化
  },
};

module.exports = nextConfig;

2. 数据库连接池

typescript
// src/lib/db/supabase.ts

import { createClient } from '@supabase/supabase-js';

// 创建单例客户端
let supabaseInstance: ReturnType<typeof createClient> | null = null;

export function getSupabaseClient() {
  if (!supabaseInstance) {
    supabaseInstance = createClient(
      process.env.NEXT_PUBLIC_SUPABASE_URL!,
      process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
      {
        auth: {
          persistSession: false,     // 服务端不需要持久化
        },
        db: {
          schema: 'public',
        },
        global: {
          headers: {
            'x-application-name': 'ai-content-studio',
          },
        },
      }
    );
  }
  return supabaseInstance;
}

3. Redis 缓存(可选)

typescript
// src/lib/cache/redis.ts

import Redis from 'ioredis';

const redis = new Redis({
  host: process.env.REDIS_HOST || 'localhost',
  port: parseInt(process.env.REDIS_PORT || '6379'),
  password: process.env.REDIS_PASSWORD,
  retryStrategy(times) {
    return Math.min(times * 50, 2000);
  },
});

export async function getCached<T>(
  key: string,
  fetcher: () => Promise<T>,
  ttl: number = 3600
): Promise<T> {
  // 尝试从缓存获取
  const cached = await redis.get(key);
  if (cached) {
    return JSON.parse(cached);
  }

  // 缓存未命中,调用 fetcher
  const data = await fetcher();

  // 存入缓存
  await redis.setex(key, ttl, JSON.stringify(data));

  return data;
}

监控和日志

1. Vercel Analytics

typescript
// src/app/layout.tsx

import { Analytics } from '@vercel/analytics/react';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <Analytics />
      </body>
    </html>
  );
}

2. Sentry 错误追踪

bash
# 安装 Sentry
npm install @sentry/nextjs
typescript
// sentry.client.config.ts

import * as Sentry from '@sentry/nextjs';

Sentry.init({
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
  environment: process.env.NODE_ENV,
  tracesSampleRate: 1.0,
});

3. 自定义日志

typescript
// src/lib/logger.ts

import winston from 'winston';

const logger = winston.createLogger({
  level: process.env.LOG_LEVEL || 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.json()
  ),
  transports: [
    new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
    new winston.transports.File({ filename: 'logs/combined.log' }),
  ],
});

if (process.env.NODE_ENV !== 'production') {
  logger.add(new winston.transports.Console({
    format: winston.format.simple(),
  }));
}

export default logger;

常见问题

Q1: 部署后 API 调用失败

可能原因

  • 环境变量未设置
  • API Key 错误
  • 网络限制

解决方案

bash
# 检查环境变量
vercel env ls

# 查看日志
vercel logs

# 本地测试
vercel dev

Q2: 数据库连接失败

可能原因

  • Supabase URL 或 Key 错误
  • RLS 策略配置问题

解决方案

typescript
// 测试连接
const { data, error } = await supabase
  .from('projects')
  .select('count')
  .single();

console.log('连接测试:', { data, error });

Q3: 构建失败

可能原因

  • 依赖版本冲突
  • TypeScript 类型错误

解决方案

bash
# 清理缓存
rm -rf .next node_modules
npm install
npm run build

# 查看详细错误
npm run build -- --debug

部署检查清单

部署前

  • 所有测试通过
  • 生产环境配置完成
  • 环境变量已设置
  • 数据库迁移完成
  • API Keys 已获取

部署后

  • 网站可以正常访问
  • 用户可以注册登录
  • AI 功能正常工作
  • 数据可以正常保存
  • 错误日志正常记录
  • 性能指标在合理范围
  • SSL 证书有效

面试要点

部署经验讲解

简短版

plain
"我使用 Vercel 部署项目,因为它与 Next.js 集成得最好。
配置环境变量后,git push 就自动部署,非常方便。
同时我也准备了 Docker 方案,方便自托管。"

详细版

plain
"我支持多种部署方式:

1. Vercel(生产环境):
   - 自动 CI/CD
   - 全球 CDN
   - 零配置 HTTPS

2. Docker(自托管):
   - 多阶段构建减小镜像
   - 使用 docker-compose 管理
   - Nginx 做反向代理

3. PM2(传统服务器):
   - 集群模式利用多核
   - 自动重启保证可用性
   - 日志管理方便调试

还做了性能优化:
- 启用 standalone 输出
- 配置图片优化
- 使用 Redis 缓存
- 集成监控和日志

恭喜!部署完成