🔒

FreeLLMAPI 无弹窗运维:PM2进程守护 + 崩溃恢复 + 静默启动

👤 。。 📦 v1.2.1 ⭐ 4.5 ⬇️ 105 下载
🔒 IT运维与安全 免费

📖 技能介绍


name: freellmapi-server slug: freellmapi-server displayName: "FreeLLMAPI 无弹窗运维:PM2进程守护 + 崩溃恢复 + 静默启动" description: Run, troubleshoot, and maintain the FreeLLMAPI local LLM proxy gateway on Windows — startup, PM2 process management, crash diagnosis, and server lifecycle. version: 1.2.1 author: Hermes Agent license: MIT platforms: [windows] metadata: hermes: tags: [Freellmapi, Proxy, LLM-Gateway, PM2, Process-Management, Windows] related_skills: [codex, reasonix, hermes-agent]


FreeLLMAPI Server

FreeLLMAPI is a local LLM proxy gateway that routes requests to multiple upstream providers through a proxy. It serves an OpenAI-compatible /v1/chat/completions API, a Responses API shim at /v1/responses, a WebSocket bridge at /v1/responses/ws, an Anthropic-compatible /v1/messages endpoint, and a React dashboard at http://localhost:3001.

Source: https://github.com/tashfeenahmed/freellmapi (GitHub version v0.2.1+). This is a monorepo (npm workspaces: shared, server, client) using better-sqlite3 (native, replaces sql.js), Drizzle ORM, and Express 5. The old local v2.0.0 build was a custom non-git project with a different architecture — this skill now documents the GitHub version.

Location

C:\Users\13657\Desktop\freellmapi\
├── shared/                          # @freellmapi/shared workspace (types, utilities)
├── server/                          # @freellmapi/server workspace
│   ├── src/
│   │   ├── index.ts                 # Entry point (Express 5, helmet, CORS)
│   │   ├── db/                      # Drizzle ORM schema, migrations, migrate CLI
│   │   │   ├── index.ts
│   │   │   ├── types.ts
│   │   │   ├── migrate/
│   │   │   │   ├── cli.ts           # Migration CLI (up/down/fresh/status/create)
│   │   │   │   ├── runner.ts
│   │   │   │   └── defaults.ts      # Seeds initial models + fallback config
│   │   │   └── migrations/          # Dated migration files
│   │   ├── providers/               # Upstream provider adapters
│   │   ├── routes/
│   │   ├── middleware/
│   │   ├── services/
│   │   │   ├── health.ts            # Checks API keys every 5min
│   │   │   └── catalog-sync.ts      # Pulls model catalog from api.freellmapi.co
│   │   └── lib/
│   ├── data/
│   │   ├── freeapi.db               # SQLite database (better-sqlite3, not sql.js)
│   │   └── .encryption-key          # Auto-generated dev encryption key (if ENCRYPTION_KEY not set)
│   └── package.json
├── client/                          # @freellmapi/client workspace (React + Vite)
│   ├── src/
│   └── dist/                        # Built dashboard (npm run build -w client)
├── package.json                     # Root monorepo package (workspaces config)
├── .env                             # Environment variables
├── .env.example                     # Documented template with all available vars
└── ecosystem.config.cjs             # PM2 config

Key architectural differences from the old local v2.0.0 build: - better-sqlite3 instead of sql.js (native C module, no WASM, no "stdin is not a tty" quirks) - Drizzle ORM with migrations instead of raw SQL schema management - Monorepo (npm workspaces) — dependencies hoisted to root node_modules - Account-based auth — users create accounts via dashboard, each with their own API keys. No more single unified_api_key for everything; the unified_api_key setting still exists but API auth checks the api_keys table first.

Why FreeLLMAPI Keeps Crashing (Root Causes)

Fresh Install from GitHub

Clone

cd /c/Users/13657/Desktop
git clone -c http.proxy=http://127.0.0.1:7890 -c https.proxy=http://127.0.0.1:7890 \
  --depth 1 https://github.com/tashfeenahmed/freellmapi.git freellmapi

GitHub is not directly reachable from this environment — always pass proxy config (-c http.proxy=...) when cloning or fetching.

npm install

cd /c/Users/13657/Desktop/freellmapi
npm install

Expect 3-5 minutes. better-sqlite3 compiles SQLite from source via node-gyp. This needs Python and a C++ toolchain (VS Build Tools). The proxy (7890) must be up for package downloads.

Windows pitfall — file locking during install: If the directory already has a node_modules/ from a previous install, npm install may fail with EPERM / ENOTEMPTY because Windows locks files in nested directories. The workaround is to delete node_modules/ with Python's shutil.rmtree (which handles permission errors by chmod-ing files first), then re-run npm install:

import shutil, os, stat
target = r"C:\Users\13657\Desktop\freellmapi\node_modules"
def on_error(func, path, exc_info):
    os.chmod(path, stat.S_IWRITE)
    func(path)
if os.path.exists(target):
    shutil.rmtree(target, onerror=on_error)

Plain rm -rf or cmd //c "rmdir /s /q" will fail on locked files — always use the Python approach.

First-time database setup

npm run db:migration:up -w server

This runs Drizzle migrations, creates the SQLite DB, seeds the initial model catalog (~25 models), and prints a first-run setup code and a unified API key. Save both.

If you're setting ENCRYPTION_KEY in .env, do it BEFORE running migrations — the key encrypts API credentials at rest and changing it later invalidates encrypted data.

Build the dashboard

npm run build -w client

The server serves client/dist/index.html as the dashboard. Without this build, the root route returns 404 or crashes with ENOENT: no such file or directory, stat '...client/dist/index.html'.

.env minimum

PORT=3001
ENCRYPTION_KEY=<64-char-hex>

Generate a key: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

The server prints warnings for missing REQUEST_ANALYTICS_MAX_ROWS and REQUEST_ANALYTICS_RETENTION_DAYS but these are non-fatal — they just use defaults.

First-run account setup

The new version uses account-based auth, not a single unified key. On first boot, the server prints a setup code in logs:

First-run setup code: YRU2PRAGYX
A browser on this machine can finish setup without it. From any
other device, enter this code to create the first account.

Open http://localhost:3001 → create account with email + password → the dashboard generates API keys under the account.

The unified_api_key in the settings table is a bootstrap/legacy key — it may not pass API auth middleware once accounts exist. Always create an account and use its API keys for client configs.

Why FreeLLMAPI Keeps Crashing (Root Causes)

PM2 is still the fix. The process-safety-net from the old build is gone; the new version has its own error handling, but PM2 auto-restart remains essential for resilience against programming bugs, port conflicts, and proxy instability.

PM2 Setup (The Fix)

PM2 auto-restarts the process on any crash, with exponential backoff.

Installation

npm install -g pm2

Start

cd /c/Users/13657/Desktop/freellmapi
pm2 start ecosystem.config.cjs   # Uses ecosystem.config.cjs (preferred)
# OR
pm2 start D:\node_modules\tsx\dist\cli.mjs --name freellmapi -- server/src/index.ts

ecosystem.config.cjs contents (used by pm2 start):

module.exports = {
  apps: [{
    name: 'freellmapi',
    script: 'node_modules/tsx/dist/cli.mjs',
    cwd: 'C:\\Users\\13657\\Desktop\\freellmapi',
    args: ['server/src/index.ts'],
    max_restarts: 20,
    min_uptime: 5000,
    restart_delay: 2000,
    exp_backoff_restart_delay: 5000,
    max_memory_restart: '1G',
    windowsHide: true,          // ★ 隐藏子进程控制台窗口(无弹窗)
    kill_timeout: 5000,         // 优雅关闭超时
    error_file: 'C:\\Users\\13657\\.pm2\\logs\\freellmapi-error.log',
    out_file: 'C:\\Users\\13657\\.pm2\\logs\\freellmapi-out.log',
    merge_logs: true,
    log_date_format: 'YYYY-MM-DD HH:mm:ss',
    env: {
      PORT: '3001',
    },
  }],
};

DO NOT set NODE_ENV=production in the ecosystem config. In production mode, the server requires a 64-char hex ENCRYPTION_KEY in .env and refuses to start without it. If you omit NODE_ENV, the server auto-generates a dev encryption key file at server/data/.encryption-key. If you DO set it, also add ENCRYPTION_KEY to the env block.

Verify

pm2 status
# Should show freellmapi as "online"
curl http://localhost:3001/   # Dashboard
curl http://localhost:3001/v1/models  # (requires API key or returns auth error)

Logs

pm2 logs freellmapi           # Tail logs
pm2 logs freellmapi --lines 200 --nostream  # Recent output
# Or check files directly:
cat ~/.pm2/logs/freellmapi-out.log
cat ~/.pm2/logs/freellmapi-error.log

Save Process List (for boot resurrection)

pm2 save

On Windows, pm2 startup doesn't work (no Init system detected). Use a silent VBS launcher (no CMD popup window at login):

Create %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\freellmapi-pm2.vbs:

' FreeLLMAPI PM2 Auto-Start — Silent (no popup window at login)
On Error Resume Next
Dim WshShell
Set WshShell = CreateObject("Wscript.Shell")
WshShell.CurrentDirectory = "C:\Users\13657\Desktop\freellmapi"
' WindowStyle: 0=Hidden — no CMD window flashes on screen
WshShell.Run "cmd /c C:\Users\13657\AppData\Roaming\npm\pm2.cmd resurrect", 0, False
Set WshShell = Nothing

Why VBS instead of .cmd: .cmd files in Startup open a visible console window briefly. VBS with Run(..., 0, False) runs completely invisible. The old freellmapi-pm2.cmd should be deleted if it still exists.

Other Management

pm2 restart freellmapi         # Graceful restart
pm2 stop freellmapi            # Stop
pm2 delete freellmapi          # Remove from PM2
pm2 kill                       # Kill PM2 daemon entirely

Codex WSS Bridge (bridge-443)

Codex CLI 需要通过 WSS 桥接在 443 端口连 FreeLLMAPI。详见 codex-wws-bridge skill。

⚠️ PM2 不能管理这个桥接 — 443 端口需要管理员权限,PM2 以普通用户运行无法绑定。用 PowerShell RunAs 启动:

创建 start-bridge.bat

@echo off
cd /d C:\Users\13657\Desktop\freellmapi
node server\src\lib\bridge-443.mjs

启动(管理员,隐藏窗口):

powershell -Command "Start-Process cmd -ArgumentList '/c','C:\\Users\\13657\\Desktop\\freellmapi\\start-bridge.bat' -Verb RunAs -WindowStyle Hidden"

bridge 不持久 — PowerShell RunAs 启动的进程跟 PM2/系统服务无关。任何导致 node 被杀的事件(系统睡眠、杀进程、端口冲突)都会让 bridge 消失。没有自动恢复机制,每次出问题需要手动重拉。

Reference Files

  • references/v0.2.1-upgrade.md — Upgrade from old local v2.0.0 to GitHub monorepo v0.2.1
  • references/claude-code-non-tty.md — Claude Code mode compatibility in non-TTY / Hermes terminal environments
  • references/crash-analysis-2026-06-26.md — Detailed root cause analysis of a real crash event
  • references/pm2-windows-guide.md — PM2 on Windows quirks
  • references/shannon-setup.md — Connecting Shannon to FreeLLMAPI via the Anthropic endpoint
  • references/deep-cooldown-clear.md — 彻底清除 cooldown
  • references/routing-and-model-setup.md — Routing limitations (no round-robin), adding custom provider models checklist, common pitfalls
  • references/models-table-schema.md — models 表完整 schema,用于 SQL INSERT 添加自定义模型(含所有必填列、索引、约束)

PM2 Resilience: Process Resurrection

PM2 daemon may restart (e.g. after system sleep, crash, or manual pm2 kill). When the daemon comes back, the process list is emptypm2 list shows nothing. All processes saved with pm2 save are in ~/.pm2/dump.pm2 but not running.

Fix: Run pm2 resurrect to restore all saved processes. Then verify with pm2 list.

Prevention: Regularly run pm2 save after adding or updating processes. The Windows startup script (freellmapi-pm2.vbs in Startup folder — silent VBS, no CMD popup) calls pm2 resurrect at login, so this only matters for mid-session daemon restarts.

.env + ENCRYPTION_KEY

The new version uses ENCRYPTION_KEY to encrypt API credentials at rest in the api_keys table (AES-GCM). Two modes:

  • Without ENCRYPTION_KEY (dev): Server auto-generates a key file at server/data/.encryption-key with 0600 permissions. Safe for local development.
  • With ENCRYPTION_KEY set (production): Reads from .env. Required when NODE_ENV=production.

Changing ENCRYPTION_KEY after data exists invalidates all encrypted API keys. The api_keys table stores encrypted_key, iv, and auth_tag columns — decrypting with a different key produces garbage. If you lose the key and have no backup, you must re-enter all upstream API keys through the dashboard.

Testing the API

# Check dashboard
curl -s -o /dev/null -w "%{http_code}" http://localhost:3001/
# Should return 200 if client is built

# Test API (requires account-created API key or unified_api_key)
curl -s http://localhost:3001/v1/models -H "x-api-key: <your-api-key>"

The unified_api_key from the settings table may work as a bootstrap key before accounts exist, but once the first account is created, use the account's API keys from the dashboard. The spelling is freellmapi (double-E), not frellmapi.

Troubleshooting

"Windows cannot find startfreellmapi.vbs" on boot

Leftover .lnk shortcut in the Startup folder from a previous setup. The current startup uses freellmapi-pm2.cmd (PM2 resurrect). Delete the stale .lnk. Full procedure: references/startup-lnk-cleanup.md

ENCRYPTION_KEY required in production

症状: 每次登录 Windows 后弹出错误框,提示找不到某个 .vbs 文件。

根因: 曾经使用过旧的启动方式(VBS 脚本 + Startup 快捷方式),后来 VBS 文件被删除但 .lnk 快捷方式还留在 Startup 文件夹里。

诊断步骤(按顺序,逐层排查):

  1. 检查 Startup 文件夹是否有 FreeLLMAPI 相关的 .lnkbash ls -la "$APPDATA/Microsoft/Windows/Start Menu/Programs/Startup/" | grep -i freellmapi
  2. 如果有 .lnk,解析其目标路径确认是否指向不存在的 VBS: python # 解析 .lnk 的 Python 脚本,提取 TargetPath 和 Arguments
  3. 检查注册表 Run 键是否有残留: bash cmd //c "reg query HKCU\Software\Microsoft\Windows\CurrentVersion\Run" | grep -i vbs
  4. 检查计划任务: bash schtasks /query /fo LIST /v | grep -i "freellmapi\|vbs"

修复: 删除孤立的 .lnk(当前正确的启动方案是 freellmapi-pm2.cmd,两者不冲突但弹窗烦人):

rm -f "$APPDATA/Microsoft/Windows/Start Menu/Programs/Startup/FreeLLMAPI.lnk"

Windows System Proxy: The Silent Killer (🚨 check FIRST)

Every AI coding agent (Codex, Claude Code, Grok Build) that routes through FreeLLMAPI can be silently hijacked by the Windows system proxy. The proxy does its own DNS resolution, bypassing hosts redirects and local bridges. This is the #1 cause of "agent suddenly broken" after everything looks fine.

Symptom: All services are online, bridge is listening, FreeLLMAPI returns 200 — but the agent times out or hits the real external API (401 from real OpenAI, real Anthropic).

One-time fix — add ALL agent domains to ProxyOverride:

import winreg
key_path = r"Software\Microsoft\Windows\CurrentVersion\Internet Settings"
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path, 0, winreg.KEY_READ | winreg.KEY_SET_VALUE)
current, _ = winreg.QueryValueEx(key, "ProxyOverride")

# Add ALL agent domains
for domain in ["api.openai.com", "api.anthropic.com", "grok.com", "x.ai", "cli-chat-proxy.grok.com"]:
    if domain not in current:
        current = current + ";" + domain

winreg.SetValueEx(key, "ProxyOverride", 0, winreg.REG_SZ, current)
winreg.CloseKey(key)

Then kill all agent processes so they pick up the new registry setting:

taskkill //F //IM codex.exe 2>/dev/null
taskkill //F //IM "Claude.exe" 2>/dev/null
taskkill //F //IM claude.exe 2>/dev/null

📋 Quick diagnostic:

powershell -Command "(Get-ItemProperty 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings').ProxyOverride" | tr ';' '\n' | grep -E 'openai|anthropic|grok'

All three domains must appear. Missing any → that agent will silently hit the real external API.

Troubleshooting

ENCRYPTION_KEY required in production

[server] Failed to start:
  ENCRYPTION_KEY is required in production for API key encryption.

Fix: Either remove NODE_ENV=production from the PM2 ecosystem config, or add a 64-char hex ENCRYPTION_KEY to .env. Generate one: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))".

Port 3001 Already in Use

netstat -ano | grep ':3001' | grep LISTENING
taskkill //F //PID <pid>

Note: TIME_WAIT on Windows can hold the port for 30-60s after killing a Node process.

⚠️ PM2 auto-respawn race: when you kill the FreeLLMAPI process manually, PM2 detects the death and instantly respawns it. If you're trying to restart with a fresh config (new API key, changed DB), PM2's respawn grabs port 3001 before your manual start can bind. This creates a loop where you keep seeing EADDRINUSE and the old process keeps winning.

Fix: stop via PM2 first, NOT via taskkill:

pm2 stop freellmapi     # Graceful stop — PM2 won't respawn
# Wait for port to free
sleep 3
# Now start manually or via PM2
pm2 start freellmapi    # or your manual command

Or to kill EVERYTHING and start fresh:

pm2 stop freellmapi
cmd //c "wmic process where \"name='node.exe' and commandline like '%frellmapi%server/src/index.ts%'\" get processid" | grep -o '[0-9]\+' | while read pid; do taskkill //F //PID $pid; done
sleep 3
netstat -ano | grep ':3001.*LISTENING' || echo "Port free"

Dashboard returns 404 or crash: ENOENT client/dist/index.html

The React dashboard must be built before the server can serve it. Run npm run build -w client from the project root. The server boots without it, but accessing the root route will fail.

Server crashes after restart / NODE_ENV pitfall

When Claude Code routes through FreeLLMAPI (ANTHROPIC_BASE_URL=http://localhost:3001), the upstream free-tier model can add 30-120s of latency per turn. Multi-turn tasks (e.g. --max-turns 10) easily exceed 300s foreground timeout and fail silently.

Symptoms: - claude -p "complex task" --max-turns 5 returns exit code 124 (timeout) - Terminal shows [Command timed out after 300s] - Claude may have made partial changes before timing out — check git diff

Mitigations: - Use background=true + notify_on_complete=true with generous timeout (600s) for multi-turn tasks - Set --max-turns higher than you think necessary (10+ for 3-bug fixes, 15+ for refactors) - For simple single-file edits, use --max-turns 3 to keep latency manageable - For complex tasks that will hit FreeLLMAPI latency limits, prefer Hermes native agent or delegate_task subagents instead of Claude Code

All upstream calls get 401/403

Quick check for 401 "Invalid API key": before deep-diving, verify the key the running process actually reads against what you're sending:

# Read key from DB
cd C:\Users\13657\Desktop\freellmapi && node -e "
const Database = require('better-sqlite3');
const db = new Database('server/data/freeapi.db');
const row = db.prepare(\"SELECT value FROM settings WHERE key = 'unified_api_key'\").get();
console.log('DB key:', row?.value);
db.close();
"

Pitfall: the unified_api_key regenerates silently. FreeLLMAPI may regenerate the key on restart (DB migration, encryption key change, or manual reset). When 401 appears suddenly for a key that worked yesterday, always read the DB value first — don't assume the old key is still valid.

2. Test with curl (both header styles)

curl -s http://localhost:3001/v1/models -H "Authorization: Bearer " curl -s http://localhost:3001/v1/models -H "x-api-key: "

3. If both return 401 despite key matching DB: the process may have started

before a key regeneration and cached stale auth state. Try:

a) pm2 restart frellmapi

b) Wait 5s and retry

c) If still 401, kill ALL node processes holding :3001 and restart fresh:

pm2 stop frellmapi cmd //c "wmic process where \"name='node.exe' and commandline like '%frellmapi%server/src/index.ts%'\" get processid" | grep -o '[0-9]+' | while read pid; do taskkill //F //PID $pid; done sleep 3 pm2 start frellmapi


**Account-based auth pitfall:** once an account is created through the dashboard, the `unified_api_key` bootstrap key may be rejected by the API auth middleware even though it still exists in the `settings` table. The auth middleware checks account-created API keys first. If accounts exist, generate an API key under your account at Dashboard → API Keys and use that instead.

**If the key is confirmed correct and the process was cleanly restarted but 401 persists**, add debug logging to `server/src/routes/proxy.ts` in the `/models` auth block (around line 198):

```typescript
console.log('[AUTH-DEBUG] token:', JSON.stringify(token));
console.log('[AUTH-DEBUG] dbKey:', JSON.stringify(unifiedKey));
console.log('[AUTH-DEBUG] match:', token === unifiedKey);

tsx picks up file changes live — send one request and check PM2 logs (pm2 logs freellmapi --lines 5 --nostream). This reveals whether the running process is reading a different key than what's in the DB file, or if there's a character-level mismatch (whitespace, encoding).

Last resort: regenerate the key and update all consumers:

cd C:\Users\13657\Desktop\freellmapi
node -e "
const crypto = require('crypto');
const Database = require('better-sqlite3');
const db = new Database('server/data/freeapi.db');
const key = 'freellmapi-' + crypto.randomBytes(24).toString('hex');
db.prepare(\"UPDATE settings SET value = ? WHERE key = 'unified_api_key'\").run(key);
console.log('NEW KEY:', key);
db.close();
"
# Then restart FreeLLMAPI and update ~/.codex/auth.json and bridge auth config

### Rate Limit / Cooldown Clear(模型全部耗尽时用)

适用于 better-sqlite3 版本。一键清除所有 rate limit 状态,无需停服、无需清 WAL:

```bash
cd /c/Users/13657/Desktop/freellmapi && node -e "
const Database = require('better-sqlite3');
const db = new Database('server/data/freeapi.db');
const r1 = db.prepare('DELETE FROM rate_limit_cooldowns').run();
const r2 = db.prepare('DELETE FROM rate_limit_usage').run();
const r3 = db.prepare(\"UPDATE api_keys SET status='healthy' WHERE status='error'\").run();
console.log('cooldowns:', r1.changes, 'usage:', r2.changes, 'keys fixed:', r3.changes);
db.close();
"
pm2 restart freellmapi

输出示例:cooldowns: 2 usage: 188 keys fixed: 2。然后 curl -s -o /dev/null -w "%{http_code}" http://localhost:3001/ 确认 200。

注意:process name 是 freellmapi(double-e, double-l),不是 frellmapi。如果 pm2 restart freellmapi 报 "not found",用 pm2 restart <id> 替代(先 pm2 list 查 id)。

All upstream traffic goes through http://127.0.0.1:7890. If the proxy is slow or down: - Upstream calls hang for 20-30s before timeout - Health checker marks keys as 'error' (transport errors don't count toward disable threshold) - Catalog sync log shows fetch failed

Possible fixes: disable proxy in settings, switch to a different proxy port, or add proxy bypass for certain hosts.

Proxy bypass for custom providers

When a custom platform key targets an endpoint that doesn't need the proxy, add custom to the proxy bypass list so those requests go direct. Without this, a dead proxy blocks all custom provider calls even if the endpoint is directly reachable.

-- Add 'custom' to proxy_bypass (comma-separated)
INSERT INTO settings (key, value) VALUES ('proxy_bypass', 'custom')
ON CONFLICT DO UPDATE SET value = value || ',custom';

Restart FreeLLMAPI after changing (pm2 restart freellmapi). The boot log should show [proxy] Bypass for: custom.

Custom models not visible in auto-routing

When new custom platform models are added, they must be inserted into THREE places to work:

  1. models table — the model catalog entry. See references/models-table-schema.md for the full column list and a minimal INSERT template. Key gotchas: intelligence_rank, speed_rank, monthly_token_budget, and supports_tools are all NOT NULL and easily forgotten.
  2. fallback_config table — the fallback chain that getActiveChain() uses when no profile is active
  3. profile_models table — the active profile's model list. If an active_profile_id exists in settings, getActiveChain() returns ONLY models from that profile. Custom models missing from the profile are invisible to auto-routing.

⚠️ Key ID shift after dashboard edit: When the user updates an API key through the Dashboard → Keys panel, the old api_keys row may be deleted and recreated with a new id. Any models in the models table that reference the old key_id are now orphaned (point to a non-existent key). After the user says "好了" following a dashboard key update:

  1. Query all keys to find the new ID: sql SELECT id, platform, label, base_url FROM api_keys WHERE platform = 'custom';
  2. Find orphaned models: sql SELECT m.id, m.model_id, m.key_id FROM models m LEFT JOIN api_keys k ON k.id = m.key_id WHERE k.id IS NULL;
  3. Re-point orphaned models or recreate them with the new key_id.

To add a custom model to the active profile:

INSERT INTO profile_models (profile_id, model_db_id, priority, enabled)
SELECT 1, id, (SELECT COALESCE(MAX(priority), 0) + 1 FROM profile_models WHERE profile_id = 1), 1
FROM models WHERE platform = 'custom' AND enabled = 1;

Note: fallback_config may be auto-populated by a database trigger when models are inserted, but profile_models requires explicit insertion. Verify with:

SELECT pm.priority, m.model_id, m.platform
FROM profile_models pm JOIN models m ON m.id = pm.model_db_id
WHERE m.platform = 'custom';

Dashboard shows but API calls fail

The new version has account-based auth. API calls require either: 1. An API key created under a user account (Dashboard → API Keys), or 2. The bootstrap unified_api_key from the settings table (may stop working once accounts exist).

If no account has been created yet, open the dashboard at http://localhost:3001 and complete first-run setup using the setup code printed in server logs. Then create an API key under your account and use that key for client configs.

Anthropic-Compatible Endpoint (POST /v1/messages)

FreeLLMAPI exposes a full Anthropic Messages API emulation at POST /v1/messages. It translates Anthropic wire format → internal OpenAI-shaped messages → routes through the same router/fallback/analytics pipeline as /v1/chat/completions → translates response back to Anthropic format (including SSE streaming with message_start, content_block_start/delta/stop, message_delta, message_stop events).

Why this exists: Tools that speak the Anthropic SDK (Claude Code, Shannon, any ANTHROPIC_BASE_URL-compatible client) can point at FreeLLMAPI and transparently route claude-* model requests through whichever free upstream models are available.

Model Resolution

Claude model families (claude-sonnet-4-6, claude-haiku-4-5-20251001, claude-opus-4-8) are resolved through the Anthropic model map configured in the Dashboard → Anthropic tab. By default, every family maps to auto (the router picks a free model). Operators can pin specific families to specific catalog models.

Auth

Accepts both Anthropic-native x-api-key header and OpenAI-style Authorization: Bearer <token>. Auth checks account-created API keys first, falling back to the unified_api_key bootstrap key. Get an API key from Dashboard → API Keys after creating an account.

Session Affinity

When auto-routing, requests with X-Claude-Code-Session-Id or X-Session-Id headers stick to the same model for the entire session (sticky routing), avoiding cross-provider flapping mid-conversation.

Claude Code Integration

Claude Code works transparently through FreeLLMAPI via the Anthropic Messages endpoint. Configure ~/.claude/settings.json:

{
  "env": {
    "ANTHROPIC_BASE_URL": "http://localhost:3001",
    "ANTHROPIC_API_KEY": "<unified-key>"
  }
}

Pitfall — missing .claude.json config file: Claude Code may refuse to start with "Claude configuration file not found at ~/.claude.json". Restore from backup:

cp ~/.claude/backups/.claude.json.backup.* ~/.claude.json

Tested: Claude Code v2.1.195+ → FreeLLMAPI :3001 → claude-sonnet-4-6 auto-routed to deepseek-v4-pro or auto. Print mode (-p) skips interactive auth entirely.

Pitfall: Claude Code's safety filters may still block exploit/pentest prompts even when routing through a proxy. Phrase tasks as code analysis or automation scripts.

Quick Test

curl -s -X POST http://localhost:3001/v1/messages \
  -H 'Content-Type: application/json' \
  -H 'x-api-key: <unified-key>' \
  -H 'anthropic-version: 2023-06-01' \
  -d '{"model":"claude-sonnet-4-6","max_tokens":50,"messages":[{"role":"user","content":"Say hello"}]}'

Claude Code in Hermes (non-TTY)

When running Claude Code from inside Hermes (non-TTY terminal), only -p (print) mode works reliably. Interactive mode auto-falls to print, and --bg mode requires OAuth login that API keys can't satisfy. Full matrix and native binary fix in references/claude-code-non-tty.md.

ANTHROPIC_BASE_URL=http://localhost:3001 \
ANTHROPIC_API_KEY=<unified-key> \
claude -p "your prompt" --max-turns 3

For interactive sessions, use a real Windows terminal directly.

Pitfalls

  • "All models exhausted" — Can have multiple root causes. See references/shannon-setup.md "Debugging 'All models exhausted'" for the full 5-step checklist. Quick checks: (1) custom key has base_url with /v1 suffix? (2) proxy bypass configured for custom platform if proxy is down? (3) custom models are in the active profile's profile_models table, not just models?
  • Model name mismatch — Shannon sends exact Anthropic model IDs (claude-sonnet-4-6). If the Anthropic map doesn't resolve these, the request fails. Configure the map in Dashboard → Anthropic.
  • Streaming tool calls — Buffered across deltas and emitted as complete tool_use blocks with input_json_delta. Partial tool-call JSON is never forwarded mid-flight (same buffering as the OpenAI route).

Reference

  • references/shannon-setup.md — Connecting Shannon (KeygraphHQ AI pentest) to FreeLLMAPI via this endpoint.

WSS Bridge (for Codex CLI)

FreeLLMAPI has a built-in WebSocket bridge at server/src/lib/ws-bridge.ts, activated automatically on boot at /v1/responses/ws on the main HTTP server (port 3001).

For Codex's hardcoded wss://api.openai.com, the standalone bridge script server/src/lib/bridge-443.mjs runs on port 443 with HTTPS. See the codex skill for full setup instructions — it requires: - CA-signed certificate chain (not plain self-signed — Codex's Rust TLS rejects CaUsedAsEndEntity) - CA installed to Windows Trust Store via certutil -addstore Root ca-cert.pem - Admin privileges to bind port 443 - Hosts redirect: 127.0.0.1 api.openai.com

🤖 AI 评测

这个 Skill 质量不错,文档内容非常全面详尽,涵盖了 FreeLLMAPI 在 Windows 上从安装到日常运维的几乎所有常见问题,尤其是针对 Windows 平台特性(如文件锁定、进程管理)的处理很有针对性。优点是实用性强、包含完整的故障排查指南和脚本示例;不足是文档内容有较多重复,部分段落重复出现多次,整体组织可以更精简。此外它只适用于 Windows 系统。总体来说,这是一个实用价值较高的运维 Skill,适合需要运维 FreeLLMAPI 的用户参考。

📊 多维度评分

适应性4.4
规范性4.2
有效性4.8
可靠性4.5
可信度4.5

📁 包含文件 (11 个)

📄 SKILL.md 32.1 KB
📄 references/claude-code-non-tty.md 1.6 KB
📄 references/crash-analysis-2026-06-26.md 3.5 KB
📄 references/deep-cooldown-clear.md 1.3 KB
📄 references/models-table-schema.md 3.3 KB
📄 references/mysql-to-sqljs-migration.md 2.6 KB
📄 references/pm2-windows-guide.md 3 KB
📄 references/routing-and-model-setup.md 2.8 KB
📄 references/shannon-setup.md 8.6 KB
📄 references/startup-lnk-cleanup.md 969 B
📄 references/v0.2.1-upgrade.md 3.7 KB

🔥 大家都在搜

wps 写作 pdf 苹果