Skip to content

生产环境部署

注意

本部署指南专门针对 Linux 生产服务器环境。如果需要搭建开发环境,请参考 开发环境搭建

系统要求

操作系统

  • Ubuntu 20.04 LTS 或更高版本(推荐)
  • Debian 11+

服务器配置

  • CPU: 2 核心或更多
  • 内存: 4GB 或更多(推荐 8GB+)
  • 存储: 50GB 或更多可用空间
  • 网络: 公网 IP 和域名

软件要求

域名和 SSL 证书准备

1. 域名配置

在开始部署前,请确保你拥有一个域名并配置以下子域名 DNS 记录:

yourdomain.com          -> 你的服务器 IP
api.yourdomain.com      -> 你的服务器 IP
static.yourdomain.com   -> 你的服务器 IP
admin.yourdomain.com    -> 你的服务器 IP
puzzle.yourdomain.com   -> 你的服务器 IP

2. 申请 SSL 证书

我们强烈推荐使用 Certbot 自动申请和管理 Let's Encrypt 免费 SSL 证书:

安装 Certbot (Ubuntu/Debian):

bash
sudo apt update
sudo apt install certbot python3-certbot-nginx

申请证书:

bash
# 为所有子域名申请证书
sudo certbot --nginx -d yourdomain.com -d api.yourdomain.com -d static.yourdomain.com -d admin.yourdomain.com -d puzzle.yourdomain.com

自动续期

Certbot 会自动设置证书续期任务。可以通过以下命令测试续期:

bash
sudo certbot renew --dry-run

环境准备

1. 更新系统并安装基础软件

bash
# Ubuntu/Debian
sudo apt update -y
sudo apt install -y curl wget git unzip

2. 安装 Node.js

bash
# 安装 fnm (Fast Node Manager)
curl -fsSL https://fnm.vercel.app/install | bash

# 重新加载 shell 环境
source ~/.bashrc

# 安装 Node.js 22.x
fnm install 22
fnm use 22
fnm default 22

# 验证安装
node --version
npm --version

3. 安装 .NET 8.0 Runtime

bash
# Ubuntu 22.04
wget https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
sudo apt-get update
sudo apt-get install -y dotnet-runtime-8.0 aspnetcore-runtime-8.0

# 验证安装
dotnet --version

4. 安装 PM2

bash
sudo npm install -g pm2
pm2 --version

中间件安装配置

1. 安装配置 MariaDB

bash
# 安装 MariaDB
sudo apt install -y mariadb-server

# 启动并设置开机自启
sudo systemctl start mariadb
sudo systemctl enable mariadb

# 安全配置
sudo mysql_secure_installation

创建数据库和用户:

sql
mysql -u root -p

CREATE DATABASE ccxc_prod CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'ccxc_user'@'localhost' IDENTIFIED BY 'your_secure_production_password';
GRANT ALL PRIVILEGES ON ccxc_prod.* TO 'ccxc_user'@'localhost';
GRANT SELECT ON information_schema.* TO 'ccxc_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;

2. 安装配置 Redis

bash
# 安装 Redis
sudo apt install -y redis-server

# 配置 Redis(可选,增强安全性)
sudo nano /etc/redis/redis.conf
# 取消注释并修改以下行:
# bind 127.0.0.1
# requirepass your_redis_password

# 启动并设置开机自启
sudo systemctl start redis-server
sudo systemctl enable redis-server

# 验证
redis-cli ping

3. 安装配置 Nginx

bash
# 安装 Nginx
sudo apt install -y nginx

# 启动并设置开机自启
sudo systemctl start nginx
sudo systemctl enable nginx

# 创建必要目录
sudo mkdir -p /var/www/static
sudo mkdir -p /var/www/ccxc/{admin,website,puzzle}
sudo chown -R www-data:www-data /var/www/

组件部署

1. 部署主后端 (ccxc-backend)

获取并发布项目

bash
# 创建应用目录
sudo mkdir -p /opt/ccxc-backend
cd /opt/ccxc-backend

# 克隆源码
sudo git clone https://github.com/cipherpuzzles/ccxc-backend.git src
cd src

# 发布项目
sudo dotnet publish --configuration Release --runtime linux-x64 --self-contained false --output /opt/ccxc-backend/app

# 设置权限
sudo chown -R www-data:www-data /opt/ccxc-backend
sudo chmod +x /opt/ccxc-backend/app/ccxc-backend

配置文件

编辑配置文件 /opt/ccxc-backend/app/Config/ccxc.config.toml

toml
[Config/CcxcConfig]
HttpPort = "52412"
RedisConnStr = "127.0.0.1:6379"
DbConnStr = "Server=localhost;User=ccxc_user;Database=ccxc_prod;Port=3306;Password=your_secure_production_password;Charset=utf8mb4;ConvertZeroDateTime=True"
DebugMode = "False"
ImageStorage = "/var/www/static/images/"
ImagePrefix = "https://static.yourdomain.com/images/"
PassHashKey1 = "your_random_seed_1_production"
PassHashKey2 = "your_random_seed_2_production"
AESMasterKey = "your_32_character_aes_master_key_prod"
EnableEmailVerify = "True"
AliyunDmAccessKey = "your_production_aliyun_dm_access_key"
AliyunDmAccessSecret = "your_production_aliyun_dm_access_secret"

配置 Systemctl 服务

发布的版本中已包含 ccxc.service 文件,将其复制到系统服务目录:

bash
# 复制服务文件
sudo cp /opt/ccxc-backend/app/ccxc.service /etc/systemd/system/

# 重新加载 systemd 配置
sudo systemctl daemon-reload

# 启用并启动服务
sudo systemctl enable ccxc
sudo systemctl start ccxc

# 检查服务状态
sudo systemctl status ccxc

Systemctl 基本管理命令:

bash
# 启动服务
sudo systemctl start ccxc

# 停止服务
sudo systemctl stop ccxc

# 重启服务
sudo systemctl restart ccxc

# 查看服务状态
sudo systemctl status ccxc

# 查看服务日志
sudo journalctl -u ccxc -f

# 禁用服务(不开机自启)
sudo systemctl disable ccxc

2. 部署消息同步服务器 (ccxc-sync-server)

bash
# 创建应用目录
sudo mkdir -p /opt/ccxc-sync-server
cd /opt/ccxc-sync-server

# 克隆源码
sudo git clone https://github.com/cipherpuzzles/ccxc-sync-server.git .

# 安装依赖
sudo npm install

# 构建项目
sudo npm run build

# 配置文件
sudo cp config.default.json config.json
sudo nano config.json

编辑配置文件 config.json:

json
{
    "redis": {
        "host": "localhost",
        "port": 6379
    },
    "yPersistence": {
        "dir": "/opt/ccxc-sync-server/data"
    },
    "apiRoot": "http://localhost:52412/api/v1"
}

使用 PM2 启动:

bash
# 设置权限
sudo chown -R www-data:www-data /opt/ccxc-sync-server

# 切换到 www-data 用户启动
sudo -u www-data pm2 start dist/app.js --name ccxc-sync-server

# 保存 PM2 配置
sudo -u www-data pm2 save

# 设置 PM2 开机自启
sudo -u www-data pm2 startup
# 按照提示执行返回的命令

PM2 基本管理命令:

bash
# 查看所有进程
sudo -u www-data pm2 list

# 查看日志
sudo -u www-data pm2 logs ccxc-sync-server

# 重启服务
sudo -u www-data pm2 restart ccxc-sync-server

# 停止服务
sudo -u www-data pm2 stop ccxc-sync-server

# 删除服务
sudo -u www-data pm2 delete ccxc-sync-server

3. 部署前端组件

3.1 后台管理面板 (ccxc-admin)

bash
# 创建构建目录
mkdir -p /tmp/ccxc-builds/admin
cd /tmp/ccxc-builds/admin

# 克隆并构建
git clone https://github.com/cipherpuzzles/ccxc-admin.git .
npm install

# 配置生产环境变量
cat > .env.production << EOF
VITE_BACKEND_ROOT=https://api.yourdomain.com/api
EOF

# 构建生产版本
npm run build

# 部署到 Nginx 目录
sudo cp -r dist/* /var/www/ccxc/admin/

3.2 主站前端 (ccxc-website)

bash
# 创建构建目录
mkdir -p /tmp/ccxc-builds/website
cd /tmp/ccxc-builds/website

# 克隆并构建
git clone https://github.com/cipherpuzzles/ccxc-website.git .
npm install

# 配置生产环境变量
cat > .env.production << EOF
VITE_BACKEND_ROOT=https://api.yourdomain.com/api
EOF

# 构建生产版本
npm run build

# 部署到 Nginx 目录
sudo cp -r dist/* /var/www/ccxc/website/

3.3 谜题前端 (ccxc-puzzle)

bash
# 创建构建目录
mkdir -p /tmp/ccxc-builds/puzzle
cd /tmp/ccxc-builds/puzzle

# 克隆并构建
git clone https://github.com/cipherpuzzles/ccxc-puzzle.git .
npm install

# 配置生产环境变量
cat > .env.production << EOF
VITE_API_ROOT=https://api.yourdomain.com/api/v1
VITE_WS_HOST=wss://api.yourdomain.com/ws-api
VITE_WEBSITE_MAIN=https://yourdomain.com
EOF

# 构建生产版本
npm run build

# 部署到 Nginx 目录
sudo cp -r dist/* /var/www/ccxc/puzzle/

Nginx 配置

创建 Nginx 配置文件 /etc/nginx/sites-available/ccxc-production

nginx
# WebSocket 连接升级配置
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

# 后端服务负载均衡
upstream ccxc_backend {
    server 127.0.0.1:52412;
    keepalive 64;
}

upstream ccxc_sync {
    server 127.0.0.1:15562;
    keepalive 64;
}

# API 服务器配置
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name api.yourdomain.com;

    # SSL 证书配置(Certbot 自动配置)
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
    
    # SSL 优化配置
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384;
    ssl_prefer_server_ciphers on;
    ssl_protocols TLSv1.2 TLSv1.3;

    # 安全头
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # WebSocket 代理(同步服务)
    location /ws-api {
        proxy_pass http://ccxc_sync;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        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_connect_timeout 86400;
        proxy_send_timeout 86400;
        proxy_read_timeout 86400;
    }

    # API 代理(主后端)
    location / {
        proxy_pass http://ccxc_backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        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;
        
        # 上传文件大小限制
        client_max_body_size 50M;
    }
}

# 静态文件服务器配置
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name static.yourdomain.com;

    # SSL 证书配置
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    # 静态文件根目录
    root /var/www/static;
    index index.html;

    # 安全头
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;

    # CORS 和缓存配置
    location / {
        # 处理 OPTIONS 预检请求
        if ($request_method = 'OPTIONS') {
            add_header Access-Control-Allow-Origin *;
            add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
            add_header Access-Control-Allow-Headers 'Content-Type, User-Token, X-Auth-Token';
            add_header Access-Control-Max-Age 1728000;
            add_header Content-Type 'text/plain; charset=utf-8';
            add_header Content-Length 0;
            return 204;
        }

        # 添加 CORS 头
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
        add_header Access-Control-Allow-Headers 'Content-Type, User-Token, X-Auth-Token';
        
        # 缓存配置
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

# 主站前端
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

    root /var/www/ccxc/website;
    index index.html;

    # 安全头
    add_header X-Frame-Options SAMEORIGIN;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";

    location / {
        try_files $uri $uri/ /index.html;
        expires 1h;
    }

    # 静态资源缓存
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

# 管理后台
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name admin.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

    root /var/www/ccxc/admin;
    index index.html;

    # 安全头
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";

    location / {
        try_files $uri $uri/ /index.html;
        expires 1h;
    }

    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

# 谜题前端
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name puzzle.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

    root /var/www/ccxc/puzzle;
    index index.html;

    # 安全头
    add_header X-Frame-Options SAMEORIGIN;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";

    location / {
        try_files $uri $uri/ /index.html;
        expires 1h;
    }

    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

# HTTP 重定向到 HTTPS
server {
    listen 80;
    listen [::]:80;
    server_name yourdomain.com api.yourdomain.com static.yourdomain.com admin.yourdomain.com puzzle.yourdomain.com;
    return 301 https://$server_name$request_uri;
}

启用配置:

bash
# 启用站点配置
sudo ln -s /etc/nginx/sites-available/ccxc-production /etc/nginx/sites-enabled/

# 删除默认配置
sudo rm -f /etc/nginx/sites-enabled/default

# 测试配置
sudo nginx -t

# 重载 Nginx
sudo systemctl reload nginx

系统初始化

1. 创建管理员用户

bash
# 确保所有服务正常运行
sudo systemctl status ccxc-backend
sudo -u www-data pm2 status

# 访问主站注册第一个用户
# https://yourdomain.com

# 设置管理员
cd /opt/ccxc-backend/app
sudo ./ccxc-backend initadmin

2. 验证部署

bash
# 检查各个服务
curl -k https://yourdomain.com
curl -k https://api.yourdomain.com/api/v1
curl -k https://admin.yourdomain.com
curl -k https://puzzle.yourdomain.com
curl -k https://static.yourdomain.com

安全加固

1. 防火墙配置

bash
# 安装 UFW
sudo apt install -y ufw

# 基本配置
sudo ufw default deny incoming
sudo ufw default allow outgoing

# 允许必要端口
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# 启用防火墙
sudo ufw enable

2. 定期维护

创建备份脚本 /opt/backup-ccxc.sh:

bash
#!/bin/bash
BACKUP_DIR="/opt/backups"
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p $BACKUP_DIR

# 备份数据库
mysqldump -u ccxc_user -p ccxc_prod > $BACKUP_DIR/ccxc_db_$DATE.sql

# 备份配置文件
tar -czf $BACKUP_DIR/ccxc_config_$DATE.tar.gz /opt/ccxc-backend/app/Config/

# 备份静态文件
tar -czf $BACKUP_DIR/ccxc_static_$DATE.tar.gz /var/www/static/

# 删除30天前的备份
find $BACKUP_DIR -name "*.sql" -o -name "*.tar.gz" -mtime +30 -delete

设置定时备份:

bash
sudo chmod +x /opt/backup-ccxc.sh
echo "0 2 * * * /opt/backup-ccxc.sh" | sudo crontab -

故障排除

常见问题

1. SSL 证书问题

bash
# 检查证书状态
sudo certbot certificates

# 手动续期
sudo certbot renew

2. 服务启动失败

bash
# 查看后端日志
sudo journalctl -u ccxc -f

# 查看同步服务日志
sudo -u www-data pm2 logs ccxc-sync-server

3. 权限问题

bash
# 修复文件权限
sudo chown -R www-data:www-data /var/www/
sudo chown -R www-data:www-data /opt/ccxc-*

性能监控

bash
# 安装监控工具
sudo apt install -y htop iotop

# 查看资源使用
htop
sudo iotop

# 查看 Nginx 访问日志
sudo tail -f /var/log/nginx/access.log

# 查看系统日志
sudo journalctl -f

更新和维护

更新应用

更新后端:

bash
cd /opt/ccxc-backend/src
sudo git pull
sudo dotnet publish --configuration Release --runtime linux-x64 --self-contained false --output /opt/ccxc-backend/app
sudo systemctl restart ccxc

更新前端:

bash
# 以管理后台为例
cd /tmp/ccxc-builds/admin
git pull
npm install
npm run build
sudo cp -r dist/* /var/www/ccxc/admin/

更新同步服务:

bash
cd /opt/ccxc-sync-server
sudo git pull
sudo npm install
sudo npm run build
sudo -u www-data pm2 restart ccxc-sync-server

下一步

部署完成后,建议你:

  1. 阅读 快速入门 了解系统使用
  2. 阅读 系统优化建议
  3. 配置定期备份策略
  4. 关注 密码菌 Github 获取最新版本和动态

Released under the MIT License. Powered by VitePress.