本机 CC-Switch + Docker + Claude Code 连通配置教程(含全部脚本与操作详解)
本教程记录(Ubuntu)实际配置,教你为什么这么配、每行脚本是什么意思、日常怎么操作 。
更新日期:2026-10-09
合规声明:本文仅用于个人学习与开发调试,介绍如何在自有设备上配置本地代理工具。文中涉及的第三方接口、密钥与供应商信息均已脱敏,请勿用于任何商业用途或规避官方服务条款。使用前请自行确认所接入的接口与密钥符合相关平台的服务协议与当地法律法规,因使用不当产生的任何后果由使用者自行承担。
目录
- 总览:三个组件如何"联通"
- 配置文件全景图
- 从零部署:一键安装脚本逐段讲解
- [Dockerfile 逐行讲解](#Dockerfile 逐行讲解)
- 启动脚本逐行讲解
- [Claude Code 侧配置](#Claude Code 侧配置)
- [CC-Switch 侧配置与数据库](#CC-Switch 侧配置与数据库)
- [日常操作手册(每条命令 + 原因)](#日常操作手册(每条命令 + 原因))
- 故障排查表
- [卸载 / 重置](#卸载 / 重置)
- 安全加固
一、总览:三个组件如何"联通"
1.1 数据流(请求怎么走)
你敲 claude 命令
│
▼
Claude Code CLI (v2.1.x,npm 全局安装)
│ 读取 ~/.claude/settings.json
│ ANTHROPIC_BASE_URL = http://127.0.0.1:15721
│ ANTHROPIC_AUTH_TOKEN = PROXY_MANAGED
│
▼ (本机回环,不经外网)
CC-Switch 本地代理(Docker 容器,--network host)
│ 监听 127.0.0.1:15721
│ ① 拦截请求,② 按"当前启用的供应商"改写 base_url / token / 模型名
│
▼ (走外网)
上游供应商:https://api.deepseek.com/anthropic/v1/messages
一句话:Claude Code 不直连官方,而是打到本机 15721 端口;Docker 里的 CC-Switch 当中间代理,把请求转发给第三方 Anthropic 兼容接口(当前是 DeepSeek),并负责注入密钥、改写模型名。
1.2 组件职责表
| 组件 | 角色 | 本机版本 / 位置 | 关键点 |
|---|---|---|---|
| Claude Code | 使用方,发请求到本地代理 | v2.1.x;/usr/bin/claude(软链到 npm 全局包) |
只改两个环境变量 |
| CC-Switch | 本地代理 + 供应商切换 GUI | v3.20.4;Docker 镜像 cc-switch:v3.20.4 |
跑在容器里,监听 15721 |
| Docker | CC-Switch 的运行载体 | docker.io(apt 安装) |
隔离依赖、干净可卸载 |
1.3 为什么用 Docker 跑 CC-Switch(而不是直接装 .deb)
- 依赖难装全 :CC-Switch 是 Tauri 写的 GUI,前端用 WebKitGTK 渲染,依赖
libwebkit2gtk-4.1-0等一整套系统库,不同发行版/版本参差不齐,宿主直接装 deb 容易缺库、装不干净。 - 隔离可卸载 :把所有依赖圈进 Ubuntu 22.04 容器,宿主机只留一个 Docker;卸载时
docker rmi+rm -rf就干净了。 - 配置持久化 :容器删了无所谓,数据通过挂载存在宿主机
~/.cc-switch。
二、配置文件全景图
| 文件 / 目录 | 作用 | 谁写的 |
|---|---|---|
~/.claude/settings.json |
Claude Code 环境变量(指向代理) | CC-Switch 接管后写入 |
~/.claude.json |
Claude Code 运行状态/统计 | Claude Code 自己 |
~/.cc-switch/ |
CC-Switch 数据目录 | CC-Switch |
~/.cc-switch/settings.json |
CC-Switch 应用设置(代理开关、当前供应商) | CC-Switch |
~/.cc-switch/cc-switch.db |
SQLite:供应商、密钥、代理参数、用量 | CC-Switch |
~/.cc-switch/backups/ |
数据库每日自动备份 | CC-Switch |
~/.cc-switch/logs/cc-switch.log |
运行日志(能看到转发目标) | CC-Switch |
~/cc-switch-docker/Dockerfile |
构建 CC-Switch 镜像 | 手动/安装脚本 |
~/cc-switch.sh |
简化启动脚本(前台 GUI) | 手动 |
~/CCSwitch_Start.sh |
完整启动脚本(后台 + host 网络 + 等端口) | 手动 |
~/.bashrc |
末尾的 alias cc-switch=... |
安装脚本追加 |
/etc/docker/daemon.json |
Docker 国内镜像加速 | 安装脚本写入 |
~/.local/share/applications/cc-switch.desktop |
应用菜单/桌面一键启动 | 手动 |
三、从零部署:一键安装脚本逐段讲解
下面是本机曾经用过的部署脚本 ~/桌面/install_ccswitch_docker_v3204.sh 全文(用户名已用占位符代替)。这台机器已经装完了,你一般不需要重跑,这里逐段讲清楚它做了什么、为什么,方便你以后重装或迁移到新机器。
3.1 脚本全文
bash
#!/bin/bash
set -e
echo "===== CC-Switch v3.20.4 Docker 一键部署脚本开始 ====="
# 1. 更新源、安装docker.io
echo "[1/8] 安装 Docker"
sudo apt-get update
sudo apt-get install -y docker.io
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -aG docker $USER
newgrp docker <<EOF
echo "Docker用户组已添加,当前终端临时生效"
EOF
# 2. 创建工作目录
echo "[2/8] 创建工作目录 ~/cc-switch-docker"
mkdir -p ~/cc-switch-docker
cd ~/cc-switch-docker
# 3. 下载 CC-Switch v3.20.4 deb包
echo "[3/8] 下载 CC-Switch v3.20.4 deb安装包"
wget -O cc-switch.deb https://github.com/farion1231/cc-switch/releases/download/v3.20.4/CC-Switch-v3.20.4-Linux-x86_64.deb
# 4. 解压deb包
echo "[4/8] 解压deb安装包"
rm -rf cc-switch-extract
dpkg -x cc-switch.deb cc-switch-extract/
ls cc-switch-extract/usr/bin/
# 5. 配置docker镜像加速器
echo "[5/8] 配置Docker国内镜像加速"
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://docker.m.daocloud.io",
"https://dockerproxy.com",
"https://docker.nju.edu.cn"
]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
docker info | grep -A 5 "Registry Mirrors"
# 6. 写入Dockerfile
echo "[6/8] 生成Dockerfile"
cat > Dockerfile << 'EOF'
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive
# 安装 CC-Switch 运行时依赖
RUN apt-get update && apt-get install -y \
libwebkit2gtk-4.1-0 \
libgtk-3-0 \
libayatana-appindicator3-1 \
libnotify4 \
libnss3 \
libxss1 \
libxtst6 \
xdg-utils \
libatspi2.0-0 \
libuuid1 \
libsecret-1-0 \
fonts-noto-cjk \
locales \
libfuse2 \
ca-certificates \
&& rm -rf /var/lib/apt/lists/* \
&& locale-gen zh_CN.UTF-8
ENV LANG=zh_CN.UTF-8
ENV LC_ALL=zh_CN.UTF-8
ENV DEBIAN_FRONTEND=
# 复制解压后的 CC-Switch 文件到容器中
COPY cc-switch-extract/ /
# 添加执行权限
RUN chmod +x /usr/bin/cc-switch
# 启动 CC-Switch
CMD ["/usr/bin/cc-switch"]
EOF
# 7. 构建镜像
echo "[7/8] 构建cc-switch docker镜像"
docker build -t cc-switch:v3.20.4 .
# 8. 创建全局启动脚本 ~/cc-switch.sh
echo "[8/8] 创建启动脚本并配置bash别名"
cat > ~/cc-switch.sh << 'EOF'
#!/bin/bash
xhost +local:docker > /dev/null 2>&1
docker run --rm \
-e DISPLAY=$DISPLAY \
-e XDG_RUNTIME_DIR=/tmp \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-v $HOME/.cc-switch:/root/.cc-switch \
cc-switch:v3.20.4
EOF
chmod +x ~/cc-switch.sh
# 添加别名到.bashrc,避免重复写入
grep -q 'alias cc-switch="~/cc-switch.sh"' ~/.bashrc || echo 'alias cc-switch="~/cc-switch.sh"' >> ~/.bashrc
source ~/.bashrc
echo "====================================="
echo "✅ CC-Switch v3.20.4 Docker部署完成!"
echo "使用方式:"
echo " 终端输入 cc-switch 即可启动图形界面"
echo "重要说明:"
echo " 1. GUI图形转发,Wayland会话极易闪退,登录时务必选择 Ubuntu on Xorg"
echo " 2. 配置文件持久化挂载在宿主机 ~/.cc-switch"
echo " 3. 如需卸载:docker rmi cc-switch:v3.20.4 && rm -rf ~/cc-switch-docker ~/cc-switch.sh"
echo "====================================="
3.2 逐段讲解(每步做了什么、为什么)
| 步骤 | 命令 | 为什么这么做 |
|---|---|---|
set -e |
--- | 任一命令出错就立刻停,避免半成品环境 |
| 第 1 步 | apt-get install docker.io |
Ubuntu 官方源里的 Docker 引擎包(docker.io 是包名,docker 是命令名) |
systemctl enable docker |
开机自启 dockerd | |
usermod -aG docker $USER |
把当前用户加进 docker 组,免 sudo 才能跑 docker 命令 |
|
newgrp docker |
组身份默认要重新登录才生效;newgrp 开一个临时子 shell 立即生效(否则接下来 docker build 会权限不足) |
|
| 第 2 步 | mkdir -p ~/cc-switch-docker |
统一的工作目录,放 deb、解包产物、Dockerfile |
| 第 3 步 | wget -O cc-switch.deb <url> |
从 GitHub Releases 下载官方 deb |
| 第 4 步 | dpkg -x cc-switch.deb cc-switch-extract/ |
关键点 :不是 dpkg -i 安装到宿主机,而是解包,把程序文件抽出来,稍后 COPY 进容器。宿主机上不残留任何 CC-Switch 文件 |
| 第 5 步 | 写 /etc/docker/daemon.json |
国内拉 ubuntu:22.04 基础镜像很慢,配镜像加速源;daemon-reload + restart 让它生效 |
| 第 6 步 | 写 Dockerfile | 见下一章逐行讲解 |
| 第 7 步 | docker build -t cc-switch:v3.20.4 . |
构建镜像,标签 cc-switch:v3.20.4(后面脚本就靠这个名字) |
| 第 8 步 | 写 ~/cc-switch.sh + chmod +x |
一个能 ./cc-switch.sh 直接跑的启动脚本 |
| `grep -q ... | ||
source ~/.bashrc |
让当前 shell 立即拿到别名 |
⚠️ 注意:脚本第 8 步生成的
~/cc-switch.sh是旧版 (没有WEBKIT_DISABLE_DMABUF_RENDERER=1)。本机后来手工补了这一行,以第 5 章"当前磁盘上的版本"为准。
四、Dockerfile 逐行讲解
文件:~/cc-switch-docker/Dockerfile(当前磁盘全文,路径中的用户名已占位)
dockerfile
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive
# 安装 CC-Switch 运行时依赖
RUN apt-get update && apt-get install -y \
libwebkit2gtk-4.1-0 \
libgtk-3-0 \
libayatana-appindicator3-1 \
libnotify4 \
libnss3 \
libxss1 \
libxtst6 \
xdg-utils \
libatspi2.0-0 \
libuuid1 \
libsecret-1-0 \
fonts-noto-cjk \
locales \
libfuse2 \
ca-certificates \
&& rm -rf /var/lib/apt/lists/* \
&& locale-gen zh_CN.UTF-8
ENV LANG=zh_CN.UTF-8
ENV LC_ALL=zh_CN.UTF-8
ENV DEBIAN_FRONTEND=
# 复制解压后的 CC-Switch 文件到容器中
COPY cc-switch-extract/ /
# 添加执行权限
RUN chmod +x /usr/bin/cc-switch
# 启动 CC-Switch
CMD ["/usr/bin/cc-switch"]
逐行解释:
| 行 | 作用 | 为什么 |
|---|---|---|
FROM ubuntu:22.04 |
基础镜像 | 选和 CC-Switch deb 目标一致的老 LTS,库版本匹配 WebKitGTK 4.1 |
ENV DEBIAN_FRONTEND=noninteractive |
关掉 apt 交互提示 | 否则装库时可能卡在询问弹窗,构建会挂住 |
libwebkit2gtk-4.1-0 |
WebKit 渲染核心 | Tauri/Linux GUI 的 WebView 引擎,缺了直接起不来 |
libgtk-3-0 |
GTK 窗口框架 | 窗口、菜单、托盘依赖 |
libayatana-appindicator3-1 |
托盘图标 | showInTray 设置生效的前提 |
libnotify4 |
桌面通知 | 应用发通知用 |
libnss3 / libxss1 / libxtst6 |
浏览器/网络/输入相关 | WebKitGTK 的依赖链 |
xdg-utils |
xdg-open 等工具 | 打开链接/目录 |
libatspi2.0-0 |
无障碍接口 | GTK 应用常需 |
libuuid1 / libsecret-1-0 |
UUID / 密钥环 | 应用生成 ID、存密钥 |
fonts-noto-cjk |
中文字体 | 不装界面中文全是方块 |
locales + locale-gen zh_CN.UTF-8 |
生成中文 locale | 配合下面 LANG 变量,界面中文 |
rm -rf /var/lib/apt/lists/* |
清 apt 缓存 | 减小镜像体积 |
ENV LANG/LC_ALL=zh_CN.UTF-8 |
设默认语言 | 应用按中文显示 |
ENV DEBIAN_FRONTEND= |
还原环境变量 | 避免影响容器运行期 |
COPY cc-switch-extract/ / |
把解包产物铺到根目录 | deb 解包出来是 usr/bin/cc-switch 等,/ 目标正好合并进 /usr/bin |
RUN chmod +x /usr/bin/cc-switch |
加执行权限 | 解包后可能没执行位 |
CMD ["/usr/bin/cc-switch"] |
容器启动即运行 | 用 exec 形式,容器前台进程就是 cc-switch |
五、启动脚本逐行讲解
5.1 简化版 ~/cc-switch.sh(当前磁盘全文,路径中的用户名已占位)
bash
#!/bin/bash
xhost +local:docker > /dev/null 2>&1
docker run --rm \
-e DISPLAY=$DISPLAY \
-e XDG_RUNTIME_DIR=/tmp \
-e WEBKIT_DISABLE_DMABUF_RENDERER=1 \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-v $HOME/.cc-switch:/root/.cc-switch \
cc-switch:v3.20.4
逐行解释:
| 行 | 作用 | 为什么 |
|---|---|---|
xhost +local:docker |
授权本机 docker 连接 X 服务器 | 容器里的 GUI 要在宿主机屏幕画窗口,但 X 默认只认当前会话,需显式放行;local:docker 只放行"本机",不放行远程 |
> /dev/null 2>&1 |
吞掉输出 | xhost 成功/失败都会打印,避免刷屏 |
docker run --rm |
一次性容器,退出即删 | 这个脚本跑的是前台 GUI,关掉窗口容器就没了,不留垃圾 |
-e DISPLAY=$DISPLAY |
把显示号传给容器 | 容器要往哪个 X 屏画,DISPLAY 告诉它(一般是 :0) |
-e XDG_RUNTIME_DIR=/tmp |
指定 runtime 目录 | 容器里没有 systemd 的 user runtime 目录,GTK/WebKit 需要这个变量指向可写位置,否则报错 |
-e WEBKIT_DISABLE_DMABUF_RENDERER=1 |
禁用 WebKitGTK 的 DMABUF 渲染 | 规避部分 GPU/驱动下花屏、白屏、闪退(Tauri WebKit 在 Linux 的老毛病) |
-v /tmp/.X11-unix:/tmp/.X11-unix |
共享 X11 socket | 容器连 X server 的实际通道,不挂这个 DISPLAY 设了也没用 |
-v $HOME/.cc-switch:/root/.cc-switch |
挂载数据目录 | 容器以 root 运行,应用把数据写在 /root/.cc-switch;挂到宿主机 ~/.cc-switch 后,删容器不丢配置(密钥、供应商都在这里) |
cc-switch:v3.20.4 |
用哪个镜像 | 与 build 时的标签一致 |
注意:这个脚本没写
--network host,默认 bridge 网络下代理绑定的127.0.0.1:15721只在容器内部,宿主机访问不到。所以它只适合"打开 GUI 看界面/改配置",要起代理请用 5.2 的完整版脚本。
5.2 完整版 ~/CCSwitch_Start.sh(当前磁盘全文,重点,路径中的用户名已占位)
bash
#!/bin/bash
# CCSwitch 一键启动脚本
# 位置:~/CCSwitch_Start.sh(用户名已占位)
newgrp docker <<CMD
# ---- X11 显示授权 ----
xhost +local:docker > /dev/null 2>&1
echo "=== CCSwitch 启动中 ==="
IMAGE="cc-switch:v3.20.4"
NAME="cc-switch"
CONFIG_DIR="\$HOME/.cc-switch"
# ---- 1. 清理同名容器 ----
if docker ps -a --format '{{.Names}}' | grep -q "^\${NAME}\$"; then
echo "清理旧容器 \${NAME} ..."
docker stop "\${NAME}" > /dev/null 2>&1 || true
docker rm "\${NAME}" > /dev/null 2>&1 || true
fi
# ---- 2. 清理同镜像残留容器 ----
OLD=\$(docker ps -a --filter "ancestor=\${IMAGE}" -q)
if [ -n "\$OLD" ]; then
echo "清理残留容器 ..."
docker stop \$OLD > /dev/null 2>&1 || true
docker rm \$OLD > /dev/null 2>&1 || true
fi
# ---- 3. 启动唯一实例(host 模式)----
echo "启动 \${NAME} ..."
docker run -d --name "\${NAME}" \
--network host \
-e DISPLAY=\$DISPLAY \
-e XDG_RUNTIME_DIR=/tmp \
-e WEBKIT_DISABLE_DMABUF_RENDERER=1 \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-v "\${CONFIG_DIR}:/root/.cc-switch" \
"\${IMAGE}"
# ---- 4. 等待代理端口 ----
echo "等待代理端口 15721 ..."
READY=0
for i in \$(seq 1 60); do
if ss -tln 2>/dev/null | grep -q '127.0.0.1:15721'; then
echo "✓ 代理已就绪:127.0.0.1:15721"
READY=1
break
fi
sleep 1
done
# ---- 5. 结果提示 ----
if [ "\$READY" -eq 1 ]; then
echo "=== 启动完成 ==="
echo "提示:Claude Code 使用前,请确认 CCSwitch 界面中目标供应商已启用。"
else
echo ""
echo "⚠ 代理端口 15721 未监听。"
echo "请在 CCSwitch 界面中打开【代理 / 本地路由】开关,"
echo "并确认目标供应商卡片已点击【启用】。"
echo ""
fi
CMD
逐段解释:
| 段 | 作用 | 为什么 |
|---|---|---|
newgrp docker <<CMD ... CMD |
在 docker 组环境里跑整段脚本 | usermod -aG docker 后,新开的终端才认组;用 newgrp + heredoc 让整段命令立即拥有 docker 权限,脚本可被普通用户直接双击执行 |
变量 IMAGE/NAME/CONFIG_DIR |
集中定义 | 改一个地方就够,且后续要 \$ 转义------因为 heredoc 里 ${...} 会被外层 shell 提前展开,转义后保留给 newgrp 子 shell 展开 |
| 第 1 步 清理同名容器 | docker ps -a 查所有容器(含停止的),grep -q "^\$NAME\$" 精确匹配名字 |
防止上次没删干净的 cc-switch 占着名字导致 docker run --name 冲突 |
| ` | true` | |
| 第 2 步 清理残留容器 | --filter "ancestor=$IMAGE" 找出所有用这个镜像的容器 |
除了名字 cc-switch,还可能有用同一镜像启动的其他残留实例,一并清掉,避免端口 15721 被占 |
第 3 步 docker run -d |
后台启动,打印容器 ID 后返回 | -d 让它常驻,脚本才能继续走"等端口"逻辑 |
--network host |
用宿主机网络栈 | 关键:host 模式下容器里监听 127.0.0.1:15721 就等于宿主机监听,Claude Code(跑在宿主机)才能通过回环地址连上。默认 bridge 网络下容器自己的 127.0.0.1 是隔离的 |
| 挂载 / env | 同 5.1 | 见 5.1 的逐行表 |
| 第 4 步 等端口循环 | ss -tln 看监听端口,grep 127.0.0.1:15721,最多 seq 1 60 即 60 秒 |
代理是 GUI 应用启动后异步 拉起的,docker run -d 返回时端口可能还没监听;循环等到就绪,保证"脚本跑完 = 代理可用" |
| 第 5 步 结果提示 | 按 READY 分支提示 | 没就绪时给用户明确指引(开代理开关、启用供应商) |
5.3 两个脚本怎么选
| 场景 | 用哪个 | 原因 |
|---|---|---|
| 只想打开 CC-Switch 界面看配置、加供应商、改设置 | ~/cc-switch.sh(或别名 cc-switch) |
前台 GUI,用完即删容器,无需常驻代理 |
| 要让 Claude Code 真正能跑(起代理) | ~/CCSwitch_Start.sh |
有 --network host 才能把 15721 暴露给宿主机,且后台常驻 |
日常最省事的姿势:直接跑
~/CCSwitch_Start.sh把代理起来;要看界面再从桌面启动器或菜单点开(两者都调用的完整版脚本,见下)。
5.4 桌面一键启动入口
文件:~/.local/share/applications/cc-switch.desktop(~/桌面/CCSwitch.desktop 内容相同,路径中的用户名已占位)
ini
[Desktop Entry]
Type=Application
Name=CC-Switch一键启动
Comment=Docker CC-Switch
Exec=gnome-terminal -- bash -c "bash ~/CCSwitch_Start.sh; exec bash"
Icon=gnome-terminal
Terminal=false
Categories=Utility;
Path=~
````Exec=gnome-terminal -- bash -c "...; exec bash"`:借一个终端窗口跑完整版启动脚本,跑完 `exec bash` 保持窗口不关,方便看"代理已就绪"的提示。
- `Path=~`:工作目录固定,避免相对路径出问题。
- 另有 `cc-switch-handler.desktop` 是给 `ccswitch://` 深链 URL 用的注册项(`NoDisplay=true`,不在菜单显示),由 CC-Switch 首次启动时生成,不用管。
---
## 六、Claude Code 侧配置
### 6.1 安装方式(现状)
```bash
# 全局 npm 安装,装在 /usr/lib/node_modules/@anthropic-ai/claude-code
# 可执行文件软链:/usr/bin/claude -> ../lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe
npm ls -g --depth=0 # 看到 @anthropic-ai/claude-code@2.1.x
.bashrc 里还有 export PATH=~/.npm-global/bin:$PATH,是为了让 ~/.npm-global/bin 下可能存在的 npm 全局命令可被找到(本机 claude 主链接在 /usr/bin/claude,这条 PATH 是历史兜底)。
6.2 核心配置 ~/.claude/settings.json
json
{
"env": {
"ANTHROPIC_BASE_URL": "http://127.0.0.1:15721",
"ANTHROPIC_AUTH_TOKEN": "PROXY_MANAGED"
}
}
逐项解释:
| 字段 | 值 | 为什么 |
|---|---|---|
ANTHROPIC_BASE_URL |
http://127.0.0.1:15721 |
让 Claude Code 的所有 API 请求打到本地 CC-Switch 代理,而不是官方 https://api.anthropic.com |
ANTHROPIC_AUTH_TOKEN |
PROXY_MANAGED |
占位符,表示"密钥由代理托管"。CC-Switch 接管后,会在转发时把请求头里的 token 替换成当前供应商的真实 key,所以你切供应商时不用改这里 |
为什么用
PROXY_MANAGED而不是直接填 key?------ 好处是切换供应商零改动:key 都存在 CC-Switch 的库里,代理动态注入。Claude Code 侧永远是"发到 15721 + 占位 token"这两行。
6.3 代理"接管"机制(CC-Switch 做了什么)
从日志 ~/.cc-switch/logs/cc-switch.log 能看到接管过程:
[SRV-001] 代理服务器启动于 127.0.0.1:15721
已同步 Claude Token 到数据库 (provider: fd3c7ea3-****)
Claude Live 配置已接管,代理地址: http://127.0.0.1:15721
[Claude] >>> 请求目标: https://api.deepseek.com/anthropic/v1/messages (model=deepseek-v4-pro)
即:CC-Switch 启动后,把 ~/.claude/settings.json 的 env 接管成上面的代理配置,同时把当前供应商(DeepSeek)的 key 同步进自己的库,转发时再动态填回请求头。
七、CC-Switch 侧配置与数据库
7.1 应用设置 ~/.cc-switch/settings.json(关键字段)
json
{
"enableLocalProxy": true,
"proxyConfirmed": true,
"enableClaudePluginIntegration": true,
"skipClaudeOnboarding": true,
"sessionAutoSyncEnabled": true,
"language": "zh",
"currentProviderClaude": "fd3c7ea3-****-****-****-************"
}
| 字段 | 值 | 作用 / 为什么 |
|---|---|---|
enableLocalProxy |
true |
本地代理总开关 。为 false 时 15721 不监听,Claude Code 全断 |
proxyConfirmed |
true |
首次启用代理时的确认弹窗已点过 |
enableClaudePluginIntegration |
true |
允许接管 Claude Code 的 settings.json |
skipClaudeOnboarding |
true |
跳过 Claude Code 首次引导 |
sessionAutoSyncEnabled |
true |
自动同步会话历史到库里(供用量统计) |
currentProviderClaude |
UUID(已脱敏) | 当前启用的 Claude 供应商 ID,指向 providers 表 |
language |
zh |
界面中文 |
7.2 数据库 ~/.cc-switch/cc-switch.db
SQLite 3,主要表:
| 表 | 作用 |
|---|---|
providers |
供应商(含密钥 settings_config、is_current 标记) |
proxy_config |
代理参数(按 app_type 一行) |
proxy_request_logs |
每次请求的用量/耗时/费用 |
usage_daily_rollups |
按天聚合的用量 |
session_log_sync / session_usage_dedup |
会话同步与去重 |
settings / skills / mcp_servers / skill_repos / prompts / profiles |
杂项配置 |
当前供应商(唯一启用) :DeepSeek,is_current=1:
名称: DeepSeek
分类: cn_official(自定义,Anthropic 兼容)
Base URL: https://api.deepseek.com/anthropic
Token: sk-****(存于 providers.settings_config.env.ANTHROPIC_AUTH_TOKEN)
模型映射:
ANTHROPIC_DEFAULT_HAIKU_MODEL → deepseek-v4-flash
ANTHROPIC_DEFAULT_OPUS_MODEL → deepseek-v4-pro
ANTHROPIC_DEFAULT_SONNET_MODEL → deepseek-v4-pro
ANTHROPIC_MODEL → deepseek-v4-pro
含义:在 Claude Code 里无论选 opus 还是 sonnet 模型,实际都被映射到
deepseek-v4-pro。
当前代理参数 (proxy_config 里 app_type='claude' 那一行):
| 参数 | 值 | 含义 |
|---|---|---|
listen_address / listen_port |
127.0.0.1 / 15721 |
代理监听地址(与脚本里的等待端口一致) |
enabled / proxy_enabled |
1 |
代理启用 |
max_retries |
6 |
上游失败重试次数 |
streaming_first_byte_timeout |
90 |
流式首字节超时(秒) |
streaming_idle_timeout |
180 |
流式空闲超时 |
auto_failover_enabled |
0 |
自动故障切换(当前关) |
八、日常操作手册(每条命令 + 原因)
8.1 启动代理(最常用)
bash
bash ~/CCSwitch_Start.sh
- 为什么用
bash而不是./:不依赖文件执行位,直接解释执行。 - 预期输出:
✓ 代理已就绪:127.0.0.1:15721+=== 启动完成 ===。
也可以用桌面图标 / 应用菜单里的「CC-Switch一键启动」点开(等价操作)。
8.2 停止 / 重启 / 删除容器
bash
docker stop cc-switch # 停代理(Claude Code 会暂时连不上,属正常)
docker start cc-switch # 再启动(容器还在,直接 start 比重新 run 快)
docker restart cc-switch # 重启(改配置后想快速生效可用)
docker rm -f cc-switch # 强制删除容器(下次用 Start 脚本重新 run)
- 为什么
stop后start能直接恢复:容器还在(-d建的,不是--rm),数据在挂载卷里,重启即恢复代理。
8.3 查看状态 / 日志 / 端口
bash
docker ps # 看运行中的容器(应有 cc-switch)
docker ps -a # 看所有容器(含已停止)
docker inspect cc-switch \
--format '{{.HostConfig.NetworkMode}}' # 确认网络模式是 host
docker inspect cc-switch \
--format '{{range .Mounts}}{{.Source}}->{{.Destination}} {{end}}' # 看挂载
ss -tlnp | grep 15721 # 看 15721 是否在监听
tail -f ~/.cc-switch/logs/cc-switch.log # 实时看转发目标 / 报错
docker logs cc-switch # 看容器的 stdout(和上面的日志不同源)
- 为什么
ss -tlnp | grep 15721是核心体检命令:代理是否活、Claude Code 能否连上,全看这一行有没有LISTEN 127.0.0.1:15721。 - 为什么日志看两处:
~/.cc-switch/logs/是应用内部日志(能看到>>> 请求目标),docker logs是进程 stdout(程序崩溃时的报错)。
8.4 端到端验证(确认整条链路通)
bash
claude -p "你好,请回复 OK 两个字母"
- 为什么这样测:
-p是非交互单轮,走完"Claude Code → 15721 → DeepSeek → 返回"整条链路,能立刻看出通不通。
8.5 切换供应商(在应用界面操作)
不用命令行,打开 CC-Switch 界面:
bash ~/cc-switch.sh打开界面(或启动脚本起来后 GUI 窗口就在)。- 在供应商列表点击目标供应商卡片【启用】/ 设为当前。
- 它自动改写
~/.claude/settings.json并切换 token,下一次claude请求即走新供应商,无需重启。
为什么切完不用改
~/.claude/settings.json:那里是PROXY_MANAGED占位,代理按is_current供应商动态填 key 和 base_url。
8.6 新增供应商(在应用界面操作)
- 打开界面:
bash ~/cc-switch.sh - 界面「添加供应商」→ 选 API 格式 = Anthropic。
- 填 Base URL(如
https://api.xxx.com/anthropic)、API Key、模型映射(opus/sonnet/haiku → 该供应商对应模型名)。 - 保存后点【启用】。
为什么必须选 Anthropic 格式:Claude Code 只会发 Anthropic 协议的请求,代理只是原样转发 + 换域名换 key,不做协议翻译。
8.7 查库 / 备份 / 恢复
bash
# 查供应商列表(仅展示脱敏后的字段,不输出密钥原文)
python3 - <<'PY'
import sqlite3, re
db = sqlite3.connect('~/.cc-switch/cc-switch.db')
def m(s):
return re.sub(r'(sk-[A-Za-z0-9_-]{4})[A-Za-z0-9_-]+', r'\1****', s or '')
for r in db.execute("SELECT app_type,name,category,is_current,website_url,settings_config FROM providers ORDER BY app_type"):
print(r[0], '|', r[1], '|', r[2], '| current=', r[3], '|', m(r[4]))
print(' ', m(r[5])[:120])
PY
# 手动备份数据库(CC-Switch 本身每天也会自动备份到 ~/.cc-switch/backups/)
cp ~/.cc-switch/cc-switch.db ~/.cc-switch/cc-switch.db.manual.bak
# 恢复(先停容器再覆盖,避免正在写入)
docker stop cc-switch
cp ~/.cc-switch/backups/db_backup_YYYYMMDD_HHMMSS.db ~/.cc-switch/cc-switch.db
bash ~/CCSwitch_Start.sh
- 为什么恢复前要
docker stop:应用运行时会持续写库,直接覆盖可能损坏/被回写覆盖。
8.8 重建镜像(改了 Dockerfile / 升级版本时)
bash
cd ~/cc-switch-docker
# 换版本时:重新下载对应版本 deb 并 dpkg -x 解包覆盖 cc-switch-extract/
docker build -t cc-switch:v3.20.4 .
docker rm -f cc-switch # 停旧容器
bash ~/CCSwitch_Start.sh # 用新镜像重启
- 为什么先
docker rm -f再重启:旧容器仍用旧镜像,手动删更直接。
九、故障排查表
| 现象 | 可能原因 | 处理命令 / 动作 |
|---|---|---|
claude 报连不上 127.0.0.1:15721 |
代理没起 / 容器没跑 | `ss -tlnp |
| Start 脚本提示「15721 未监听」 | 界面里【代理/本地路由】开关关着,或没启用供应商 | 打开界面确认开关 + 供应商卡片已启用,再重跑 |
| GUI 白屏 / 花屏 / 闪退 | DMABUF 渲染问题(Wayland 下尤其常见) | 登录时选 "Ubuntu on Xorg" ;确认脚本里有 WEBKIT_DISABLE_DMABUF_RENDERER=1 |
docker: permission denied |
用户不在 docker 组,或组未生效 | groups 看有没有 docker;没有则 sudo usermod -aG docker $USER 后重新登录 |
端口被占 / --name 冲突 |
残留容器 | docker ps -a;docker rm -f cc-switch |
| 请求报 401 / 认证失败 | 供应商 key 失效或没启用 | 查 tail -f ~/.cc-switch/logs/cc-switch.log;界面重填 key |
| 拉镜像/构建慢 | 网络问题 | 检查 /etc/docker/daemon.json 的镜像加速是否还在 |
| 界面中文乱码 | 容器里缺中文字体 | 确认 Dockerfile 有 fonts-noto-cjk + locale-gen zh_CN.UTF-8 |
更新检查报错(dl.ccswitch.io / GitHub) |
网络不通 | 无害,忽略;不影响代理功能 |
十、卸载 / 重置
bash
# 1. 停并删容器
docker rm -f cc-switch
# 2. 删镜像
docker rmi cc-switch:v3.20.4
# 3. 删部署产物(脚本 + 工作目录)
rm -rf ~/cc-switch-docker ~/cc-switch.sh ~/CCSwitch_Start.sh
# 4. 删数据目录(⚠ 含供应商密钥,确认后执行)
rm -rf ~/.cc-switch
# 5. 删别名与桌面入口(如需要)
# 编辑 ~/.bashrc 删除 alias cc-switch="~/cc-switch.sh" 一行
rm -f ~/.local/share/applications/cc-switch.desktop ~/桌面/CCSwitch.desktop
# 6. 让 Claude Code 恢复直连官方
# 删除 ~/.claude/settings.json 里的 env 段,或直接删除该文件
rm -f ~/.claude/settings.json
十一、安全加固
-
收紧配置目录权限 (当前
~/.cc-switch是755,其他用户可读,内含明文 key):bashchmod 700 ~/.cc-switch chmod 600 ~/.cc-switch/cc-switch.db ~/.cc-switch/settings.json- 为什么:供应商 API Key 明文存在
cc-switch.db里,755意味着同机其他账号能读到。
- 为什么:供应商 API Key 明文存在
-
xhost +local:docker的影响:放开了本机 docker 对 X 显示的访问。仅建议在个人单用户桌面环境使用;若有多用户,应改用更细粒度的 X 授权方式。 -
密钥脱敏 :任何教程/分享里,凡出现
sk-开头的 key 都应打码(本教程已用sk-****代替)。