Claude Code Router 配置存储深入解析:config.sqlite 的位置、迁移机制与安全操作指南
【免费下载链接】claude-code-routerOne local control plane for every AI agent: route across models, fuse new capabilities, orchestrate tools, and stay fully in control.项目地址: https://gitcode.com/GitHub_Trending/cl/claude-code-router
config.sqlite 是 Claude Code Router(CCR)桌面应用维护运行时配置的 SQLite 数据库,也是判断“当前配置到底生效在哪”的关键。本文将以官方文档 configuration-file.md 为骨架,结合仓库源码(app-paths.ts、constants.ts、config-repository.ts、entrypoint.sh),讲清楚各平台数据库默认位置、Docker 环境的数据持久化方式、旧版config.json的一次性迁移语义,以及如何在安全前提下完成备份与修改——读完你既能快速找到自己的配置数据库,也能理解 CCR 内部“JSON 时代 → SQLite 时代”的演进逻辑。
背景:CCR 的运行时配置为什么存放在 SQLite
CCR(Claude Code Router)是一个“本地 AI Agent 控制面”,负责在多个模型 Provider 之间路由请求、编排工具。与很多仅用单个 JSON 文件存配置的工具不同,CCR 的运行时配置统一存放在一个 SQLite 数据库文件中,即config.sqlite。
从源码看,配置数据库文件的常量在 constants.ts 中定义:
export const APP_CONFIG_DB_FILE = path.join(CONFIGDIR, "config.sqlite");而CONFIGDIR由 app-paths.ts 按平台解析:
export function resolveRuntimeConfigDir(): string { if (process.platform === "win32") { return path.join(resolveRuntimeAppPath("appData"), APP_STORAGE_NAME); } return path.join(resolveRuntimeAppPath("home"), `.${APP_STORAGE_NAME}`); }其中APP_STORAGE_NAME固定为"claude-code-router"(app-paths.ts)。也就是说,配置目录的命名规则是“家目录下的隐藏目录”或“系统 AppData 目录下的应用目录”,这也是官方文档默认位置表格的代码来源。
各平台默认位置一览
官方文档给出的默认位置如下,这三行也是排查问题时的“标准答案”:
| 运行环境 | 配置数据库默认路径 |
|---|---|
| macOS / Linux | ~/.claude-code-router/config.sqlite |
| Windows | %APPDATA%\claude-code-router\config.sqlite |
| Docker | /data/.claude-code-router/config.sqlite |
macOS / Linux:家目录下的隐藏目录
在非 Windows 平台,配置目录固定在家目录下的~/.claude-code-router,不受XDG_CONFIG_HOME影响。这一点与许多遵循 XDG 规范的工具不同,属于 CCR 自己的约定:即使你在 Linux 上设置了XDG_CONFIG_HOME,配置仍然落在~/.claude-code-router/config.sqlite。
Windows:优先使用%APPDATA%
在 Windows 上,配置目录解析为appData下的claude-code-router。appData的取值逻辑见 app-paths.ts:
function fallbackAppDataDir(): string { if (process.platform === "win32") { return process.env.APPDATA || process.env.LOCALAPPDATA || (process.env.USERPROFILE ? path.join(process.env.USERPROFILE, "AppData", "Roaming") : path.join(os.homedir(), "AppData", "Roaming")); } return process.env.XDG_CONFIG_HOME || path.join(os.homedir(), ".config"); }即依次尝试环境变量APPDATA→LOCALAPPDATA→USERPROFILE\AppData\Roaming,最终得到%APPDATA%\claude-code-router\config.sqlite。
历史版本遗留目录:Windows 上的“Claude Code Router”目录
需要特别注意的是 Windows 上存在一个历史遗留配置目录。源码中保留了对%APPDATA%\Claude Code Router(APP_NAME="Claude Code Router",带空格)目录的兼容处理(constants.ts):
export const LEGACY_WINDOWS_CONFIGDIR = path.join(resolveRuntimeAppPath("appData"), APP_NAME); export const LEGACY_WINDOWS_CONFIG_FILE = path.join(LEGACY_WINDOWS_CONFIGDIR, "config.json");并且在模块加载时,会把旧目录中的内容按“仅复制缺失项”的方式并入新目录(constants.ts):
if (process.platform === "win32") { copyMissingDirectoryContents(LEGACY_WINDOWS_CONFIGDIR, CONFIGDIR, "Windows app data directory"); }copyMissingDirectoryContents使用cpSync(source, target, { errorOnExist: false, force: false, recursive: true }),即不会覆盖新目录下已存在的文件,实现细节见 migration.ts。因此,如果你升级自较早的 Windows 版本,新配置库位于%APPDATA%\claude-code-router\,旧数据会被自动带过来。
提示:如果你在磁盘上找不到
config.sqlite,请先确认自己是否属于“老版本迁移”场景——旧版可能只生成了config.json,位于~/.claude-code-router/config.json(macOS/Linux)或%APPDATA%\Claude Code Router\config.json(Windows 旧目录)。
Docker 环境:HOME=/data与整目录持久化
官方文档特别强调:Docker 镜像将HOME设置为/data,因此配置数据库位于/data/.claude-code-router/config.sqlite。这一行为在 entrypoint.sh 中可以看到完整链路:
CCR_DATA_DIR="${CCR_DATA_DIR:-/data}" ... export HOME="${CCR_DATA_DIR}" export CCR_DATA_DIR ... CONFIG_DIR="${HOME}/.claude-code-router" CONFIG_FILE="${CONFIG_DIR}/config.json" APP_CONFIG_DB_FILE="${CONFIG_DIR}/config.sqlite" mkdir -p "${CONFIG_DIR}" "${CONFIG_DIR}/app-data" /run/nginx /var/lib/nginx /var/log/nginx由于路径解析逻辑是HOME+.claude-code-router,一旦HOME=/data,config.sqlite自然落在/data/.claude-code-router/下。同时入口脚本会预先创建app-data子目录,因为配置目录并不是孤立的——它还承载着网关运行需要的其他数据。
必须持久化整个/data,而不是单个文件
文档要求“持久化完整的/data目录,以保证配置数据库和相关文件都被保存”。从 docker/README.md 可以看到容器内数据目录的真实全貌:
/data/.claude-code-router/ ├── config.sqlite ├── gateway.config.json ├── app-data/ │ ├── api-keys.sqlite │ ├── request-logs.sqlite │ ├── usage.sqlite │ └── certs/ ├── profiles/ └── bin/config.sqlite:主配置数据库(本主题核心);gateway.config.json:网关运行时生成文件;app-data/:历史遗留的 API 密钥库、请求日志库、用量统计库、代理/系统级证书(certs/)等。
仓库根目录的 docker-compose.yml 正是通过命名卷挂载整个/data实现持久化:
volumes: - ccr-data:/data这里有一个经常踩坑的点:重建容器后“配置消失”,绝大多数是因为/data没有被正确挂载或换用了新的空卷(docker compose down --volumes会连同数据卷一起删除)。确认容器使用的还是同一个ccr-data卷或同一 bind-mount 路径即可。
此外,入口脚本还有一个细节:首次启动时若config.json与config.sqlite均不存在,会先写一份最小化的遗留版config.json作为引导(entrypoint.sh);当 UI 保存过设置后,SQLite 便成为权威来源(详见下一节)。默认情况下,每次容器启动还会把配置中的监听地址与routerEndpoint同步到 Docker 对外地址(CCR_DOCKER_SYNC_PUBLIC_ENDPOINT控制,见 docker/README.md)。
生效方式:SQLite 是权威来源,config.json只迁移一次
理解“生效方式”是使用 CCR 配置能力的关键。官方文档的表述可以拆成三条事实:
- 运行时配置存储在 SQLite 中;
- 旧版
config.json只在“没有 SQLite 配置”时作为一次性迁移来源被读取; - 迁移完成后,继续编辑
config.json不会影响当前配置。
从代码看“一次性迁移”
在 config-repository.ts 中,CCR 明确登记了三类需要归档的遗留 JSON 配置文件:
const legacyJsonConfigFiles = [ LEGACY_ACTIVE_CONFIG_FILE, // 当前配置目录下的 config.json LEGACY_WINDOWS_CONFIG_FILE, // Windows 旧目录 config.json LEGACY_CONFIG_FILE // 家目录 .claude-code-router/config.json ];当 SQLite 配置库被创建并完成 schema 初始化后,这些遗留 JSON 会被读取、备份并最终清理(archiveLegacyJsonConfigFiles+drainLegacyCleanup,见 config-repository.ts 与 config-repository.ts)。整个流程带有“安全网”设计:
- 迁移前会先计算遗留文件的 SHA-256,将内容存入数据库内置的
legacy_storage_backups备份表,再登记到legacy_storage_cleanup清理队列; - 真正删除前会再次比对 SHA-256,若文件在“读取”与“清理”之间发生变化且无对应备份,则保留源文件并等待下次迁移重试,绝不误删用户数据;
- 由于迁移只执行一次,SQLite 一旦写入成功并记录迁移 ID,之后你对
config.json的任何编辑都只是改一个“档案文件”,不再进入当前运行配置。
Docker 场景下的一致行为
Docker 入口脚本同样贯彻了“SQLite 优先”的语义(docker/README.md):首启引导 JSON 只在没有任何配置时生成;一旦 UI 保存过设置,SQLite 即成为权威。容器每次启动的“端点同步”也是分别处理 JSON 与 SQLite 两种情况(entrypoint.sh 中的syncJsonFile与syncSqliteConfig)。
配置库的内部表结构
为方便你理解“配置到底以什么形态存在”,从 config-repository.ts 可以看到首次建库时创建的几张核心表:
| 表 | 用途 |
|---|---|
app_config | 主配置键值表,key/value_json/updated_at,默认应用配置以"default"为键 |
api_keys | CCR 客户端 API Key(encrypted_key+encryption+limits_json) |
runtime_state | 各类运行时状态(如 onboarding 完成时间等) |
config_schema_migrations | 迁移记录,防止迁移重复执行 |
legacy_storage_backups/legacy_storage_cleanup | 遗留 JSON / SQLite 文件的备份与延迟清理队列 |
因此一个config.sqlite内实际上同时管理着“配置”“客户端密钥”“运行时状态”三类数据,这也是为什么文档反复强调不要在运行时直接编辑数据库。
不要在运行时直接编辑config.sqlite:WAL 模式与正确改法
文档给出的操作红线是:
- 修改配置请使用桌面 UI,或在Settings中导出备份;
- 不要在 CCR 运行时直接编辑
config.sqlite; - 同一目录下还存在
config.sqlite-wal与config.sqlite-shm两个配套文件,编辑数据库时必须一并考虑。
为什么会同时出现-wal与-shm文件
SQLite 在 CCR 中被显式配置为WAL(Write-Ahead Logging)模式,见 config-repository.ts:
function configureSqliteDatabase(database: SqlDatabase): void { database.pragma("journal_mode = WAL"); database.pragma("synchronous = NORMAL"); database.pragma("busy_timeout = 5000"); }在 WAL 模式下,写入先追加到config.sqlite-wal,随后才周期性地 checkpoint 回主文件;config.sqlite-shm则是共享内存索引文件,用于多连接协调。带来的实际影响:
- 只复制
config.sqlite主文件往往得到不完整/不一致的快照(部分最新事务还在-wal里); - 在进程运行时用外部工具改写主文件,极易损坏数据库,因为 WAL 与主文件之间的状态会对不上;
- 直接删除
-wal/-shm同样危险,可能丢失尚未 checkpoint 的事务。
所以,请牢记“数据三件套”是一个整体。如果你确实需要文件级备份,最稳妥的顺序是:先停止 CCR(或至少让写入完全静止),再同时复制config.sqlite、config.sqlite-wal、config.sqlite-shm。恢复时也应整体放回,不要把旧备份覆盖到一个仍在运行、还有新 WAL 数据的目录上(docker/README.md 对此有同样告诫)。
推荐的配置修改路径
CCR 提供的受支持改法本质上都走同一条代码路径——config-repository.ts 中的replacePersistedAppConfig/replacePersistedConfigSnapshot/replaceApiKeys等方法在事务内完成写入并刷新文件权限:
- 桌面/浏览器管理 UI:CCR 的管理界面(桌面 App 或 Docker 镜像通过 Nginx 提供的 Web UI)会把用户操作序列化为对
app_config/api_keys的替换写库; - Settings → Export data 导出备份:这是官方推荐的应用级备份手段(见 docker/README.md)。Docker 升级/迁移前先执行导出,比手工拷贝文件更安全;
- 网关/管理 RPC:若以 Docker 等模式远程管理,应通过认证的管理 RPC 修改,而不是直接进容器改库文件。
敏感性与文件权限
配置库中保存的是 Provider 凭据与 CCR 客户端 Key 等机密。源码在创建目录与每次写入后都会执行权限收紧(config-repository.ts 与 config-repository.ts):
- 配置目录权限设为
0o700; - 主库文件、
-wal、-shm三个文件权限均被设为0o600(secureDatabaseFilePermissions)。
也就是说,非当前系统用户无法读取配置内容。对应的,任何配置数据库的备份都必须按“包含密钥的敏感数据”对待,不要放进公开仓库或不可信存储。
常见问题排查速查
结合上面的机制,把高频疑问整理如下:
| 现象 | 原因与解法 |
|---|---|
找不到config.sqlite | 先确认平台默认位置;Windows 老版本可能在%APPDATA%\Claude Code Router\(带空格目录),首次运行会并入%APPDATA%\claude-code-router\ |
修改~/.claude-code-router/config.json后不生效 | 这是预期行为:SQLite 迁移完成后config.json只是归档文件,应改走桌面 UI 或 Settings 导出/导入流程 |
| 容器重建后配置消失 | 检查是否仍挂载同一个/data卷;docker compose down --volumes会删除数据 |
只备份了config.sqlite,恢复后配置不全 | WAL 模式下最新事务可能还在-wal中;应用级备份请使用 Settings → Export data |
| 想迁移到新机器/新环境 | 备份整个数据目录(含config.sqlite-wal/-shm与app-data/),在 CCR 停止状态下拷贝,恢复前先清空目标目录 |
小结与延伸阅读
一句话总结:CCR 的运行配置以 SQLite 为唯一权威来源,位置由“平台默认目录 +claude-code-router目录名”决定;Docker 中因HOME=/data落在/data/.claude-code-router/,必须持久化整个/data;旧版config.json只在首次无 SQLite 配置时迁移一次,之后编辑它不再影响任何行为。
本文核心结论均有源码与配置佐证,可供进一步深入的文件包括:
- 官方文档原文:configuration-file.md(英文)、configuration-file.md(中文)
- 平台路径解析:app-paths.ts
- 常量定义与 Windows 兼容拷贝:constants.ts
- 建库、迁移与权限管理实现:config-repository.ts、migration.ts
- SQLite 原生驱动封装:sqlite-native.ts
- Docker 相关:配置库路径语义 entrypoint.sh、持久化布局与备份策略 docker/README.md、数据卷挂载 docker-compose.yml
- 相关测试:配置迁移与遗留 JSON 行为可参考 config-repository-migration.test.mjs、legacy-json-preservation.test.mjs、config-repository-backup-deduplication.test.mjs
如果你需要继续了解供应商与模型配置、路由规则如何在 UI 中编辑并落到这张数据库里,可以阅读同目录下的 overview.md 或仓库根目录的 README_zh.md。
【免费下载链接】claude-code-routerOne local control plane for every AI agent: route across models, fuse new capabilities, orchestrate tools, and stay fully in control.项目地址: https://gitcode.com/GitHub_Trending/cl/claude-code-router
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考