部署指南-1B-单体Docker-自建方案

单体服务 Docker 部署 - 自建方案

方向一 · 方案B:完全自主搭建,不依赖云数据库

适用场景:预算有限、学习目的、完全掌控


一、方案概述

1.1 与阿里云方案的区别

对比项 阿里云方案 自建方案
数据库 云 RDS(托管) 自己 Docker 部署 MySQL
缓存 云 Redis(托管) 自己 Docker 部署 Redis
成本 较高(RDS+Redis费用) 较低(只需 ECS)
运维 云厂商负责数据库运维 自己负责备份、监控
可靠性 高(自动备份、主备切换) 依赖自己的运维能力
适用场景 生产环境、企业项目 测试环境、个人项目、学习

1.2 架构图

复制代码
┌─────────────────────────────────────────────────────────────────────────────────┐
│                        自建单体部署架构                                           │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│   用户访问 https://example.com                                                   │
│              │                                                                  │
│              ▼                                                                  │
│   ┌─────────────────────────────────────────────────────────────────────────┐  │
│   │                         ECS 云服务器(一台搞定)                          │  │
│   │                                                                          │  │
│   │  ┌───────────────────────────────────────────────────────────────────┐  │  │
│   │  │                      Docker 容器网络                               │  │  │
│   │  │                                                                   │  │  │
│   │  │  ┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐        │  │  │
│   │  │  │  Nginx  │ ─▶ │ Backend │ ─▶ │  MySQL  │    │  Redis  │        │  │  │
│   │  │  │  :443   │    │  :8080  │    │  :3306  │    │  :6379  │        │  │  │
│   │  │  │         │    │         │ ─▶ │  (容器) │    │  (容器) │        │  │  │
│   │  │  └─────────┘    └─────────┘    └─────────┘    └─────────┘        │  │  │
│   │  │                                     │              │              │  │  │
│   │  │                                     ▼              ▼              │  │  │
│   │  │                              ┌─────────────────────────────┐     │  │  │
│   │  │                              │    数据持久化(宿主机目录)    │     │  │  │
│   │  │                              │  /home/deploy/mysql/data    │     │  │  │
│   │  │                              │  /home/deploy/redis/data    │     │  │  │
│   │  │                              └─────────────────────────────┘     │  │  │
│   │  │                                                                   │  │  │
│   │  └───────────────────────────────────────────────────────────────────┘  │  │
│   │                                                                          │  │
│   └─────────────────────────────────────────────────────────────────────────┘  │
│                                                                                 │
│   优点:成本低、完全可控、适合学习                                               │
│   缺点:需要自己运维数据库、做好备份                                             │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘

二、服务器准备

(与阿里云方案相同,参考前文)


三、完整 docker-compose.yml

bash 复制代码
# ═══════════════════════════════════════════════════════════════════════════════
# 文件位置:/home/deploy/docker-compose.yml
# 
# 创建命令:
cd /home/deploy
cat > docker-compose.yml << 'EOF'
# ═══════════════════════════════════════════════════════════════════════════════
# Docker Compose 完整配置 - 自建方案(包含 MySQL、Redis)
# 
# 【需要修改的地方】搜索【改】标记
# ═══════════════════════════════════════════════════════════════════════════════

version: '3.8'

services:
  # ═══════════════════════════════════════════════════════════════════════════════
  # Nginx - 反向代理、静态文件、HTTPS
  # ═══════════════════════════════════════════════════════════════════════════════
  nginx:
    image: nginx:1.24-alpine
    container_name: nginx
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
      - ./frontend/dist:/usr/share/nginx/html:ro
      - ./ssl:/etc/nginx/ssl:ro
      - ./nginx/logs:/var/log/nginx
    depends_on:
      - backend
    networks:
      - app-network

  # ═══════════════════════════════════════════════════════════════════════════════
  # Backend - Spring Boot 后端
  # ═══════════════════════════════════════════════════════════════════════════════
  backend:
    image: openjdk:17-jdk-slim
    container_name: backend
    restart: always
    working_dir: /app
    command: java -jar -Xms512m -Xmx1024m -Dspring.profiles.active=prod app.jar
    # ┌─────────────────────────────────────────────────────────────────────────────┐
    # │【改】JVM 内存参数                                                           │
    # │ 2G 服务器:-Xms256m -Xmx512m                                               │
    # │ 4G 服务器:-Xms512m -Xmx1024m                                              │
    # │ 8G 服务器:-Xms1g -Xmx2g                                                   │
    # └─────────────────────────────────────────────────────────────────────────────┘
    volumes:
      - ./backend/app.jar:/app/app.jar:ro
      - ./backend/logs:/app/logs
    environment:
      - TZ=Asia/Shanghai
      # ┌───────────────────────────────────────────────────────────────────────────┐
      # │ 数据库连接配置                                                             │
      # │ • mysql 是 Docker 网络内的服务名,自动解析为 MySQL 容器 IP                  │
      # │ • 3306 是 MySQL 默认端口                                                  │
      # │ • mydb 是数据库名(需要与 MySQL 容器的 MYSQL_DATABASE 一致)               │
      # └───────────────────────────────────────────────────────────────────────────┘
      - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/mydb?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
      - SPRING_DATASOURCE_USERNAME=root
      - SPRING_DATASOURCE_PASSWORD=MyPassword123!
      # ┌───────────────────────────────────────────────────────────────────────────┐
      # │【改】数据库密码,必须与 MySQL 容器的 MYSQL_ROOT_PASSWORD 一致              │
      # └───────────────────────────────────────────────────────────────────────────┘
      - SPRING_REDIS_HOST=redis
      # ┌───────────────────────────────────────────────────────────────────────────┐
      # │ Redis 连接配置                                                            │
      # │ • redis 是 Docker 网络内的服务名                                          │
      # │ • 如果 Redis 设置了密码,加上:SPRING_REDIS_PASSWORD=xxx                   │
      # └───────────────────────────────────────────────────────────────────────────┘
    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_healthy
      # ┌───────────────────────────────────────────────────────────────────────────┐
      # │ depends_on + condition: service_healthy                                   │
      # │ • 等待 MySQL 和 Redis 健康检查通过后再启动 Backend                        │
      # │ • 避免 Backend 启动时数据库还没准备好                                      │
      # └───────────────────────────────────────────────────────────────────────────┘
    networks:
      - app-network

  # ═══════════════════════════════════════════════════════════════════════════════
  # MySQL - 数据库
  # ═══════════════════════════════════════════════════════════════════════════════
  mysql:
    image: mysql:8.0
    # ┌─────────────────────────────────────────────────────────────────────────────┐
    # │ MySQL 镜像选择:                                                            │
    # │ • mysql:8.0       → MySQL 8.0(推荐,性能好)                               │
    # │ • mysql:5.7       → MySQL 5.7(旧项目兼容)                                 │
    # │ • mariadb:10.11   → MariaDB(MySQL 开源分支)                               │
    # └─────────────────────────────────────────────────────────────────────────────┘
    container_name: mysql
    restart: always
    volumes:
      - ./mysql/data:/var/lib/mysql
      - ./mysql/conf:/etc/mysql/conf.d
      - ./mysql/init:/docker-entrypoint-initdb.d
    # ┌─────────────────────────────────────────────────────────────────────────────┐
    # │ 数据卷说明:                                                                │
    # │                                                                             │
    # │ ./mysql/data:/var/lib/mysql                                                │
    # │ → 数据库文件持久化                                                         │
    # │ → 容器删除后数据不丢失                                                      │
    # │ → ⚠️ 首次启动会初始化,需要等几分钟                                         │
    # │                                                                             │
    # │ ./mysql/conf:/etc/mysql/conf.d                                             │
    # │ → 自定义 MySQL 配置文件目录                                                 │
    # │ → 可以放 my.cnf 配置文件                                                   │
    # │                                                                             │
    # │ ./mysql/init:/docker-entrypoint-initdb.d                                   │
    # │ → 初始化脚本目录                                                           │
    # │ → 首次启动时自动执行 .sql 或 .sh 文件                                       │
    # │ → 可以放建表 SQL                                                           │
    # └─────────────────────────────────────────────────────────────────────────────┘
    environment:
      - TZ=Asia/Shanghai
      - MYSQL_ROOT_PASSWORD=MyPassword123!
      # ┌───────────────────────────────────────────────────────────────────────────┐
      # │【改】MYSQL_ROOT_PASSWORD: root 用户密码                                   │
      # │ • 必须设置!                                                              │
      # │ • 建议强密码:大小写字母 + 数字 + 符号                                     │
      # │ • 示例:MyP@ssw0rd!2024                                                  │
      # └───────────────────────────────────────────────────────────────────────────┘
      - MYSQL_DATABASE=mydb
      # ┌───────────────────────────────────────────────────────────────────────────┐
      # │【改】MYSQL_DATABASE: 自动创建的数据库名                                    │
      # │ • 首次启动时自动创建                                                      │
      # │ • 与 Backend 的 SPRING_DATASOURCE_URL 中的数据库名一致                    │
      # └───────────────────────────────────────────────────────────────────────────┘
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
      - --default-authentication-plugin=mysql_native_password
      - --max_connections=500
    # ┌─────────────────────────────────────────────────────────────────────────────┐
    # │ MySQL 启动参数说明:                                                        │
    # │                                                                             │
    # │ --character-set-server=utf8mb4                                             │
    # │ → 默认字符集 utf8mb4                                                       │
    # │ → 支持中文、emoji                                                          │
    # │ → utf8mb4 是真正的 UTF-8(utf8 只支持 3 字节,不支持 emoji)                │
    # │                                                                             │
    # │ --collation-server=utf8mb4_unicode_ci                                      │
    # │ → 排序规则                                                                 │
    # │ → ci = case insensitive(不区分大小写)                                    │
    # │                                                                             │
    # │ --default-authentication-plugin=mysql_native_password                      │
    # │ → 使用旧版认证方式                                                         │
    # │ → 兼容旧版客户端和连接库                                                   │
    # │ → MySQL 8 默认用 caching_sha2_password,某些驱动不支持                      │
    # │                                                                             │
    # │ --max_connections=500                                                      │
    # │ → 最大连接数                                                               │
    # │ → 默认 151,生产环境可调大                                                 │
    # │                                                                             │
    # │ 其他常用参数:                                                              │
    # │ --innodb_buffer_pool_size=1G  → InnoDB 缓冲池(内存大可调大)               │
    # │ --slow_query_log=1            → 开启慢查询日志                             │
    # │ --long_query_time=2           → 慢查询阈值(秒)                            │
    # └─────────────────────────────────────────────────────────────────────────────┘
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
    # ┌─────────────────────────────────────────────────────────────────────────────┐
    # │ healthcheck: 健康检查配置                                                   │
    # │                                                                             │
    # │ test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]                     │
    # │ → 检查命令:mysqladmin ping                                                │
    # │ → 如果 MySQL 正常运行,返回 "mysqld is alive"                               │
    # │                                                                             │
    # │ interval: 10s                                                              │
    # │ → 每 10 秒检查一次                                                         │
    # │                                                                             │
    # │ timeout: 5s                                                                │
    # │ → 检查超时时间 5 秒                                                        │
    # │                                                                             │
    # │ retries: 5                                                                 │
    # │ → 连续失败 5 次才认为不健康                                                 │
    # │                                                                             │
    # │ start_period: 30s                                                          │
    # │ → 启动后 30 秒内的失败不计入重试                                            │
    # │ → MySQL 初始化需要时间                                                     │
    # └─────────────────────────────────────────────────────────────────────────────┘
    networks:
      - app-network

  # ═══════════════════════════════════════════════════════════════════════════════
  # Redis - 缓存
  # ═══════════════════════════════════════════════════════════════════════════════
  redis:
    image: redis:7-alpine
    # ┌─────────────────────────────────────────────────────────────────────────────┐
    # │ Redis 镜像选择:                                                            │
    # │ • redis:7-alpine  → Redis 7 轻量版(推荐)                                  │
    # │ • redis:7         → Redis 7 完整版                                         │
    # │ • redis:6-alpine  → Redis 6(旧项目)                                      │
    # └─────────────────────────────────────────────────────────────────────────────┘
    container_name: redis
    restart: always
    volumes:
      - ./redis/data:/data
    # ┌─────────────────────────────────────────────────────────────────────────────┐
    # │ ./redis/data:/data                                                         │
    # │ → Redis 数据持久化目录                                                     │
    # │ → 存储 RDB 快照和 AOF 日志                                                 │
    # └─────────────────────────────────────────────────────────────────────────────┘
    command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru
    # ┌─────────────────────────────────────────────────────────────────────────────┐
    # │ Redis 启动参数说明:                                                        │
    # │                                                                             │
    # │ --appendonly yes                                                           │
    # │ → 开启 AOF 持久化                                                          │
    # │ → 每次写操作都记录到日志,数据更安全                                        │
    # │ → 与 RDB 快照配合使用                                                      │
    # │                                                                             │
    # │ --maxmemory 256mb                                                          │
    # │ → 限制最大内存 256MB                                                       │
    # │ →【改】根据服务器内存调整:                                                 │
    # │   2G 服务器:128mb-256mb                                                   │
    # │   4G 服务器:256mb-512mb                                                   │
    # │   8G 服务器:512mb-1gb                                                     │
    # │                                                                             │
    # │ --maxmemory-policy allkeys-lru                                             │
    # │ → 内存满时的淘汰策略                                                       │
    # │ → allkeys-lru:淘汰最近最少使用的 key                                       │
    # │ → 其他策略:                                                               │
    # │   volatile-lru  → 只淘汰有过期时间的 key                                   │
    # │   allkeys-random → 随机淘汰                                                │
    # │   noeviction    → 不淘汰,内存满时拒绝写入                                  │
    # │                                                                             │
    # │ 如果需要密码:                                                              │
    # │ --requirepass YourRedisPassword                                            │
    # │ Backend 也需要配置 SPRING_REDIS_PASSWORD                                   │
    # └─────────────────────────────────────────────────────────────────────────────┘
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
    # ┌─────────────────────────────────────────────────────────────────────────────┐
    # │ 健康检查:redis-cli ping                                                    │
    # │ → 正常返回 "PONG"                                                          │
    # └─────────────────────────────────────────────────────────────────────────────┘
    networks:
      - app-network

networks:
  app-network:
    driver: bridge
EOF

echo "✅ docker-compose.yml 创建完成!"

四、Nginx 配置

4.1 主配置文件

bash 复制代码
# ═══════════════════════════════════════════════════════════════════════════════
# 文件位置:/home/deploy/nginx/nginx.conf
# ═══════════════════════════════════════════════════════════════════════════════

mkdir -p /home/deploy/nginx/conf.d

cat > /home/deploy/nginx/nginx.conf << 'EOF'
# Nginx 主配置文件

user nginx;
# 运行 Nginx 的用户

worker_processes auto;
# 工作进程数,auto 自动等于 CPU 核心数
# 举例:2 核 CPU 就是 2 个工作进程

error_log /var/log/nginx/error.log warn;
# 错误日志路径和级别
# 级别:debug, info, notice, warn, error, crit, alert, emerg

pid /var/run/nginx.pid;
# PID 文件位置

events {
    worker_connections 10240;
    # 每个工作进程的最大连接数
    # 总连接数 = worker_processes × worker_connections
    # 举例:4核 × 10240 = 40960 并发连接
    
    use epoll;
    # Linux 下使用 epoll 事件模型,性能最好
}

http {
    include /etc/nginx/mime.types;
    # 导入 MIME 类型配置
    # 让浏览器正确识别 css、js、图片等文件类型

    default_type application/octet-stream;
    # 默认 MIME 类型

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for" '
                    'rt=$request_time';
    # ┌─────────────────────────────────────────────────────────────────────────┐
    # │ 日志格式说明:                                                          │
    # │ $remote_addr         → 客户端 IP                                       │
    # │ $remote_user         → 认证用户名                                      │
    # │ $time_local          → 访问时间                                        │
    # │ $request             → 请求行(GET /api/xxx HTTP/1.1)                 │
    # │ $status              → HTTP 状态码                                     │
    # │ $body_bytes_sent     → 响应体大小                                      │
    # │ $http_referer        → 来源页面                                        │
    # │ $http_user_agent     → 浏览器标识                                      │
    # │ $http_x_forwarded_for → 代理链 IP                                      │
    # │ $request_time        → 请求处理时间                                    │
    # └─────────────────────────────────────────────────────────────────────────┘

    access_log /var/log/nginx/access.log main;
    # 访问日志

    sendfile on;
    # 零拷贝传输,提高静态文件传输效率

    tcp_nopush on;
    # 优化数据包发送

    tcp_nodelay on;
    # 禁用 Nagle 算法,减少延迟

    keepalive_timeout 65;
    # 长连接超时时间(秒)

    # Gzip 压缩
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_comp_level 6;
    gzip_types text/plain text/css application/json application/javascript 
               text/xml application/xml application/xml+rss text/javascript 
               image/svg+xml;
    # ┌─────────────────────────────────────────────────────────────────────────┐
    # │ Gzip 压缩配置:                                                         │
    # │ gzip on            → 开启压缩                                          │
    # │ gzip_vary on       → 添加 Vary: Accept-Encoding 响应头                 │
    # │ gzip_min_length    → 最小压缩大小,小于 1024 字节不压缩                 │
    # │ gzip_comp_level    → 压缩级别 1-9,6 是性能和压缩率的平衡               │
    # │ gzip_types         → 要压缩的 MIME 类型                                │
    # │                                                                         │
    # │ 效果:减少传输大小,加快加载速度                                        │
    # │ 举例:100KB 的 JS 压缩后可能只有 30KB                                   │
    # └─────────────────────────────────────────────────────────────────────────┘

    # 导入站点配置
    include /etc/nginx/conf.d/*.conf;
}
EOF

4.2 站点配置(HTTPS)

bash 复制代码
# ═══════════════════════════════════════════════════════════════════════════════
# 文件位置:/home/deploy/nginx/conf.d/default.conf
# 
#【改】把所有 example.com 换成你的域名
# ═══════════════════════════════════════════════════════════════════════════════

cat > /home/deploy/nginx/conf.d/default.conf << 'EOF'
# HTTP → HTTPS 重定向
server {
    listen 80;
    server_name example.com www.example.com;
    # 【改】换成你的域名

    # Let's Encrypt 证书验证路径(申请证书时需要)
    location /.well-known/acme-challenge/ {
        root /usr/share/nginx/html;
    }

    # 其他请求重定向到 HTTPS
    location / {
        return 301 https://$server_name$request_uri;
        # 301 永久重定向
        # $server_name 当前域名
        # $request_uri 原始请求路径
    }
}

# HTTPS 配置
server {
    listen 443 ssl http2;
    # 443: HTTPS 端口
    # ssl: 启用 SSL/TLS
    # http2: 启用 HTTP/2 协议(更快)

    server_name example.com www.example.com;
    # 【改】换成你的域名

    # ═══════════════════════════════════════════════════════════════════════════
    # SSL 证书配置
    # ═══════════════════════════════════════════════════════════════════════════
    ssl_certificate /etc/nginx/ssl/example.com.pem;
    ssl_certificate_key /etc/nginx/ssl/example.com.key;
    # 【改】换成你的证书文件名

    ssl_session_timeout 1d;
    # SSL 会话缓存超时时间

    ssl_session_cache shared:SSL:50m;
    # SSL 会话缓存,50MB 可存储约 20 万个会话

    ssl_session_tickets off;
    # 禁用 session tickets(安全考虑)

    ssl_protocols TLSv1.2 TLSv1.3;
    # 只允许 TLS 1.2 和 1.3(安全版本)
    # 不要启用 TLSv1.0/1.1(有安全漏洞)

    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    # 加密套件,优先使用安全性高的

    ssl_prefer_server_ciphers off;
    # 优先使用客户端的加密套件偏好

    # ═══════════════════════════════════════════════════════════════════════════
    # 安全响应头
    # ═══════════════════════════════════════════════════════════════════════════
    add_header X-Frame-Options "SAMEORIGIN" always;
    # 防止点击劫持,只允许同源 iframe 嵌入

    add_header X-Content-Type-Options "nosniff" always;
    # 防止 MIME 类型嗅探攻击

    add_header X-XSS-Protection "1; mode=block" always;
    # 启用 XSS 过滤

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    # HSTS:告诉浏览器只用 HTTPS 访问
    # max-age=31536000:一年内强制 HTTPS
    # includeSubDomains:子域名也强制 HTTPS

    # ═══════════════════════════════════════════════════════════════════════════
    # 请求限制
    # ═══════════════════════════════════════════════════════════════════════════
    client_max_body_size 100M;
    # 最大请求体大小
    # 【改】如果有大文件上传,调大这个值
    # 举例:视频网站设置 1G:client_max_body_size 1G;

    # ═══════════════════════════════════════════════════════════════════════════
    # 前端静态文件
    # ═══════════════════════════════════════════════════════════════════════════
    location / {
        root /usr/share/nginx/html;
        # 静态文件根目录
        # 对应宿主机:/home/deploy/frontend/dist

        index index.html;
        # 默认首页

        try_files $uri $uri/ /index.html;
        # ┌─────────────────────────────────────────────────────────────────────┐
        # │ try_files: 文件查找顺序                                             │
        # │                                                                     │
        # │ $uri      → 先找请求的文件(如 /css/style.css)                     │
        # │ $uri/     → 再找目录(如 /about/)                                  │
        # │ /index.html → 都没有就返回 index.html                               │
        # │                                                                     │
        # │ 作用:支持 Vue/React 的前端路由(History 模式)                      │
        # │ 举例:                                                              │
        # │ 用户访问 /user/123                                                 │
        # │ → 服务器没有 /user/123 这个文件                                    │
        # │ → 返回 index.html                                                  │
        # │ → 前端 JS 根据路由渲染 UserDetail 组件                              │
        # └─────────────────────────────────────────────────────────────────────┘

        # 静态资源缓存
        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
            expires 30d;
            # 缓存 30 天

            add_header Cache-Control "public, immutable";
            # public: 可以被代理缓存
            # immutable: 文件不会变(前端打包带 hash)

            access_log off;
            # 静态资源不记录访问日志,减少日志量
        }
    }

    # ═══════════════════════════════════════════════════════════════════════════
    # API 反向代理
    # ═══════════════════════════════════════════════════════════════════════════
    location /api/ {
        rewrite ^/api/(.*)$ /$1 break;
        # ┌─────────────────────────────────────────────────────────────────────┐
        # │ rewrite: URL 重写                                                   │
        # │                                                                     │
        # │ ^/api/(.*)$  → 匹配 /api/ 开头的请求                                │
        # │ (.*)         → 捕获 /api/ 后面的部分                                │
        # │ /$1          → 重写为捕获的部分                                     │
        # │ break        → 停止后续 rewrite                                    │
        # │                                                                     │
        # │ 举例:                                                              │
        # │ /api/user/list → /user/list                                        │
        # │ /api/order/1   → /order/1                                          │
        # │                                                                     │
        # │ 为什么这样设计:                                                    │
        # │ • 前端统一用 /api 前缀区分 API 请求                                 │
        # │ • 后端不需要 /api 前缀                                              │
        # │ • Nginx 负责去掉前缀                                                │
        # └─────────────────────────────────────────────────────────────────────┘

        proxy_pass http://backend:8080;
        # ┌─────────────────────────────────────────────────────────────────────┐
        # │ proxy_pass: 反向代理目标                                            │
        # │                                                                     │
        # │ backend → Docker 服务名,自动解析为容器 IP                          │
        # │ 8080    → 后端服务端口                                             │
        # │                                                                     │
        # │ 其他写法举例:                                                      │
        # │ http://127.0.0.1:8080  → 本机 8080 端口                            │
        # │ http://10.0.0.10:8080  → 指定 IP                                   │
        # └─────────────────────────────────────────────────────────────────────┘

        proxy_http_version 1.1;
        # 使用 HTTP/1.1 协议代理

        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;
        # ┌─────────────────────────────────────────────────────────────────────┐
        # │ proxy_set_header: 设置转发给后端的请求头                             │
        # │                                                                     │
        # │ Host $host                                                         │
        # │ → 原始域名(example.com)                                          │
        # │ → 后端可以通过 request.getHeader("Host") 获取                      │
        # │                                                                     │
        # │ X-Real-IP $remote_addr                                             │
        # │ → 客户端真实 IP                                                    │
        # │ → 后端可以获取用户真实 IP                                          │
        # │                                                                     │
        # │ X-Forwarded-For $proxy_add_x_forwarded_for                         │
        # │ → 代理链 IP 列表                                                   │
        # │ → 格式:客户端IP, 代理1IP, 代理2IP                                  │
        # │                                                                     │
        # │ X-Forwarded-Proto $scheme                                          │
        # │ → 原始协议(http 或 https)                                        │
        # │ → 后端判断请求是否 HTTPS                                           │
        # └─────────────────────────────────────────────────────────────────────┘

        proxy_set_header Cookie $http_cookie;
        proxy_pass_header Set-Cookie;
        # ┌─────────────────────────────────────────────────────────────────────┐
        # │ Cookie 转发配置:                                                   │
        # │                                                                     │
        # │ proxy_set_header Cookie $http_cookie                               │
        # │ → 把请求中的 Cookie 转发给后端                                     │
        # │                                                                     │
        # │ proxy_pass_header Set-Cookie                                       │
        # │ → 把后端响应的 Set-Cookie 头透传给浏览器                            │
        # │                                                                     │
        # │ 作用:支持后端 Session                                              │
        # └─────────────────────────────────────────────────────────────────────┘

        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
        # 超时配置(秒)
        # connect: 连接后端超时
        # send: 发送请求超时
        # read: 读取响应超时
    }
}
EOF

五、部署步骤

5.1 创建目录结构

bash 复制代码
mkdir -p /home/deploy/{frontend/dist,backend/logs,nginx/conf.d,nginx/logs,mysql/data,mysql/conf,mysql/init,redis/data,ssl}

5.2 上传项目文件

bash 复制代码
# 在你的本地电脑执行

# 1. 前端打包
cd 你的前端项目目录
npm install
npm run build

# 2. 上传前端
scp -r dist/* root@你的服务器IP:/home/deploy/frontend/dist/

# 3. 后端打包
cd 你的后端项目目录
mvn clean package -DskipTests

# 4. 上传后端 JAR
scp target/你的项目.jar root@你的服务器IP:/home/deploy/backend/app.jar

# 5. 上传 SSL 证书
scp example.com.pem root@你的服务器IP:/home/deploy/ssl/
scp example.com.key root@你的服务器IP:/home/deploy/ssl/

5.3 启动服务

bash 复制代码
cd /home/deploy

# 启动
docker compose up -d

# 查看状态
docker compose ps

# 查看日志
docker compose logs -f

六、数据库备份

bash 复制代码
# ═══════════════════════════════════════════════════════════════════════════════
# 创建备份脚本
# 位置:/home/deploy/backup.sh
# ═══════════════════════════════════════════════════════════════════════════════

cat > /home/deploy/backup.sh << 'EOF'
#!/bin/bash

# 配置
BACKUP_DIR="/home/deploy/backups"
DATE=$(date +%Y%m%d_%H%M%S)
KEEP_DAYS=7  # 保留最近 7 天的备份

# 创建备份目录
mkdir -p $BACKUP_DIR

# 备份 MySQL
docker exec mysql mysqldump -uroot -pMyPassword123! --all-databases | gzip > $BACKUP_DIR/mysql_$DATE.sql.gz
# 【改】把 MyPassword123! 换成你的 MySQL 密码

# 删除旧备份
find $BACKUP_DIR -name "mysql_*.sql.gz" -mtime +$KEEP_DAYS -delete

echo "备份完成: $BACKUP_DIR/mysql_$DATE.sql.gz"
EOF

chmod +x /home/deploy/backup.sh

# 添加定时任务(每天凌晨 3 点备份)
echo "0 3 * * * /home/deploy/backup.sh >> /var/log/backup.log 2>&1" >> /etc/crontab

七、常用命令

bash 复制代码
cd /home/deploy

# 服务管理
docker compose up -d              # 启动
docker compose down               # 停止
docker compose restart            # 重启全部
docker compose restart backend    # 重启单个服务

# 日志查看
docker compose logs -f            # 所有日志
docker compose logs -f backend    # 后端日志
docker compose logs --tail=100 backend  # 最近 100 行

# 进入容器
docker exec -it mysql mysql -uroot -p   # 进入 MySQL
docker exec -it redis redis-cli          # 进入 Redis
docker exec -it backend bash             # 进入后端容器

# 更新部署
# 上传新文件后:
docker compose restart backend   # 重启后端
docker compose restart nginx     # 重启前端
相关推荐
Joren的学习记录2 小时前
【Linux运维进阶知识】Nginx负载均衡
linux·运维·nginx
Jtti3 小时前
服务器防御SYN Flood攻击的方法
运维·服务器
2501_941982053 小时前
RPA 的跨平台部署与统一自动化策略
运维·自动化·rpa
b***25113 小时前
电池自动分选机:精密分选保障新能源产业质量核心
运维·自动化·制造
数数科技的数据干货3 小时前
游戏流失分析:一套经实战检验的「流程化操作指南」
大数据·运维·人工智能·游戏
eight *4 小时前
源码部署docker自动化脚本
docker·shell
sayyy4 小时前
【Docker】 安装 mysql8.0
mysql·docker
蒟蒻要翻身4 小时前
在同一局域网内共享打印机设置指南
运维
chem41114 小时前
魔百盒 私有网盘seafile搭建
linux·运维·网络
早睡的叶子4 小时前
VM / IREE 的调度器架构
linux·运维·架构