0 前言
搭建完 3x-ui 后,服务器还有些内存,于是想着部署一个云酒馆玩玩。在已经有一个稳定的公网 IP 的情况下,可以很轻松地部署一个安全的私人云酒馆,于是想写篇教程分享一下我的方案。
首先,一台 VPS 依旧是必要的。你可以把云酒馆部署在一个性能较好的建站机上,再用线路机拉它。也可以干脆都部署在线路机上,效果是一样的,服务器的最低配置是1核CPU、1g内存、10g硬盘。其次,需要一个域名,可以使用免费域名,只要能托管到 Cloudflare 上均可。
安全的云酒馆方案有很多,比如 tailscale 组网,比如用 zero trust 进行更严格的登录验证。本文介绍这种方案是因为作者已经搭建好了 3x-ui,且有使用网络代理的习惯,因此对我来说这是最安全最便捷的做法。
1 前期准备
首先,你需要把域名托管到 Cloudflare 上,在你的域名上添加一条 A 记录,指向你服务器的 IP 地址,关掉 CDN 代理
然后,你需要一个固定的公网 IP 地址,如果你已经搭建过 3x-ui, 使用那个作为你的公网 IP 即可,使用酒馆的时候挂上梯子。不知道怎么做的看我的上一篇教程3x-ui搭建教程
2 安装酒馆
如果你没有安装 docker,需要先安装。docker 的好处有很多,环境隔离、一键部署、数据迁移等等。
curl -fsSL https://get.docker.com | sudo sh建立一个目录,存放酒馆
mkdir /opt/sillytavern && cd /opt/sillytavern编写配置文件
nano docker-compose.yml把以下配置信息复制进去
services: sillytavern: build: .. container_name: sillytavern hostname: sillytavern image: ghcr.io/sillytavern/sillytavern:latest environment: - NODE_ENV=production - FORCE_COLOR=1 - SILLYTAVERN_HEARTBEATINTERVAL=30 ports: - "127.0.0.1:8000:8000" volumes: - "./config:/home/node/app/config" - "./data:/home/node/app/data" - "./plugins:/home/node/app/plugins" - "./extensions:/home/node/app/public/scripts/extensions/third-party" healthcheck: test: ["CMD", "node", "src/healthcheck.js"] interval: 30s timeout: 10s start_period: 20s retries: 3 restart: unless-stoppedctrl + o 保存,回车,ctrl + x 退出
一键拉起容器
docker compose up -d酒馆已经安装好了,接下来我们修改酒馆的配置文件
nano /opt/sillytavern/config/config.yaml可以用ctrl + w 快速搜索。首先,找到whitelistMode,把它修改成以下的样子,把你的公网 IP 添加进白名单
whitelistMode: true# When enabled, whitelist will also verify IP in headers enabled in `forwardedHeaders` section.enableForwardedWhitelist: true# Whitelist of allowed IP addresseswhitelist: - ::1 - 127.0.0.1# docker 内部网段 - 172.16.0.0/12# 你的公网 IP - 你的公网 IP就在下面一点点的位置,找到basicAuthMode,添加登录用的账号密码。把user和password改成你自己的。
# Toggle basic authentication for endpointsbasicAuthMode: true# Basic authentication credentialsbasicAuthUser: username: "user" password: "password"找到 hostWhitelist
# Host whitelist configuration. Recommended if you're using a listen modehostWhitelist: # Enable or disable host whitelisting enabled: true # Scan incoming requests for potential host header spoofing scan: true # List of allowed hosts. Do not include localhost or IPs, these are safe. # Use a dot to create subdomain patterns. # Examples: # - example.com # - .trycloudflare.com hosts: - tavern.你的域名酒馆安全部分已经配置结束了,现在,只有白名单里面的 IP,才能通过你的域名,输入正确的账号密码访问酒馆
还有一些其它的配置:
- lazyLoadCharacters: 把懒加载改成 true,提高酒馆启动速度
- 把backups里面的numberOfBackups改成3,即每个聊天最多只能有 3 个备份,以免服务器硬盘爆炸。我的本地酒馆不限制备份,玩半年酒馆就超过10G了,大部分都是备份文件
修改完以后,依旧是ctrl + o 保存,回车,ctrl + x 退出
重启酒馆,让配置文件生效
docker compose restart3 安装 Caddy
现在,我们的酒馆在访问上已经足够安全了,只有你自己的公网 ip 能访问,不对外开放。但是,如果不通过 ssl 证书加密,中间人可以窃取你的明文数据,获取你的聊天记录、api 密钥等。所以,本节讲解如何通过 Caddy 配置反向代理,Caddy 会自动为你的域名申请证书,提供安全的 https 加密。
首先我们在 VPS 上安装 Caddy,以下是官方提供的 Ubuntu/Debian 部署流程:
sudo apt update && sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl gpgcurl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpgcurl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.listsudo chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpgsudo chmod o+r /etc/apt/sources.list.d/caddy-stable.listsudo apt install caddy -y如果你的服务器有 ufw 或者安全组,开始 Caddy 配置前,请放行 80 端口和一个用于访问酒馆的端口,我用的是 8001,不用 443 是因为会和 reality 协议搭建的节点端口冲突。如果你没有在这台服务器上搭建网络代理,也可以直接用 443。
打开 Caddy 配置文件
sudo nano /etc/caddy/Caddyfile把以下内容修改后添加到文件末尾
tavern.你的域名:8001 { # 将流量反向代理到本地 Docker 跑的酒馆端口 reverse_proxy 127.0.0.1:8000}重载 Caddy
sudo systemctl reload caddy可以检查一下有没有报错,证书申请成功没有
sudo systemctl status caddy现在,在你开启网络代理,使用 VPS 的公网 IP 的情况下,可以通过 https://tavern.你的域名:8001 访问你的云酒馆了
4 数据备份
本节介绍了如何在服务器上配置 Rclone,把酒馆数据定时备份到 Google Drive 上。Rclone 支持非常多种云盘,比如 One Drive,Cloudflare R2 等等,选择谷歌是因为它的免费额度给的相对较大,有 15 GB,备份酒馆是足够了,如果有学生会员甚至有 5T 的额度。
4.1 申请 API 密钥
配置 Google Drive 的远程连接,需要填入 Client ID,其实也可以直接使用公共的 Client ID,但是速度会比较慢,而且谷歌在逐步停用/限制公用共享 Client ID,所以我们可以申请一个自己的。这部分申请还挺麻烦的,你也可以直接使用公共的,先用着再说,可以跳过此节。
首先访问谷歌控制台
https://console.cloud.google.com/
顶部搜索栏搜索Google Drive API

点击启用,这里我已经启用过了,然后点管理

创建凭证


邮箱用你的谷歌邮箱就行



选桌面应用,名称随便填

把凭证下载下来,里面有Client ID 和Client Secret,点击完成

发布应用,否则会限制访问,不需要验证应用,直接用就行

4.2 配置 Rclone
在 VPS 上安装 Rclone
sudo -v ; curl https://rclone.org/install.sh | sudo bash输入以下指令,进入配置:
rclone confige) Edit existing remote
n) New remote
d) Delete remote
r) Rename remote
c) Copy remote
s) Set configuration password
q) Quit config
e/n/d/r/c/s/q>
输入n,我们新建一个远程连接
Enter name for new remote.
name>
给这个配置起一个名字,这里我输入 gdrive
24 / Google Drive
\ (drive)
25 / Google Photos
\ (google photos)
26 / HTTP
\ (http)
27 / Hadoop distributed file system
\ (hdfs)
28 / HiDrive
\ (hidrive)
29 / Huawei Drive
\ (huaweidrive)
30 / ImageKit.io
\ (imagekit)
会显示非常多支持的存储类型,我这里 24 是 Google Drive,输入 24
Option client_id.
Google Application Client Id
Setting your own is recommended.
See https://rclone.org/drive/#making-your-own-client-id for how to create your own.
If you leave this blank, it will use an internal key which is low performance.
Enter a value. Press Enter to leave empty.
client_id>
如果你已经按照 4.1 节手动创建了客户端,可以直接打开下载的 json 文件,填入自己的Client ID。否则,直接回车留空,用公共的
Option client_secret.
OAuth Client Secret.
Leave blank normally.
Enter a value. Press Enter to leave empty.
client_secret>
同样,有自己的用自己的,没有就回车留空
Option scope.
Comma separated list of scopes that rclone should use when requesting access from drive.
Choose a number from below, or type in your own value.
Press Enter to leave empty.
1 / Full access all files, excluding Application Data Folder.
\ (drive)
2 / Read-only access to file metadata and file contents.
\ (drive.readonly)
/ Access to files created by rclone only.
3 | These are visible in the drive website.
| File authorization is revoked when the user deauthorizes the app. \ (drive.file)
/ Allows read and write access to the Application Data folder.
4 | This is not visible in the drive website.
\ (drive.appfolder)
/ Allows read-only access to file metadata but
5 | does not allow any access to read or download file content.
\ (drive.metadata.readonly)
scope>
权限限制,输入 1,给它完整的读写权限
Option service_account_file.
Service Account Credentials JSON file path.
Leave blank normally.
Needed only if you want use SA instead of interactive login.
Leading~will be expanded in the file name as will environment variables such as${RCLONE_CONFIG_DIR}.
Enter a value. Press Enter to leave empty.
service_account_file>
回车留空
Edit advanced config?
y) Yes
n) No (default)
y/n>
输入n
Use web browser to automatically authenticate rclone with remote?
* Say Y if the machine running rclone has a web browser you can use
* Say N if running rclone on a (remote) machine without web browser access
If not sure try Y. If Y failed, try N.
y) Yes (default)
n) No
y/n>
这里是问我们登录认证的方式,VPS 上没有浏览器窗口,我们只能输入 n,在本地电脑上认证。
Option config_token.
For this to work, you will need rclone available on a machine that has a web browser available.
For more help and alternate methods see: https://rclone.org/remote_setup/
Execute the following on the machine with the web browser (same rclone version recommended):
rclone authorize “drive” “LpJpY27wpS18ImRyaRZlIn0”
Then paste the result.
Enter a value.
这里注意!它返回了一串命令rclone authorize “drive” “LpJpY27wpS18ImRyaRZlIn0”。记下来,我们需要在本地电脑上运行它。
如果你用的是 windows,打开你的 cmd,输入以下指令先安装 Rclone:
winget install Rclone.Rcloner关闭当前窗口,打开一个新的 cmd 窗口
cmd 默认不走系统代理,我们先为这个窗口设置临时的代理变量。10808是v2ray的代理端口,如果你用的其它代理软件,替换成你自己。或者你可以直接打开梯子的 tun 模式。
$env:HTTP_PROXY="http://127.0.0.1:10808"$env:HTTPS_PROXY="http://127.0.0.1:10808"输入 VPS 上之前返回的指令,每个人的token不同,记得替换成你自己的:
rclone authorize "drive" "LpJpY27wpS18ImRyaRZlIn0"随后,会跳转到浏览器上进行认证。如果你是用自己的客户端,因为没有验证会说有风险,在高级里面无视风险继续访问即可。
认证结束后,cmd 会返回一长串东西
Paste the following into your remote machine --->
你的token
<---End paste
把中间的 token 部分粘贴回 VPS,完成认证
Configure this as a Shared Drive (Team Drive)?
y) Yes
n) No (default)
输入 n,我们用的是个人云盘
Configuration complete.
Options:
- type: drive
- scope: drive
- token: {}
- team_drive:
Keep this “gdrive” remote?
y) Yes this is OK (default)
e) Edit this remote
d) Delete this remote
y/e/d>
配置结束,输入 y 保存
Name Type
==== ====
gdrive drive
e) Edit existing remote
n) New remote
d) Delete remote
r) Rename remote
c) Copy remote
s) Set configuration password
q) Quit config
e/n/d/r/c/s/q>
上面可以看到配置好的远程连接,输入 q,退出配置
验证一下能不能访问你的云盘。
rclone lsd gdrive:如果没有报错,就是配置成功了。
4.3 自动备份脚本
创建一个脚本
nano /opt/sillytavern/st_backup.sh把以下内容粘贴进去。这个脚本是哈基米写的,做了比较多的异常判断,如果还是不行,请拷打哈基米。
可以手动修改备份数量,改成适合你的。如果备份文件实在大,云盘空间告急,可以把云盘备份数量改成1
#!/usr/bin/env bash
# ==================== 配置区域 ====================ST_ROOT_DIR="/opt/sillytavern"LOCAL_BACKUP_DIR="/root/backups/sillytavern"REMOTE_PATH="gdrive:SillyTavern_Backups"
#本地备份数量LOCAL_KEEP_COPIES=1#云盘备份数量CLOUD_KEEP_COPIES=5# ==================================================
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")ARCHIVE_NAME="st_backup_${TIMESTAMP}.tar.gz"LOCAL_FILE="${LOCAL_BACKUP_DIR}/${ARCHIVE_NAME}"
mkdir -p "${LOCAL_BACKUP_DIR}"
echo "=================================================="echo "[$(date)] -> 准备开始备份..."
# 1. 进入酒馆目录,如果失败则直接退出if ! cd "${ST_ROOT_DIR}"; then echo "[$(date)] -> 致命错误: 找不到目录 ${ST_ROOT_DIR}" exit 1fi
# 2. 停机echo "[$(date)] -> 暂停 SillyTavern 容器..."docker compose stop
# 3. 打包echo "[$(date)] -> 开始打包酒馆核心数据卷与配置..."tar -czf "${LOCAL_FILE}" data config plugins extensions docker-compose.ymlTAR_EXIT_CODE=$?
# 4.第一时间拉起echo "[$(date)] -> 容器重新恢复..."docker compose start
# 5. 校验打包文件if [ $TAR_EXIT_CODE -ge 2 ]; then echo "[$(date)] -> 致命错误: tar 打包发生严重错误 (退出码 $TAR_EXIT_CODE)!请检查日志。" rm -f "${LOCAL_FILE}" exit 1fi
# 检查文件是否存在,并且体积是否大于 10KBif [ ! -s "${LOCAL_FILE}" ] || [ $(stat -c%s "${LOCAL_FILE}") -lt 10240 ]; then echo "[$(date)] -> 致命错误: 备份文件不存在或体积过小!可能磁盘已满。" echo "[$(date)] -> 为保护云端历史备份不被脏数据替换,脚本已终止。" rm -f "${LOCAL_FILE}" exit 1fi
if [ $TAR_EXIT_CODE -eq 1 ]; then echo "[$(date)] -> 提示: tar 打包过程有警告 (通常是部分非关键目录不存在或文件被修改),但不影响核心数据。"fi
# 6. 优先清理本地备份echo "[$(date)] -> 清理本地多余备份 (仅保留最新 ${LOCAL_KEEP_COPIES} 份)..."cd "${LOCAL_BACKUP_DIR}"ls -1 st_backup_*.tar.gz 2>/dev/null | sort -r | tail -n +$((LOCAL_KEEP_COPIES + 1)) | xargs -r rm -f
# 7. 上传至 Google Driveecho "[$(date)] -> 开始上传至 Google Drive..."if rclone copy "${LOCAL_FILE}" "${REMOTE_PATH}" --drive-chunk-size 64M --transfers=1 -v; then echo "[$(date)] -> 上传成功!"else echo "[$(date)] -> 错误: rclone 上传失败,请检查网络或授权。" exit 1fi
# 8. 清理云盘备份echo "[$(date)] -> 清理 Google Drive 多余备份 (仅保留最新 ${CLOUD_KEEP_COPIES} 份)..."rclone lsf --files-only "${REMOTE_PATH}" 2>/dev/null \ | grep '^st_backup_.*\.tar\.gz$' \ | sort -r \ | tail -n +$((CLOUD_KEEP_COPIES + 1)) \ | while read -r filename; do # 规避 grep 匹配不到数据时 filename 为空导致误删的问题 if [ -n "$filename" ]; then echo "[$(date)] -> 正在彻底删除云端过期备份: ${filename}" rclone deletefile "${REMOTE_PATH}/${filename}" --drive-use-trash=false fi done
echo "[$(date)] -> Google Drive 自动化备份全流程顺利完成!"echo "=================================================="给脚本添加可执行权限
sudo chmod +x /opt/sillytavern/st_backup.sh手动测试脚本能否正常运行
/opt/sillytavern/st_backup.sh设置定时任务,自动备份
crontab -e如果是第一次使用,它会让你选择编辑器模式,输入 1,使用 nano 即可,填入以下表达式:
0 21 * * * /opt/sillytavern/st_backup.sh >> /var/log/st_backup.log 2>&1这个 cron 表达式的意思是每天 UTC 时间21点,即北京时间 5 点执行一次备份脚本。如果你的备份文件很大,每天都备份,服务器流量吃不消,也可以用下面这个每周一 5 点备份一次的 cron 表达式:
0 21 * * 0 /opt/sillytavern/st_backup.sh >> /var/log/st_backup.log 2>&1这是在你服务器时区是 UTC 的情况下,才对的上时差。你可以输入 date 查看服务器的时区。让 AI 帮你编写更个性化的 cron 表达式。
4.4 数据恢复
如果某天,你的服务器真的炸了(概率很低,但我真炸了一次,补偿了三个月),或者需要数据迁移,可以直接使用备份文件。
如果服务器里的数据还在,直接使用 /root/backups/sillytavern/ 里的本地备份就行。如果服务器彻底没了,去云盘下载最新的备份文件,用 SSH 客户端的文件传输功能手动上传到服务器。
假设你的备份文件已经放在了 /root/backups/sillytavern/ 目录:
同样先创建一个存放酒馆文件的目录
mkdir -p /opt/sillytavern解压备份文件到该目录
tar -xzf /root/backups/sillytavern/你的备份文件名 -C /opt/sillytavern进入目录
cd /opt/sillytavern如果新服务器上没有docker需要先安装,然后一键拉起容器
docker compose up -d你的所有角色、聊天记录、世界书、API 密钥设置、密码、甚至是安装过的第三方插件等等都会恢复。但是 Caddy 的配置文件不在备份范围内,需要再做一次第 3 节
5 读取日志
这一节的实际意义不大。我们是通过 docker compose 部署酒馆的,在 VPS 上,输入
docker compose logs -f --tail 20即可实时查看日志。
但是,我之前一直是在本地部署酒馆的,打开 termux 或者其它的命令行终端,就可以查看酒馆日志,查看报错信息,很方便。换成 VPS 后,有点不习惯,于是就找了一个通过 web 页面查看 docker 日志的轻量化项目,以下是效果预览:
个人认为部署完以后,还是比去 VPS 敲命令看日志要方便的,还能看到内存占用什么的。当然,如果你没有看日志的习惯,或者觉得折腾这些没必要,可以无视此节。
大致流程依旧是通过 docker compose 部署,使用 caddy 反向代理。
依次执行以下命令,新建目录,存放配置文件
mkdir -p /opt/dozzlecd /opt/dozzlenano docker-compose.yml把以下的配置信息粘贴进去
services: dozzle: image: amir20/dozzle:latest container_name: dozzle restart: unless-stopped environment: - DOZZLE_AUTH_PROVIDER=simple volumes: - /var/run/docker.sock:/var/run/docker.sock - ./users.yml:/data/users.yml - dozzle-data:/data ports: - "127.0.0.1:8088:8080"
volumes: dozzle-data:crtl + o 保存,回车,ctrl + x 退出
生成一个密码,作为你的登录密码。否则,外人如果知道你的网页,可以看到你的酒馆以及其它容器的日志。
docker run --rm amir20/dozzle generate 你的名字 --password "你的密码" > users.yml拉起容器
docker compose up -d我们接下来需要绑上域名
依旧先添加 A 记录

打开 Caddy 配置文件
nano /etc/caddy/Caddyfile把以下内容添加到尾部
dozzle.你的域名:8001 { reverse_proxy 127.0.0.1:8088 { flush_interval -1 }}现在,在浏览器输入 https://dozzle.你的域名 就可以实时查看你的酒馆日志了。
输入设置好的账号密码
另外,如果你希望和酒馆一样,只允许你自己的公网 ip 访问,可以在 caddy 的配置文件里添加白名单,改成:
dozzle.你的域名:8001 { # 1. 定义白名单规则:如果来访 IP 【不是】下面这些,就被标记为 @blocked @blocked { # 把下面的 IP 替换成你的公网 IP,可以写多个,用空格隔开 not remote_ip 192.168.1.100 114.114.114.114 }
# 2. 针对被标记为 @blocked 的访客,直接返回 403 报错 respond @blocked "Access Denied (IP not allowed)" 403
reverse_proxy 127.0.0.1:8088 { flush_interval -1 }}我自己还配置了 SSO 登录,但那有些过于复杂了,不放在本教程。而且,说实话,在你配置了 IP 白名单的情况下,所有安全措施都是在防你自己,别人连看到你网页的机会都没有。
如果这篇文章对你有帮助,欢迎分享给更多人!
部分信息可能已经过时












