Docker 部署 FreeLLMAPI:统一免费模型 API 与故障转移路由
FreeLLMAPI 将多个免费 LLM 提供商聚合到一个 OpenAI 兼容的 /v1 入口,并在可用模型之间进行路由和故障转移。本文使用官方 GHCR v0.9.7 镜像,通过 Docker Compose 运行 API 与 Web 控制台,使用 SQLite 命名卷保存账号、模型配置和加密后的提供商密钥。
FreeLLMAPI 面向个人实验和单用户自托管,不是多租户网关或生产推理平台。本文默认只让本机访问;需要局域网访问时,必须显式修改绑定地址,并将服务限制在可信网络或反向代理之后。
部署结论
| 项目 | 本文采用的值 |
|---|---|
| GitHub 地址 | tashfeenahmed/freellmapi |
| 官方镜像 | ghcr.io/tashfeenahmed/freellmapi:v0.9.7 |
| 项目版本 | v0.9.7 |
| 正式部署 | Docker Compose |
| 快速体验 | 不提供:服务需要加密密钥、首次账户和持久化 SQLite,单条 docker run 容易遗漏安全配置 |
| 适用范围 | 单主机个人实验、家庭实验室和小范围可信网络 |
| 主机架构 | linux/amd64、linux/arm64 |
| 最低资源 | 官方未给出;按 Docker 主机和上游模型请求负载规划 |
| 对外端口 | 默认 127.0.0.1:3001 -> 3001 |
| 持久化位置 | Docker 命名卷 freellmapi-data -> /app/server/data |
| 依赖服务 | 无;提供商 API 由 FreeLLMAPI 容器访问 |
| 验证范围 | 官方文档、v0.9.7 镜像元数据和 Compose 配置已核对;未在本机拉取或启动容器 |
| 部署日期 | 2026-09-07 |
Compose 使用 v0.9.7 的多架构 manifest digest,避免 latest 在后续发布后改变:
ghcr.io/tashfeenahmed/freellmapi:v0.9.7@sha256:abdd346e3c6f2e462dfd6877ff718226d726033276e94ee54901c053d74f7ec8架构与数据流
Docker Compose 只运行一个 freellmapi 服务。容器同时提供控制台和 API,容器内监听 3001;宿主机默认只发布到 127.0.0.1。SQLite 数据库位于 /app/server/data,由 freellmapi-data 命名卷保存,容器重建不会清空账号、提供商密钥和路由设置。提供商密钥存储在 SQLite 中,并由 ENCRYPTION_KEY 解密。
正在准备渲染...
查看源码
flowchart LR
C[OpenAI 兼容客户端] -->|http://127.0.0.1:3001/v1| A[FreeLLMAPI API + 控制台]
A -->|HTTPS 请求| P[上游 LLM 提供商]
A --> D[(SQLite\nfreellmapi-data)]
U[浏览器首次设置] -->|http://127.0.0.1:3001| A前置条件
准备一台已安装 Docker Engine 或 Docker Desktop 的主机,并确认 Compose 可用:
docker --version
docker compose version
openssl versionDocker 官方安装入口:Install Docker Engine。主机需要能够访问 GHCR 和你启用的提供商 API。若通过反向代理提供 HTTPS,代理应转发到本机的 127.0.0.1:3001,并保留 X-Forwarded-Proto: https。
Docker Compose 正式部署
创建工作目录和加密密钥
以下命令适用于 macOS、Linux 和 WSL。ENCRYPTION_KEY 用于保护数据库中的提供商密钥;请把 .env 当作敏感文件保存,不要提交到 Git 或粘贴到工单中。
mkdir -p ~/freellmapi
cd ~/freellmapi
umask 077
ENCRYPTION_KEY="$(openssl rand -hex 32)"
printf 'ENCRYPTION_KEY=%s\nPORT=3001\nHOST_BIND=127.0.0.1\n' "$ENCRYPTION_KEY" > .env如需让同一局域网的其他设备访问控制台,把 .env 中的 HOST_BIND 改为 0.0.0.0,并确保防火墙只允许可信网段。默认的 127.0.0.1 更适合通过本机浏览器或反向代理访问。
写入 compose.yaml
在 ~/freellmapi/compose.yaml 保存以下完整配置。镜像使用 v0.9.7 的 manifest digest;extra_hosts 让 Linux Docker 也能解析 host.docker.internal,便于容器访问宿主机上的代理;健康检查对应官方 /api/ping 端点。
services:
freellmapi:
image: ghcr.io/tashfeenahmed/freellmapi:v0.9.7@sha256:abdd346e3c6f2e462dfd6877ff718226d726033276e94ee54901c053d74f7ec8
env_file:
- .env
environment:
NODE_ENV: production
PORT: 3001
ports:
- "${HOST_BIND:-127.0.0.1}:${PORT:-3001}:3001"
volumes:
- ./data:/app/server/data
extra_hosts:
- "host.docker.internal:host-gateway"
restart: unless-stopped
healthcheck:
test:
- CMD
- node
- -e
- >-
fetch('http://127.0.0.1:3001/api/ping').then((res) => {
if (!res.ok) process.exit(1);
}).catch(() => process.exit(1));
interval: 30s
timeout: 5s
start_period: 15s
retries: 3校验并启动
先渲染 Compose 配置,确认端口和卷映射没有被环境变量意外覆盖:
docker compose config随后拉取固定镜像并启动服务:
docker compose pull
docker compose up -d
docker compose ps预期结果是 freellmapi 处于 running,并在健康检查通过后显示 healthy。首次启动可能需要等待镜像下载和 SQLite 初始化。
首次初始化
- 在部署主机打开 http://127.0.0.1:3001。
- 按控制台提示创建第一个账户。若从其他设备访问,首次创建账户需要输入启动日志打印的一次性 setup code;先执行
docker compose logs --tail=100 freellmapi。 - 在 Keys 页面添加你有权使用的提供商 API key,并按需要调整 Fallback Chain。
- 从 Keys 页面获取统一 API key。OpenAI SDK 的
base_url使用http://127.0.0.1:3001/v1,请求的api_key使用统一 API key。
示例请求只验证接口形状,不包含任何真实提供商密钥:
curl http://127.0.0.1:3001/v1/models \\
-H 'Authorization: Bearer freellmapi-your-unified-key'是否返回模型列表取决于控制台中已配置且可用的提供商;如果尚未添加提供商 key,先完成第 3 步。
验证部署结果
容器状态
docker compose ps预期 freellmapi 的状态包含 Up,健康列为 healthy。如果仍是 starting,等待一个健康检查周期再检查。
应用响应
curl -i http://127.0.0.1:3001/api/ping预期 HTTP 状态为 200。该端点也是 Compose 健康检查使用的端点。
日志
docker compose logs --tail=100 freellmapi检查日志中是否出现启动完成信息、端口监听信息和首次账户 setup code。不要长期使用无界的 docker compose logs -f 作为唯一验收证据。
持久化
docker volume inspect freellmapi-data
docker compose down
docker compose up -d
docker compose ps重新打开控制台,确认账户、提供商配置和模型路由仍然存在。不要使用 docker compose down -v 做这个检查,因为 -v 会删除命名卷。
日常运维
# 状态
docker compose ps
# 最近 100 行日志
docker compose logs --tail=100 freellmapi
# 重启服务,不删除命名卷
docker compose restart freellmapi
# 查看卷名称和挂载点
docker volume inspect freellmapi-data访问宿主机代理
如果提供商请求必须通过宿主机上的 Clash、v2rayN、sing-box 或企业代理,容器内的 127.0.0.1 指向容器本身,不能直接指向宿主机。将代理配置写入 .env,例如:
PROXY_URL=socks5h://host.docker.internal:7890宿主机代理必须监听非 loopback 地址并允许局域网连接(例如 Clash 的 allow-lan: true)。只在信任的网络中开放代理端口。
备份与恢复
FreeLLMAPI 的关键状态是命名卷中的 SQLite 文件,以及包含 ENCRYPTION_KEY 的 .env。备份时先停止写入,避免 SQLite 的 WAL 文件与主库处于不一致状态:
cd ~/freellmapi
mkdir -p backups
docker compose stop freellmapi
docker container run --rm \\
-v freellmapi-data:/data:ro \\
-v "$PWD/backups:/backup" \\
alpine:3.20 \\
tar czf /backup/freellmapi-data-$(date +%Y%m%d-%H%M%S).tar.gz -C /data .
cp .env "backups/.env-$(date +%Y%m%d-%H%M%S)"
chmod 600 backups/.env-*
docker compose start freellmapi备份文件和 .env 必须存放在受控位置;.env 泄露会使数据库中的加密密钥失去保护。恢复到同一主机时,先停止服务并清空目标卷,再解压备份。危险:恢复命令会删除目标卷中的现有文件,执行前先备份并确认文件名:
cd ~/freellmapi
docker compose down
docker container run --rm \\
-v freellmapi-data:/data \\
-v "$PWD/backups:/backup" \\
alpine:3.20 \\
sh -c 'rm -rf /data/* /data/.[!.]* /data/..?* && tar xzf /backup/freellmapi-data-YYYYMMDD-HHMMSS.tar.gz -C /data'
cp backups/.env-YYYYMMDD-HHMMSS .env
chmod 600 .env
docker compose up -d
docker compose ps
curl -i http://127.0.0.1:3001/api/ping将 YYYYMMDD-HHMMSS 替换为实际备份文件名。恢复后必须确认登录、提供商 key 解密和 /api/ping 均正常;不要在未备份的情况下更换 ENCRYPTION_KEY。
升级与回滚
本文固定在 v0.9.7。升级前先执行备份,并阅读目标版本的 Release notes:
cd ~/freellmapi
docker compose stop freellmapi
# 执行上一节的备份命令
docker compose up -d
docker compose ps
curl -i http://127.0.0.1:3001/api/ping升级时将 compose.yaml 的镜像 tag 和 digest 一起改为目标版本,然后执行:
docker compose pull
docker compose up -d
docker compose ps若新版本启动失败,先查看 docker compose logs --tail=200 freellmapi。可以把镜像 tag 和 digest 改回原版本后重新启动;如果新版本已经执行了不可逆的 SQLite migration,镜像回滚本身可能不够,必须按备份与恢复流程恢复数据库。不要把回滚当作数据库迁移的替代方案。
安全边界与生产加固
- FreeLLMAPI 官方定位是个人实验,不应直接暴露到互联网。默认
HOST_BIND=127.0.0.1,公网访问应放在带 TLS、访问控制和限流的反向代理之后。 ENCRYPTION_KEY、统一 API key、提供商 key 和任何PROXY_URL凭据都属于敏感信息。使用文件权限、主机密钥管理服务或 CI/CD secret 注入,不要写入镜像、Git 仓库或公开日志。- 只在必要时设置
HOST_BIND=0.0.0.0,并用主机防火墙限制来源网段。服务是单用户代理,不是多租户认证层。 - 保持镜像使用显式版本和 digest;升级先备份,再阅读版本说明并验证健康检查。
- 对外只发布 3001;SQLite、Docker socket 和命名卷不应通过额外端口暴露。
- 定期轮换提供商 key 和统一 API key,并保留可测试的数据库恢复副本。
常见问题
浏览器访问 server-ip:3001 一直等待
默认端口只绑定到 127.0.0.1,远程设备无法访问。确认 .env 中的 HOST_BIND=0.0.0.0,然后重建端口发布:
docker compose up -d
docker compose ps只在可信局域网使用该设置;公网场景应改为反向代理和 TLS。
容器健康检查失败
先读取有限日志并直接调用健康端点:
docker compose logs --tail=200 freellmapi
curl -i http://127.0.0.1:3001/api/ping若容器仍在初始化,等待 start_period 和首次迁移完成;若端口被其他进程占用,修改 .env 的 PORT 后重新执行 docker compose up -d。保持容器内端口为 3001,不要修改健康检查 URL。
容器能启动,但提供商请求失败
容器网络与宿主机隔离,宿主机上的代理地址不能在容器内写成 127.0.0.1。检查 .env 的 PROXY_URL 是否使用 host.docker.internal,并确认代理接受来自 Docker 网桥的连接:
docker compose exec freellmapi node -e "fetch('https://generativelanguage.googleapis.com/').then(r=>console.log('ok',r.status)).catch(e=>console.log('fail',e.cause?.code||e.message))"如果没有使用代理,检查 Docker DNS、主机出口和提供商账户配额。FreeLLMAPI 的免费提供商额度和服务可用性不由 Docker 部署保证。
重建容器后账户或提供商 key 消失
检查服务是否仍挂载 freellmapi-data,并确认没有使用 docker compose down -v:
docker compose config
docker volume inspect freellmapi-data如果命名卷已被删除,只能从备份恢复;同时恢复与数据库匹配的 .env,否则旧的加密 key 无法解密提供商配置。
总结
FreeLLMAPI 的推荐路径是使用固定版本的 GHCR 镜像和 Docker Compose:ENCRYPTION_KEY 保护 SQLite 中的提供商密钥,freellmapi-data 命名卷保存账号与路由配置,/api/ping 和 docker compose ps 提供基础健康验收。默认只绑定本机;局域网或公网访问前,应先配置可信网络、TLS、访问控制、备份和可验证的恢复流程。