new-api 系列(七):生产环境部署与安全加固
系列目录
# 生产环境部署与安全加固
## 反向代理
- Nginx:功能全面,手动证书
- Caddy:自动 HTTPS,配置简洁
- 流式响应配置(关闭缓冲)
## HTTPS / TLS
- Let's Encrypt 免费证书
- 自动续期
- HSTS 安全头
- TLS 1.2+ 最低版本
## 数据库运维
- SQLite → MySQL 迁移
- MySQL 连接池调优
- 定时备份脚本
- 灾难恢复演练
## 安全加固
- 修改默认管理员账号
- 防火墙规则
- fail2ban 防暴力破解
- 最小权限原则
- 定期更新 new-api
## 备份策略
- 数据库定时 dump
- 配置文件备份
- 异地/云存储备份
反向代理方案
new-api 直接监听 :3000 是 HTTP 明文传输,不适合公网暴露。生产环境的标准做法是在前面架一层反向代理,由反代处理 HTTPS、域名、安全头等。
方案对比
| 特性 | Nginx | Caddy |
|---|---|---|
| HTTPS 配置 | 手动申请证书 + cron 续期 | 自动申请 + 自动续期 |
| 性能 | 极高,久经考验 | 优秀,日常够用 |
| 配置复杂度 | 中等 | 低 |
| 流式响应 | 需手动关缓冲 | 一句 flush_interval -1 |
| 插件生态 | 极其丰富 | 较少但够用 |
| 推荐场景 | 对性能有极致要求 | 追求简洁运维 |
Nginx 方案
# /etc/nginx/sites-available/new-api
server {
listen 443 ssl http2;
server_name api.example.com;
# SSL 证书(Let's Encrypt)
ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
# TLS 安全配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
# 安全头
add_header Strict-Transport-Security "max-age=63072000" always;
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
# 客户端请求体大小(大文件上传场景)
client_max_body_size 10m;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
# 传递真实客户端 IP(new-api 日志和 IP 白名单依赖)
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;
# 流式响应(SSE)必须关闭缓冲
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
# WebSocket 支持(如需要)
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
# HTTP 强制跳转 HTTPS
server {
listen 80;
server_name api.example.com;
return 301 https://$host$request_uri;
}
启用配置:
sudo ln -s /etc/nginx/sites-available/new-api /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Let's Encrypt 证书申请:
# 使用 certbot
sudo certbot --nginx -d api.example.com
# 或 acme.sh
acme.sh --issue -d api.example.com --nginx
Caddy 方案(推荐新手)
# /etc/caddy/Caddyfile
api.example.com {
reverse_proxy 127.0.0.1:3000 {
flush_interval -1 # 关闭缓冲,流式输出关键配置
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
}
# 安全头
header {
Strict-Transport-Security "max-age=63072000"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
}
}
Caddy 会自动向 Let's Encrypt 申请证书并定期续期,整个过程不需要手动操作。
flowchart LR
A["配置 Caddyfile"] --> B["启动 Caddy"]
B --> C["自动申请证书"]
C --> D["HTTPS 服务就绪"]
D --> E["定期自动续期"]
数据库:SQLite → MySQL 迁移
SQLite 在请求量小的时候没问题,但当日志表超过几十万行,或并发用户超过 20 人时,建议迁移到 MySQL。
MySQL 安装
# Ubuntu / Debian
sudo apt install mysql-server
sudo mysql_secure_installation
# 创建数据库和用户
sudo mysql -u root <<SQL
CREATE DATABASE new_api CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'newapi'@'127.0.0.1' IDENTIFIED BY 'your-strong-password';
GRANT ALL PRIVILEGES ON new_api.* TO 'newapi'@'127.0.0.1';
FLUSH PRIVILEGES;
SQL
配置 new-api 连接 MySQL
./new-api \
--port 3000 \
--db-type mysql \
--mysql-dsn "newapi:your-strong-password@tcp(127.0.0.1:3306)/new_api?charset=utf8mb4&parseTime=True&loc=Local"
首次启动时 new-api 会自动创建所有需要的表。
从 SQLite 迁移数据
new-api 目前没有内置的一键迁移工具。如果需要保留历史数据,可以:
- 从 SQLite 导出关键数据(用户、令牌、渠道)为 CSV
- 在 MySQL 环境中重新创建这些资源
- 旧日志保留在 SQLite 备份中备查
或者直接用 SQLite 工具导出导入:
# 导出 SQLite 数据
sqlite3 new-api.db .dump > backup.sql
# 转换后导入 MySQL(注意 SQL 语法差异,需手动调整)
大多数情况下,迁移到 MySQL 时重新配置渠道和令牌比折腾数据迁移更快。日志数据可以保留在旧的 SQLite 文件中备查。
备份策略
备份什么
| 需备份 | 位置 | 说明 |
|---|---|---|
| 数据库文件 | ~/new-api/new-api.db(SQLite)或 MySQL dump |
用户、令牌、渠道、日志全在这 |
| 配置文件 | systemd unit 文件 | 启动参数 |
| 日志文件 | ~/new-api/logs/ |
可选,排查历史问题用 |
SQLite 自动备份脚本
#!/bin/bash
# /usr/local/bin/backup-newapi.sh
BACKUP_DIR="/backup/new-api"
DB_FILE="$HOME/new-api/new-api.db"
RETENTION_DAYS=30
mkdir -p "$BACKUP_DIR"
# 备份数据库(SQLite 支持在线备份)
sqlite3 "$DB_FILE" ".backup '$BACKUP_DIR/new-api-$(date +%Y%m%d-%H%M%S).db'"
# 清理旧备份
find "$BACKUP_DIR" -name "*.db" -mtime +$RETENTION_DAYS -delete
echo "Backup completed: $(date)"
# 加入 crontab(每天凌晨 3 点)
crontab -e
# 添加:
0 3 * * * /usr/local/bin/backup-newapi.sh >> /var/log/newapi-backup.log 2>&1
MySQL 备份
#!/bin/bash
# MySQL 备份脚本
BACKUP_DIR="/backup/new-api"
mysqldump -u newapi -p'your-password' --single-transaction new_api \
> "$BACKUP_DIR/new-api-mysql-$(date +%Y%m%d-%H%M%S).sql"
异地备份
备份文件存在本地还不够——服务器故障可能导致数据丢失。建议再加一层:
- rsync 到另一台机器:
rsync -avz /backup/new-api/ user@backup-server:/backup/ - 云存储:
rclone sync /backup/new-api/ s3:my-backup-bucket/new-api/ - GitHub 私有仓库:适用于配置文件的版本管理
安全加固
管理员账号
- 不使用默认
root/123456 - 密码 16 位以上随机字符串
- 创建专属管理员账号,禁用默认 root
防火墙
# 只开放必要端口
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp # SSH
sudo ufw allow 443/tcp # HTTPS(反代)
sudo ufw allow 80/tcp # HTTP(证书申请需要)
sudo ufw enable
# 注意:不要开放 3000 端口!new-api 只监听 127.0.0.1
flowchart LR
A["公网"] -->|":443"| B["Nginx / Caddy"]
B -->|"127.0.0.1:3000"| C["new-api"]
C --> D["上游 API"]
new-api 只绑定 127.0.0.1,外网无法直接访问。所有流量必须经过反代。
fail2ban 防暴力破解
new-api 登录接口如果暴露到公网,建议加一层 fail2ban 防护。
# /etc/fail2ban/jail.local
[new-api]
enabled = true
port = http,https
filter = new-api
logpath = /var/log/nginx/api.example.com.access.log
maxretry = 10
bantime = 3600
findtime = 600
最小权限原则
- new-api 进程以普通用户运行(不要 root)
- systemd 配置中加
NoNewPrivileges=yes - 数据库用户只给必要权限(不要
GRANT ALL如果不需要) - API Key 和密钥不写入版本控制
定期更新
# 检查 GitHub Releases
curl -s https://api.github.com/repos/Calcium-Ion/new-api/releases/latest | grep tag_name
关注更新日志中的安全修复,及时升级。
SSL 证书自动续期
Let's Encrypt(certbot)
# certbot 默认会自动续期(systemd timer)
sudo systemctl status certbot.timer
# 手动测试续期
sudo certbot renew --dry-run
Let's Encrypt(acme.sh)
acme.sh --renew -d api.example.com --force
Caddy
完全自动,无需任何操作。Caddy 在证书到期前 30 天自动续期。
性能调优
new-api 本身
- Go 程序本身已经足够高效,一般不需要调优
- 如果请求量很大(>1000 QPM),考虑用 MySQL 替代 SQLite
- 启动参数中可控制日志级别(
--log-level warn减少日志 I/O)
Nginx
# 连接数优化
worker_processes auto;
worker_connections 1024;
# 静态文件缓存
location /assets/ {
expires 30d;
add_header Cache-Control "public, immutable";
}
MySQL
# /etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld]
max_connections = 100
innodb_buffer_pool_size = 256M # 按服务器内存调整
innodb_log_file_size = 64M
系列导航
系列导航
- (一)认识 new-api——新一代 AI API 管理网关
- (二)安装部署——从零搭建 new-api
- (三)渠道配置——接入各类模型提供商
- (四)令牌与用户管理
- (五)计价模型与成本控制
- (六)监控、日志与告警
- (七)生产环境部署与安全加固(本文)
- (八)进阶——多实例、负载均衡与 SSO
- (九)接入国内支付——支付宝、微信与自动充值
- (十)接入国际支付——Stripe、PayPal 与海外收银
实操清单
- Caddy 反向代理已配置(
airouter.k330.com,HTTPS 自动签发,flush_interval -1流式支持) - HTTPS 正常(Caddy 自动续期,无需手动操作)
- 验证流式响应:用 curl 发一条请求,确认 token 逐步返回
- ⚠️ 封锁 3000 端口(当前 new-api 监听
*:3000,外网可直接访问,存在安全风险):ufw allow 22 && ufw deny 3000 && ufw enable- 或
iptables -A INPUT -p tcp --dport 3000 ! -s 127.0.0.1 -j DROP
- 确认 3000 端口对外不可达(
curl http://外网IP:3000应超时) - ⚠️ 设置数据库定时备份(当前无任何备份计划):
crontab -e添加每日备份 - 配置异地备份(rsync / rclone 推送到对象存储)
- 执行一次备份恢复演练(停服务 → 替换 db → 重启 → 验证数据)
- 独立管理员账号已创建(sdmike),已替代默认 root
- 配置 fail2ban 防暴力登录(可选)