目录
1. 生产级部署
如果你已经完成了入门篇和进阶篇的学习,现在应该已经在本地能稳定使用 SillyTavern 了。但本地 localhost:8000 只能自己访问,想要在外网安全地使用,或者想让多个设备同时连接,就需要一套完整的生产级部署方案。
本章将带你从单容器裸奔,进化到 Podman Compose 编排 + Nginx 反代 + HTTPS 安全传输 + 可选的 Cloudflare Tunnel 远程访问。
1.1 Podman Compose 编排部署
Podman Compose 是生产环境的首选方案。相比于手动敲 podman run,Compose 文件将整个部署描述声明化,方便版本控制和重复部署。
1.1.1 安装 Podman Compose
# Linux (Fedora / RHEL / CentOS)sudo dnf install podman-compose
# Ubuntu / Debiansudo apt install podman-compose
# macOS / Windows: Podman Desktop 已内置 podman-composepodman-compose --version提示: Podman Compose 与 Docker Compose 的
compose.yaml格式基本兼容。本文的 Compose 文件可直接用于 Docker Compose,只需将podman-compose替换为docker compose。
1.1.2 完整 Compose 文件
在项目根目录创建 compose.yaml:
# compose.yaml — SillyTavern 生产部署编排文件# 使用: podman-compose up -d# 停止: podman-compose down
services: # ============================================================ # SillyTavern 主服务 # ============================================================ sillytavern: image: ghcr.io/sillytavern/sillytavern:latest container_name: sillytavern restart: unless-stopped # 映射端口:宿主机:容器内 # 宿主机建议使用非标准端口(如 8300),避免端口扫描 ports: - "127.0.0.1:8300:8000" # 数据卷挂载:持久化所有用户数据 volumes: # 配置和数据目录 - ./data:/home/node/app/data # 用户自定义插件 - ./plugins:/home/node/app/plugins # 配置文件 - ./config.yaml:/home/node/app/config.yaml:ro # 环境变量通过 .env 文件加载 env_file: - .env # 健康检查:每 30s 检测服务是否存活 healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/"] interval: 30s timeout: 10s retries: 3 # 日志限制,防止磁盘写满 logging: driver: journald options: max-size: "50m" max-file: "3"
# ============================================================ # ChromaDB 向量数据库(可选,进阶篇的向量化记忆需要此服务) # 端口映射为 127.0.0.1:8301:8000,在 SillyTavern 扩展设置中应 # 将 ChromaDB API 地址配置为 http://127.0.0.1:8301 # ============================================================ chromadb: image: chromadb/chroma:latest container_name: sillytavern-chroma restart: unless-stopped ports: - "127.0.0.1:8301:8000" volumes: - ./chroma_data:/chroma/chroma environment: - IS_PERSISTENT=TRUE - PERSIST_DIRECTORY=/chroma/chroma - ANONYMIZED_TELEMETRY=FALSE logging: driver: journald options: max-size: "20m" max-file: "2"逐段说明:
ports: "127.0.0.1:8300:8000":关键的安全设定。只监听本地回环地址,不暴露到公网。前方将由 Nginx 反代处理外部流量。volumes:将容器内的数据目录映射到宿主机,这样删除重建容器不会丢失数据。config.yaml以只读模式挂载,避免运行时误修改。env_file: .env:敏感信息(API Key)通过环境变量文件注入,不写在 Compose 文件中,避免不小心提交到 Git。healthcheck:容器编排平台(如 Podman 健康检查)会定期检查服务是否正常,异常时自动重启。logging:限制日志文件大小,防止长时间运行后磁盘写满。
1.1.3 启动与管理
# 启动所有服务podman-compose up -d
# 查看运行状态podman-compose ps
# 查看日志(实时跟踪)podman-compose logs -f sillytavern
# 重启单个服务podman-compose restart sillytavern
# 停止并移除所有容器podman-compose down
# 更新镜像后重建podman-compose pull && podman-compose up -d1.1.4 Podman Pod 方式(备选方案)
如果你的环境没有 podman-compose,或者你更喜欢轻量方案,可以直接使用 Podman Pod:
# 创建 Podpodman pod create \ --name sillytavern-pod \ --publish 127.0.0.1:8300:8000
# 在 Pod 内启动容器podman run -d \ --pod sillytavern-pod \ --name sillytavern \ -v ./data:/home/node/app/data \ --env-file .env \ --restart unless-stopped \ ghcr.io/sillytavern/sillytavern:latest
# 查看 Pod 状态podman pod listpodman pod stats sillytavern-podPod 方式的好处是同一 Pod 内的容器可以通过 localhost 互相通信,适合需要多个辅助容器(如 ChromaDB)的场景。不过 Compose 方式在可维护性上更胜一筹,推荐作为主力方案。
1.2 Nginx 反代配置
Nginx 在前端接收所有外部请求,根据域名或路径转发到后端的 SillyTavern 服务。这样做有三个好处:统一的 SSL 终止、访问日志集中管理、方便叠加认证和限流。
1.2.1 安装 Nginx
# Fedora / RHELsudo dnf install nginx
# Ubuntu / Debiansudo apt install nginx
# 启动并设置开机自启sudo systemctl enable --now nginx1.2.2 完整 Nginx 配置
创建 /etc/nginx/conf.d/sillytavern.conf:
# SillyTavern 反代配置
upstream sillytavern_backend { # 指向本地 SillyTavern 服务 # 8300 对应 Compose 文件中映射的宿主机端口 server 127.0.0.1:8300; keepalive 64;}
server { # 监听 80 端口,重定向到 HTTPS listen 80; listen [::]:80; server_name sillytavern.yourdomain.com;
# Let's Encrypt 验证路径,acme.sh 自动处理 location /.well-known/acme-challenge/ { root /var/www/html; }
# 其他 HTTP 请求全部重定向到 HTTPS location / { return 301 https://$host$request_uri; }}
server { # HTTPS 配置 listen 443 ssl http2; listen [::]:443 ssl http2; server_name sillytavern.yourdomain.com;
# SSL 证书路径(acme.sh 安装证书后的默认位置) # 注意:将 /home/youruser/ 替换为你的实际用户名 ssl_certificate /home/youruser/.acme.sh/sillytavern.yourdomain.com_ecc/fullchain.cer; ssl_certificate_key /home/youruser/.acme.sh/sillytavern.yourdomain.com_ecc/sillytavern.yourdomain.com.key;
# 现代 SSL 配置(2026 年安全标准) ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; ssl_ecdh_curve X25519:prime256v1:secp384r1; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m;
# 安全响应头 add_header Strict-Transport-Security "max-age=63072000" always; add_header X-Content-Type-Options nosniff; add_header X-Frame-Options DENY;
# 请求体大小限制(角色卡上传可能需要较大限制) client_max_body_size 50M;
# ---------- 反代配置 ---------- location / { # 向后端转发 proxy_pass http://sillytavern_backend;
# WebSocket 支持(SillyTavern 实时通信需要) proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";
# 传递真实客户端信息 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_read_timeout 300s; proxy_send_timeout 300s; }}关键配置说明:
proxy_set_header Upgrade和Connection "upgrade":WebSocket 协议升级的必要头,SillyTavern 的实时消息推送依赖 WebSocket,缺少这两行会导致连接不稳定。proxy_read_timeout 300s:AI 模型响应时间长,默认 60s 可能会超时截断,建议调大到 300s。client_max_body_size 50M:角色卡文件(特别是带图片的 V2 角色卡)可能超过默认的 1M 限制。
1.2.3 配置防火墙
# firewalld(Fedora / RHEL)sudo firewall-cmd --permanent --add-service=httpsudo firewall-cmd --permanent --add-service=httpssudo firewall-cmd --reload
# ufw(Ubuntu / Debian)sudo ufw allow 80/tcpsudo ufw allow 443/tcpsudo ufw reload1.3 HTTPS 证书(Let’s Encrypt + acme.sh)
ACME 客户端推荐使用 acme.sh,它是目前最活跃、支持最广泛的 Let’s Encrypt 客户端脚本。
1.3.1 安装 acme.sh
# 使用官方脚本安装curl https://get.acme.sh | sh -s email=your-email@example.com
# 重新加载 shellexec zsh
# 验证安装acme.sh --version
# 切换到 Let's Encrypt 生产环境(默认为 ZeroSSL,也可用 Let's Encrypt)acme.sh --set-default-ca --server letsencrypt1.3.2 申请证书
假设 Nginx 已经在运行且 80 端口可访问:
# 使用 Webroot 模式申请 ECC 证书(推荐)# ECC 证书比 RSA 证书更小、更安全export DOMAIN="sillytavern.yourdomain.com"
acme.sh --issue -d $DOMAIN \ --webroot /var/www/html \ --keylength ec-256自动化流程说明: acme.sh 会在安装时自动添加 cron 任务,每天检查证书是否在 60 天内过期,过期前自动续签并在续签后自动重载 Nginx。你不需要手动管理续期。
验证 cron 任务已安装:
crontab -l | grep acme.sh应该能看到类似输出:
0 0 * * * "/home/youruser/.acme.sh"/acme.sh --cron --home "/home/youruser/.acme.sh" > /dev/null提示: 默认情况下 acme.sh 每 60 天自动续签一次,有效期总共 90 天。续签后会自动执行
--reloadcmd重载 Nginx 使新证书生效。
1.4 Cloudflare Tunnel 方案(无公网 IP 用户)
如果你没有公网 IP,或者不想暴露服务器端口到公网,Cloudflare Tunnel 是最佳选择。它通过 cloudflared 客户端与 Cloudflare 边缘网络建立加密隧道,外部流量从 Cloudflare 直接进入你的内网服务,完全不经过公网端口。
1.4.1 前提条件
- 一个 Cloudflare 账号(免费版即可)
- 域名 DNS 托管在 Cloudflare
- 服务器能正常访问 Cloudflare 网络
1.4.2 安装 cloudflared
# Linux (amd64)wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64sudo mv cloudflared-linux-amd64 /usr/local/bin/cloudflaredsudo chmod +x /usr/local/bin/cloudflared
# 验证cloudflared --version1.4.3 登录并创建 Tunnel
# 登录 Cloudflare 账号(会打开浏览器授权)cloudflared tunnel login
# 创建 Tunnel(命名为 sillytavern)cloudflared tunnel create sillytavern
# 查看已创建的 Tunnelcloudflared tunnel list登录成功后会在 ~/.cloudflared/ 下生成证书文件,Tunnel 创建后会生成唯一的 Tunnel ID 和凭据文件。
1.4.4 配置 Tunnel
创建 ~/.cloudflared/config.yaml:
# Cloudflare Tunnel 配置 — 将流量转发到本地 SillyTavern 服务
tunnel: sillytaverncredentials-file: /home/youruser/.cloudflared/sillytavern.json
# 入口规则:所有请求转发到本地 8300 端口ingress: # 主服务 - hostname: sillytavern.yourdomain.com service: http://localhost:8300 # 健康检查(Cloudflare 内部用,可以返回 200) - service: http_status:4041.4.5 DNS 路由
# 将域名指向 Tunnelcloudflared tunnel route dns sillytavern sillytavern.yourdomain.com1.4.6 以系统服务运行
# 安装为 systemd 服务sudo cloudflared service install
# 启动sudo systemctl enable --now cloudflared
# 查看状态sudo systemctl status cloudflared
# 查看日志sudo journalctl -u cloudflared -f提示: 使用 Cloudflare Tunnel 时,Nginx 可以只绑定本地
127.0.0.1:8300,完全移除 80/443 端口的 listen 监听——因为 cloudflared 已在边缘层处理了 TLS 终结。此时甚至可以在compose.yaml中去掉ports映射,将网络模式设为network_mode: "host"或使用 Podman 内部网络。
1.4.7 Tunnel 方案 vs 传统反代方案
| 对比项 | Cloudflare Tunnel | Nginx 反代 + 公网 IP |
|---|---|---|
| 是否需要公网 IP | 否 | 是 |
| 是否需要域名 | 是 | 是 |
| 是否需要开放端口 | 否 | 是(80/443) |
| HTTPS 证书管理 | 自动(Cloudflare 处理) | 需手动(acme.sh) |
| 访问速度 | 经 Cloudflare 中转 | 直连(通常更快) |
| 安全性 | 极高(不出公网) | 高(需自行加固) |
| 适用场景 | 内网部署、家庭宽带 | 有公网 IP 的 VPS |
1.5 环境变量与 .env 文件管理
敏感信息(API Key、密码)不应该硬编码在配置文件中,也不应该提交到 Git 仓库。
1.5.1 创建 .env 文件
# 在 Compose 文件同级目录创建 .envtouch .envchmod 600 .env # 仅文件所有者可读写.env 文件内容示例:
# SillyTavern 环境变量配置# 警告:此文件包含敏感信息,切勿提交到 Git!
# SillyTavern 内置认证SILLYTAVERN_BASIC_AUTH_ENABLED=trueSILLYTAVERN_BASIC_AUTH_USERNAME=adminSILLYTAVERN_BASIC_AUTH_PASSWORD=your-strong-password-here
# 可选:覆盖 SillyTavern 默认配置# SILLYTAVERN_PORT=80001.5.2 在 Compose 文件中引用
services: sillytavern: image: ghcr.io/sillytavern/sillytavern:latest env_file: - .env1.5.3 添加到 .gitignore
确保 .env 不会被提交:
echo ".env" >> .gitignore1.5.4 管理多个环境
对于开发、测试、生产不同环境,可以维护多套 .env 文件:
.env.development # 开发环境.env.staging # 测试环境.env.production # 生产环境在 compose.yaml 中指定:
env_file: - .env.production2. 数据备份与恢复
数据是 SillyTavern 最宝贵的资产——角色卡可以再下,但几十万字的对话历史一旦丢失就无可挽回。
2.1 关键数据文件清单
SillyTavern 的所有用户数据默认存储在 data/ 目录下(相对于安装目录或数据卷挂载点)。以下是需要备份的核心文件和目录:
| 目录/文件路径 | 说明 | 备份优先级 |
|---|---|---|
data/default-user/characters/ | 角色卡文件(.json / .png) | ⭐⭐⭐ |
data/default-user/chats/ | 对话历史记录 | ⭐⭐⭐ |
data/default-user/user.conf | 用户配置文件(界面设置、预设偏好) | ⭐⭐ |
data/default-user/settings.json | 全局设置(API 端点、UI 设置) | ⭐⭐ |
data/default-user/group chats/ | 群聊历史(如果使用过群聊功能) | ⭐⭐ |
data/default-user/worlds/ | 世界书(Lorebook)数据 | ⭐⭐ |
data/default-user/vectors/ | 向量数据库本地文件 | ⭐ |
config.yaml | SillyTavern 主配置(API Key 等敏感信息) | ⭐⭐⭐ |
secrets.json | 加密存储的密钥(如果使用) | ⭐⭐⭐ |
chroma_data/ | ChromaDB 持久化数据 | ⭐(如果使用向量化记忆) |
截图辅助: 在你的 SillyTavern 安装目录下执行
ls -la data/default-user/可以看到上述目录结构。确认你的数据目录中有characters/和chats/这两个最重要的目录。
2.2 自动备份脚本
以下是一个完整的备份脚本,包含 tar 打包、日期命名、保留最近 N 份备份等特性:
#!/bin/bash# ============================================================# backup-sillytavern.sh — SillyTavern 自动备份脚本# 使用: chmod +x backup-sillytavern.sh && ./backup-sillytavern.sh# ============================================================
# ---------- 配置区 ----------# SillyTavern 数据目录(Compose 文件中的 data 卷路径)ST_DATA_DIR="/home/youruser/sillytavern/data"# ChromaDB 数据目录(如果使用)CHROMA_DIR="/home/youruser/sillytavern/chroma_data"# 备份存储目录BACKUP_DIR="/home/youruser/backups/sillytavern"# 保留最近多少份备份RETENTION_COUNT=14# 备份文件名前缀PREFIX="sillytavern-backup"# ---------------------------
# 创建备份目录mkdir -p "$BACKUP_DIR"
# 生成时间戳TIMESTAMP=$(date +"%Y%m%d_%H%M%S")BACKUP_FILE="${BACKUP_DIR}/${PREFIX}_${TIMESTAMP}.tar.gz"
echo "[$(date +"%Y-%m-%d %H:%M:%S")] 开始备份..."
# 打包备份# --exclude 排除不需要备份的缓存和临时文件tar -czf "$BACKUP_FILE" \ --exclude="*.log" \ --exclude="node_modules" \ --exclude="cache" \ "$ST_DATA_DIR" \ ${CHROMA_DIR:+ "$CHROMA_DIR"} 2>/dev/null
# 检查备份是否成功if [ $? -eq 0 ]; then BACKUP_SIZE=$(du -h "$BACKUP_FILE" | cut -f1) echo "[$(date +"%Y-%m-%d %H:%M:%S")] 备份完成: $BACKUP_FILE ($BACKUP_SIZE)"else echo "[$(date +"%Y-%m-%d %H:%M:%S")] 备份失败!" exit 1fi
# 清理旧备份,只保留最近 $RETENTION_COUNT 份echo "[$(date +"%Y-%m-%d %H:%M:%S")] 清理旧备份(保留最近 ${RETENTION_COUNT} 份)..."find "$BACKUP_DIR" -name "${PREFIX}_*.tar.gz" -type f | sort -r | tail -n +$((RETENTION_COUNT + 1)) | while read -r old_file; do rm -f "$old_file" echo " 已删除: $old_file"done
echo "[$(date +"%Y-%m-%d %H:%M:%S")] 备份流程全部完成"保存脚本后赋予执行权限:
chmod +x backup-sillytavern.sh./backup-sillytavern.sh2.3 定时备份配置
方式一:cron(最通用,推荐)
# 编辑 cron 任务crontab -e
# 每天凌晨 3:00 执行备份,日志写入文件0 3 * * * /home/youruser/scripts/backup-sillytavern.sh >> /home/youruser/backups/sillytavern/backup.log 2>&1方式二:systemd timer(更精细的控制)
创建 /etc/systemd/system/sillytavern-backup.service:
[Unit]Description=SillyTavern Backup ServiceAfter=network.target
[Service]Type=oneshotExecStart=/home/youruser/scripts/backup-sillytavern.shUser=youruser创建 /etc/systemd/system/sillytavern-backup.timer:
[Unit]Description=Daily SillyTavern backup at 3:00 AM
[Timer]OnCalendar=*-*-* 03:00:00Persistent=trueRandomizedDelaySec=300
[Install]WantedBy=timers.target激活 timer:
sudo systemctl daemon-reloadsudo systemctl enable --now sillytavern-backup.timer
# 验证sudo systemctl list-timers | grep sillytavern2.4 跨设备迁移流程
将 SillyTavern 从旧服务器迁移到新服务器的完整步骤:
源服务器(旧)操作:
# 1. 停止 SillyTavern 服务,保证数据一致性podman-compose down
# 2. 打包完整数据目录tar -czf sillytavern-migrate.tar.gz \ data/ \ config.yaml \ .env
# 3. 复制到新服务器(rsync 推荐,支持断点续传)rsync -avP sillytavern-migrate.tar.gz user@new-server:/path/to/destination/目标服务器(新)操作:
# 1. 在目标服务器上克隆 SillyTavern(如果用 Git 方式)git clone https://github.com/SillyTavern/SillyTavern.gitcd SillyTavern
# 2. 解压数据到正确位置tar -xzf ../sillytavern-migrate.tar.gz
# 3. 启动服务验证podman-compose up -d迁移后检查清单:
- 角色卡列表是否完整?→ 访问
/characters页面 - 对话历史是否可加载?→ 分别打开几个旧对话验证
- API Key 是否保留了?→ 检查
config.yaml或.env - 预设配置是否迁移?→ 检查角色回复风格是否与之前一致
- 世界书内容是否正常?→ 在对话中触发世界书条目测试
2.5 rclone 备份到云存储
异地备份是备份策略的最后一道防线。推荐使用 rclone 将备份同步到云存储。
# 安装 rclonesudo apt install rclone # Ubuntu / Debiansudo dnf install rclone # Fedora
# 交互式配置远程存储(以 Google Drive 为例)rclone config
# 配置完成后,测试同步rclone ls googledrive:/
# 将备份同步到 Google Driverclone sync /home/youruser/backups/sillytavern googledrive:sillytavern-backups/ \ --progress \ --verbose
# S3 兼容存储(如 MinIO、Backblaze B2、Cloudflare R2)示例rclone sync /home/youruser/backups/sillytavern s3:bucket-name/sillytavern-backups/ \ --progress \ --verbose可以将 rclone 同步命令加入到备份脚本末尾,实现备份 + 异地同步一步完成:
# 在 backup-sillytavern.sh 末尾添加if command -v rclone &> /dev/null; then echo "[$(date +"%Y-%m-%d %H:%M:%S")] 同步到云存储..." rclone sync "$BACKUP_DIR" googledrive:sillytavern-backups/ --progress 2>>"$BACKUP_DIR/rclone.log"fi3. 性能优化
3.1 长对话场景调优
随着对话持续,上下文长度不断增长,会影响响应速度和质量。
Token 管理策略:
| 策略 | 操作位置 | 说明 | 建议值 |
|---|---|---|---|
| 上下文限制(Context Limit) | SillyTavern UI → 用户设置 | 超过此长度的历史会被截断 | 4096-8192 |
| 对话压缩(Chat Compression) | SillyTavern UI → 高级设置 | 自动对早期对话进行摘要压缩 | 启用 |
| 动态上下文(Dynamic Context) | SillyTavern UI → 高级设置 | 根据实际对话长度自动调整上下文窗口 | 启用(默认) |
| 消息可见范围(Message Visible Range) | 对话界面右上角滑块 | 控制当前可见的消息条数 | 50-100 |
长对话的主动维护策略:
- 定期新建分支:当对话超过 100 轮,建议从关键节点创建分支(Fork),在新分支继续,避免历史过于臃肿。
- 手动摘要归档:在 SillyTavern 界面使用”对话摘要”功能(位于对话操作菜单中),AI 会生成当前对话摘要,归档后可以安全清理早期历史。
- 使用向量化记忆替代长上下文:进阶篇介绍的向量化记忆(ChromaDB)可以将关键信息存入向量数据库,让你在清理对话历史后仍能保持角色记忆一致性。
3.1.1 上下文长度设置参考
# 在 SillyTavern settings.json 或 config.yaml 中# 不建议超过模型的 max context(可在模型提供商文档中查询)# DeepSeek: 64K# Claude Sonnet 4: 200K# OpenRouter 部分模型: 128KcontextLimit: 8192chatCompression: truedynamicContext: true3.2 ChromaDB 向量数据库清理与维护
如果启用了向量化记忆(进阶篇第 3 章),ChromaDB 的向量数据会持续增长。
3.2.1 查看 ChromaDB 数据量
# 查看 ChromaDB 数据目录大小du -sh /home/youruser/sillytavern/chroma_data/
# 查看容器内 ChromaDB 数据量podman exec sillytavern-chroma du -sh /chroma/chroma3.2.2 清理过期向量
在 SillyTavern 界面的 Vector Storage 管理页面(扩展 → Vector Storage),你可以:
- 查看每个角色名下的向量数量
- 删除特定角色的所有向量
- 手动触发向量重建
3.2.3 重建 ChromaDB 索引
如果向量数据损坏或体积过大:
# 停止相关容器podman-compose stop chromadb
# 备份旧的向量数据mv /home/youruser/sillytavern/chroma_data /home/youruser/sillytavern/chroma_data_old
# 重建目录mkdir -p /home/youruser/sillytavern/chroma_data
# 重启 ChromaDB(会自动创建新数据库)podman-compose up -d chromadb
# 确认新数据库正常运行后,删除旧备份rm -rf /home/youruser/sillytavern/chroma_data_old提示: 删除旧 ChromaDB 数据不会影响角色卡和对话历史。向量化记忆是附加功能,丢失后只需在 SillyTavern 中重新导入并重新生成向量即可恢复。
3.3 多用户共享服务器方案
如果多个人需要共用一台 SillyTavern 服务器,有两种方案:
3.3.1 多实例端口隔离
每个用户运行独立的 SillyTavern 实例,通过不同端口访问:
# compose.yaml 多用户示例(片段)services: sillytavern-user1: image: ghcr.io/sillytavern/sillytavern:latest container_name: sillytavern-user1 ports: - "127.0.0.1:8301:8000" volumes: - ./data-user1:/home/node/app/data env_file: - .env.user1
sillytavern-user2: image: ghcr.io/sillytavern/sillytavern:latest container_name: sillytavern-user2 ports: - "127.0.0.1:8302:8000" volumes: - ./data-user2:/home/node/app/data env_file: - .env.user2Nginx 反代配置多条 location 或不同子域名:
# Nginx 多用户反代server { listen 443 ssl http2; server_name sillytavern.example.com;
# 用户1 location /user1/ { proxy_pass http://127.0.0.1:8301/; proxy_set_header Host $host; # ... WebSocket 等其余配置同上 }
# 用户2 location /user2/ { proxy_pass http://127.0.0.1:8302/; proxy_set_header Host $host; # ... 同上 }}3.3.2 SillyTavern 多用户模式
SillyTavern 支持内置多用户(需要手动启用),但功能较基础,适合小团队共享:
# config.yaml 启用多用户multiUser: trueenableUserAccounts: true启用后在登录页面可以注册多个账号,每个用户有独立的数据目录。不过多实例方案隔离性更好,推荐在正式环境中使用。
4. 安全加固
将 SillyTavern 暴露到公网前,必须做好安全防护。以下措施按重要性排列。
4.1 认证与访问控制(双层防护)
第一层:SillyTavern 内置 Basic Auth
在 config.yaml 中启用:
basicAuth: enabled: true users: - username: "admin" password: "your-strong-password-here"或在 .env 环境变量中:
SILLYTAVERN_BASIC_AUTH_ENABLED=trueSILLYTAVERN_BASIC_AUTH_USERNAME=adminSILLYTAVERN_BASIC_AUTH_PASSWORD=your-strong-password-here第二层:Nginx 层 Basic Auth(推荐,更可控)
# 生成密码文件sudo apt install apache2-utils # Ubuntu / Debiansudo dnf install httpd-tools # Fedora
# 创建用户(会提示输入密码)sudo htpasswd -c /etc/nginx/.htpasswd sillytavern-admin
# 后续添加更多用户(去掉 -c 参数)sudo htpasswd /etc/nginx/.htpasswd another-user在 Nginx 配置中添加 auth 指令:
# 在 server 块或 location 块中添加location / { auth_basic "SillyTavern - 请输入用户名和密码"; auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://sillytavern_backend; # ... 其余反代配置同上}修改配置后重载 Nginx:
sudo nginx -t # 检查配置语法sudo systemctl reload nginx提示: 启用 Nginx Basic Auth 后,需要在 SillyTavern 内置认证之上再加一层密码。推荐两者同时启用——即使一层被绕过,还有另一层保护。
4.2 API Key 保护
API Key 是连接 AI 后端的凭证,泄露后可能被恶意使用产生高额费用。
安全准则:
| 措施 | 操作 | 说明 |
|---|---|---|
| 环境变量隔离 | 在 .env 中设置,不硬编码 | 避免 API Key 出现在配置文件中 |
| 文件权限限制 | chmod 600 .env | 仅文件所有者可读写 |
| 不提交 Git | echo ".env" >> .gitignore | 防止 Key 泄露到远程仓库 |
| 轮换策略 | 定期在 API 提供商后台更换 Key | 每 3-6 个月更换一次 |
# 检查 .env 文件权限ls -la .env# 应该显示: -rw------- (600)
# 如果不正确,修复chmod 600 .env
# 搜索是否有 API Key 被硬编码在配置文件中grep -r "sk-" config.yaml 2>/dev/null && echo "警告: config.yaml 中包含 API Key!"4.3 公网暴露风险评估
以下端口在 Linux 服务器上应该检查是否被意外暴露:
# 查看所有监听端口ss -tlnp
# 检查 SillyTavern 端口是否只绑定在 127.0.0.1# 应该显示: 127.0.0.1:8300,而不是 0.0.0.0:8300端口暴露风险矩阵:
| 情况 | 风险等级 | 说明 |
|---|---|---|
| 仅 Nginx 暴露 443 | 🟢 低 | 通过 HTTPS + 认证,安全 |
| 直接暴露 8000 (SillyTavern) | 🔴 极高 | API Key、对话数据完全暴露 |
| 暴露 8300 但通过 Basic Auth | 🟡 中 | 密码质量决定安全程度 |
| Cloudflare Tunnel 仅 CF 接入 | 🟢 低 | 无暴露端口,最安全 |
4.4 fail2ban 配置(防暴力破解)
fail2ban 可以监控 Nginx 的访问日志,对多次认证失败的 IP 进行临时封禁。
4.4.1 安装 fail2ban
# Ubuntu / Debiansudo apt install fail2ban
# Fedorasudo dnf install fail2ban
# 启用开机自启sudo systemctl enable fail2ban4.4.2 创建 Nginx Auth jail
创建 /etc/fail2ban/jail.local:
# fail2ban 本地配置文件,覆盖 defaults
[DEFAULT]# 封禁时间:1 小时(秒)bantime = 3600# 发现时间窗口:10 分钟findtime = 600# 在 findtime 内最多尝试次数maxretry = 5
# 忽略本机 IPignoreip = 127.0.0.1/8 ::1
# ============================================# SillyTavern Nginx 认证防护# ============================================[sillytavern-auth]enabled = true# 监控 Nginx 访问日志logpath = /var/log/nginx/access.log# 使用 Nginx auth 过滤器filter = nginx-http-auth# 覆盖全局配置port = http,https# 封禁后发送邮件通知(可选)# action = %(action_mwl)s4.4.3 创建自定义过滤器(可选)
如果内置的 nginx-http-auth 过滤器不够精确,可以创建 /etc/fail2ban/filter.d/sillytavern-auth.conf:
[Definition]failregex = ^<HOST> - .* "(GET|POST) / HTTP/.*" 401 .*$ ^<HOST> - .* "(GET|POST) /api.* HTTP/.*" 401 .*$ignoreregex =4.4.4 启动与测试
# 启动 fail2bansudo systemctl start fail2ban
# 查看 SillyTavern jail 状态sudo fail2ban-client status sillytavern-auth
# 手动测试正则匹配sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/sillytavern-auth.conf
# 查看当前封禁列表sudo fail2ban-client banned5. 故障排查手册
本章以表格形式列出最常见的问题及其解决方案,方便快速定位。
5.1 连接后端失败:HTTP 错误码速查
| 错误码 | 现象 | 原因 | 解决方案 | 诊断命令 |
|---|---|---|---|---|
| 401 Unauthorized | 提示”认证失败” | API Key 无效或已过期 | 在 API 提供商后台重新生成 Key,更新 .env | curl -s -o /dev/null -w "%{http_code}" https://api.deepseek.com/v1/models -H "Authorization: Bearer YOUR_KEY" |
| 403 Forbidden | 提示”无权访问” | API Key 权限不足或账号余额为 0 | 检查账号余额,检查 API Key 权限范围 | 登录 API 提供商控制台查看余额 |
| 429 Too Many Requests | 响应变慢后出现”请求过于频繁” | 触发了 API 速率限制 | 降低请求频率,增加 SillyTavern 请求间隔(设置 → API → Request Interval 设为 1-2 秒) | grep "429" /home/youruser/sillytavern/data/default-user/logs/*.log |
| 500 Internal Server Error | API 返回空或无意义内容 | 后端模型服务内部错误 | 稍后重试,查看模型提供商的官方状态公告 | 检查 API 提供商官网或账号控制台了解服务状态 |
| 502 Bad Gateway | Nginx 返回 502 | SillyTavern 服务未启动或端口错误 | 检查容器是否运行,检查 Compose 端口映射 | podman ps,podman logs sillytavern |
5.2 响应质量异常
| 现象 | 原因 | 解决方案 | 诊断方法 |
|---|---|---|---|
| 回复被截断(不完整) | 上下文限制(Context Limit)过低 | 增加 Context Limit(4096 → 8192),检查模型的 Max Tokens 设置 | 在 SillyTavern UI 查看当前上下文使用量 |
| 回复乱码/含奇怪符号 | 编码问题,或模型输出层被截断 | 检查 SillyTavern 编码设置(确保 UTF-8),尝试切换预设 | 尝试用同一模型在 API 官方测试页生成相同提示词 |
| 角色偏移(OOC,角色突然说人话) | 上下文窗口被挤占,早期角色设定被弹出 | 启用”Chat Compression”(对话压缩),或使用”Author’s Note”固定角色设定 | 检查当前上下文使用百分比 |
| 回复质量逐渐下降 | 长对话中上下文窗口尾部溢出 | 创建新分支或启用摘要归档 | 查看对话轮次和 Token 使用量统计 |
5.3 性能迟缓诊断
| 症状 | 可能原因 | 诊断步骤 | 修复方法 |
|---|---|---|---|
| UI 响应慢(页面加载卡顿) | 服务器 CPU/内存不足 | htop 查看 CPU 和内存使用率 | 增加服务器资源,减少并发用户数 |
| 生成回复慢(AI 思考时间长) | 模型推理速度瓶颈 | 检查后端 API 延迟(在 SillyTavern UI 查看 “Response Time”) | 升级 API 套餐(更快的推理优先级),或切换到更小的模型 |
| 磁盘 IO 高 | 日志文件过大或 ChromaDB 频繁读写 | iostat -x 1 查看磁盘利用率,du -sh data/default-user/logs/ 检查日志大小 | 清理日志,增大 ChromaDB 批处理间隔 |
| 内存使用持续增长 | 长时间运行未重启 | podman stats sillytavern 查看容器内存使用趋势 | 定期重启容器(每周一次),或增加 --memory 限制 |
# 资源监控命令速查htop # 实时 CPU/内存/进程glances # 综合系统监控podman stats # 容器资源使用统计podman stats --no-stream # 单次快照du -sh data/default-user/logs/ # 日志占用的磁盘空间journalctl -u nginx --since "1 hour ago" | grep "error" # Nginx 错误日志5.4 Podman 常见问题
| 现象 | 原因 | 解决方案 | 诊断命令 |
|---|---|---|---|
| 容器无法启动 | 配置错误、端口冲突或镜像损坏 | 查看容器日志定位错误 | podman logs sillytavern |
| 端口已被占用 | 其他服务使用了同一端口 | 修改 compose.yaml 中的端口映射或停止冲突进程 | ss -tlnp | grep 8300 |
| 容器间网络不通 | 网络配置或 Pod 模式问题 | 检查容器网络模式,使用 network inspect | podman network inspect podman-default |
| SELinux 阻止卷挂载 | SELinux 安全上下文不匹配 | 使用 chcon 更改安全上下文,或添加 :Z 标签 | ls -Z data/,sudo chcon -Rt container_file_t data/ |
| 存储空间不足 | 日志/镜像/卷积累 | 清理未使用的镜像和卷 | podman system prune -af(谨慎使用,会删除未使用的镜像和卷) |
SELinux 快速修复:
# 如果 Podman 因为 SELinux 拒绝挂载卷,添加 :Z 后缀# 在 compose.yaml 中:# volumes:# - ./data:/home/node/app/data:Z
# 或在运行时添加 :Zpodman run -v ./data:/home/node/app/data:Z ...
# 也可以临时设置为 Permissive 模式(不推荐生产环境)sudo setenforce 05.5 日志查看与诊断命令速查
| 日志来源 | 路径/命令 | 常用参数 |
|---|---|---|
| SillyTavern 应用日志 | data/default-user/logs/ 目录下 | tail -f data/default-user/logs/*.log |
| SillyTavern 容器日志 | podman logs sillytavern | podman logs -f --tail 100 sillytavern |
| Nginx 访问日志 | /var/log/nginx/access.log | tail -f /var/log/nginx/access.log | grep -v "health" |
| Nginx 错误日志 | /var/log/nginx/error.log | tail -f /var/log/nginx/error.log |
| systemd 系统日志 | journalctl | journalctl -u sillytavern-backup.service -f |
| fail2ban 日志 | /var/log/fail2ban.log | tail -f /var/log/fail2ban.log |
| Cloudflared 日志 | journalctl -u cloudflared | journalctl -u cloudflared -f --tail 50 |
| Podman 事件 | podman events | podman events --since 5m |
快速诊断三板斧:
# 1. 检查服务是否运行podman-compose ps
# 2. 检查 SillyTavern 是否有报错podman logs sillytavern --tail 50
# 3. 检查 Nginx 是否能正常转发curl -sI https://sillytavern.yourdomain.com | head -56. 更新与维护
6.1 Git Pull 更新流程
如果使用 Git 克隆方式安装的 SillyTavern(对应入门篇的”方式二”),更新步骤如下:
# 重要:更新前先备份!# 立即执行一次备份脚本./backup-sillytavern.sh
# 或手动备份关键数据目录cp -r data data_backup_$(date +"%Y%m%d_%H%M%S")
# 拉取最新代码git pull origin main
# 更新 Node.js 依赖(SillyTavern 依赖可能变更)npm install
# 重启服务podman-compose restart sillytavern
# 验证更新后版本# 在 SillyTavern UI 底部状态栏可以查看当前版本号提示: 非必要不追新版本。建议在 SillyTavern 官方发布 Release 后等待 1-2 天,确认没有重大 Bug 再更新。关注 GitHub Releases 页面获取更新公告。
如果使用 Podman Compose 方式(推荐的生产方式):
# Compose 方式更新podman-compose pull # 拉取最新镜像podman-compose up -d # 重建容器6.2 版本锁定
生产环境建议锁定在某个稳定版本,避免意外升级引入不稳定变更:
# 查看所有可用版本标签git tag -l | sort -V
# 锁定到特定版本(例如 1.12.6)git checkout tags/1.12.6 -b stable-1.12.6
# 查看当前版本git describe --tagsCompose 方式也建议指定具体版本号,而不是使用 latest:
# compose.yaml 中指定具体版本image: ghcr.io/sillytavern/sillytavern:1.12.66.3 版本回退方法
如果更新后出现严重问题,回退到之前版本:
# Git 方式回退# 1. 停止服务podman-compose down
# 2. 回退到之前版本git checkout tags/1.12.5
# 3. 重新安装依赖并启动npm installpodman-compose up -d
# Compose 方式回退# 1. 修改 compose.yaml 中镜像标签为旧版本# image: ghcr.io/sillytavern/sillytavern:1.12.5
# 2. 重新创建容器podman-compose up -d提示: 如果更新同时导致数据不兼容,可能需要同时恢复之前备份的
data/目录。这也是每次更新前必须备份的原因。
6.4 社区资源
| 资源 | 链接 | 说明 | 语言 |
|---|---|---|---|
| 官方文档 | https://docs.sillytavern.app/ | 官方部署、配置、扩展文档 | EN |
| GitHub Issues | https://github.com/SillyTavern/SillyTavern/issues | 报告 Bug、搜索已知问题 | EN |
| GitHub Releases | https://github.com/SillyTavern/SillyTavern/releases | 版本发布说明和更新日志 | EN |
| 官方 Discord | https://discord.gg/sillytavern | 社区讨论、技术支持 | EN 为主 |
| Reddit r/SillyTavernAI | https://www.reddit.com/r/SillyTavernAI/ | 用户交流、角色卡分享 | EN |
| Chub.ai | https://www.chub.ai/ | 角色卡社区(最大) | EN |
| NGA SillyTavern 讨论 | https://bbs.nga.cn/thread.php?fid=-547859 | 中文社区讨论 | 中文 |
6.5 后续学习路径
完成本系列三篇文章后,你已经从零到掌握 SillyTavern 的完整使用链路。如果你希望继续深入,以下方向值得探索:
工程方向:
- Kubernetes 编排:将 SillyTavern 部署到 K3s/K8s 集群,实现自动扩缩容和高可用
- CI/CD 流水线:使用 GitHub Actions 自动化备份、镜像构建、自动部署
- 监控告警:部署 Prometheus + Grafana 监控 SillyTavern 的 API 延迟和资源使用
AI 方向:
- 提示工程(Prompt Engineering):深入学习 System Prompt 设计和 Chain-of-Thought 技术
- 模型微调(Fine-tuning):使用 LoRA/QLoRA 对开源模型进行角色扮演微调
- RAG 增强检索:为 SillyTavern 搭建自定义知识库 RAG 管道
创作方向:
- 角色卡设计艺术:从对话示例撰写到角色弧光设计的完整方法论
- 世界书构建:为你的原创世界观构建完整的 Lorebook 体系
- SillyTavern 扩展开发:学习编写自定义 SillyTavern 扩展插件
本系列至此完结。从入门到进阶再到生产运维,希望这三篇文章能帮助你充分发挥 SillyTavern 的潜力。如果在部署中遇到问题,先查阅故障排查手册,依然无法解决再到社区资源中寻求帮助。