生产环境部署
注意
本部署指南专门针对 Linux 生产服务器环境。如果需要搭建开发环境,请参考 开发环境搭建。
系统要求
操作系统
- Ubuntu 20.04 LTS 或更高版本(推荐)
- Debian 11+
服务器配置
- CPU: 2 核心或更多
- 内存: 4GB 或更多(推荐 8GB+)
- 存储: 50GB 或更多可用空间
- 网络: 公网 IP 和域名
软件要求
- Node.js v22.0.0 或更高版本
- .NET 8.0 Runtime
- MariaDB 10.11.2 或更高版本
- Redis 5.0.9 或更高版本
- Nginx 1.17 或更高版本
- PM2 进程管理器
域名和 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
下一步
部署完成后,建议你:
- 阅读 快速入门 了解系统使用
- 阅读 系统优化建议
- 配置定期备份策略
- 关注 密码菌 Github 获取最新版本和动态