Skip to content

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/amd64linux/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 在后续发布后改变:

text
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 解密。

Mermaid 流程图
查看源码
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 可用:

bash
docker --version
docker compose version
openssl version

Docker 官方安装入口:Install Docker Engine。主机需要能够访问 GHCR 和你启用的提供商 API。若通过反向代理提供 HTTPS,代理应转发到本机的 127.0.0.1:3001,并保留 X-Forwarded-Proto: https

Docker Compose 正式部署

创建工作目录和加密密钥

以下命令适用于 macOS、Linux 和 WSL。ENCRYPTION_KEY 用于保护数据库中的提供商密钥;请把 .env 当作敏感文件保存,不要提交到 Git 或粘贴到工单中。

bash
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 端点。

yaml
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 配置,确认端口和卷映射没有被环境变量意外覆盖:

bash
docker compose config

随后拉取固定镜像并启动服务:

bash
docker compose pull
docker compose up -d
docker compose ps

预期结果是 freellmapi 处于 running,并在健康检查通过后显示 healthy。首次启动可能需要等待镜像下载和 SQLite 初始化。

首次初始化

  1. 在部署主机打开 http://127.0.0.1:3001
  2. 按控制台提示创建第一个账户。若从其他设备访问,首次创建账户需要输入启动日志打印的一次性 setup code;先执行 docker compose logs --tail=100 freellmapi
  3. Keys 页面添加你有权使用的提供商 API key,并按需要调整 Fallback Chain
  4. Keys 页面获取统一 API key。OpenAI SDK 的 base_url 使用 http://127.0.0.1:3001/v1,请求的 api_key 使用统一 API key。

示例请求只验证接口形状,不包含任何真实提供商密钥:

bash
curl http://127.0.0.1:3001/v1/models \\
  -H 'Authorization: Bearer freellmapi-your-unified-key'

是否返回模型列表取决于控制台中已配置且可用的提供商;如果尚未添加提供商 key,先完成第 3 步。

验证部署结果

容器状态

bash
docker compose ps

预期 freellmapi 的状态包含 Up,健康列为 healthy。如果仍是 starting,等待一个健康检查周期再检查。

应用响应

bash
curl -i http://127.0.0.1:3001/api/ping

预期 HTTP 状态为 200。该端点也是 Compose 健康检查使用的端点。

日志

bash
docker compose logs --tail=100 freellmapi

检查日志中是否出现启动完成信息、端口监听信息和首次账户 setup code。不要长期使用无界的 docker compose logs -f 作为唯一验收证据。

持久化

bash
docker volume inspect freellmapi-data
docker compose down
docker compose up -d
docker compose ps

重新打开控制台,确认账户、提供商配置和模型路由仍然存在。不要使用 docker compose down -v 做这个检查,因为 -v 会删除命名卷。

日常运维

bash
# 状态
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,例如:

dotenv
PROXY_URL=socks5h://host.docker.internal:7890

宿主机代理必须监听非 loopback 地址并允许局域网连接(例如 Clash 的 allow-lan: true)。只在信任的网络中开放代理端口。

备份与恢复

FreeLLMAPI 的关键状态是命名卷中的 SQLite 文件,以及包含 ENCRYPTION_KEY.env。备份时先停止写入,避免 SQLite 的 WAL 文件与主库处于不一致状态:

bash
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 泄露会使数据库中的加密密钥失去保护。恢复到同一主机时,先停止服务并清空目标卷,再解压备份。危险:恢复命令会删除目标卷中的现有文件,执行前先备份并确认文件名:

bash
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

bash
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 一起改为目标版本,然后执行:

bash
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,然后重建端口发布:

bash
docker compose up -d
docker compose ps

只在可信局域网使用该设置;公网场景应改为反向代理和 TLS。

容器健康检查失败

先读取有限日志并直接调用健康端点:

bash
docker compose logs --tail=200 freellmapi
curl -i http://127.0.0.1:3001/api/ping

若容器仍在初始化,等待 start_period 和首次迁移完成;若端口被其他进程占用,修改 .envPORT 后重新执行 docker compose up -d。保持容器内端口为 3001,不要修改健康检查 URL。

容器能启动,但提供商请求失败

容器网络与宿主机隔离,宿主机上的代理地址不能在容器内写成 127.0.0.1。检查 .envPROXY_URL 是否使用 host.docker.internal,并确认代理接受来自 Docker 网桥的连接:

bash
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

bash
docker compose config
docker volume inspect freellmapi-data

如果命名卷已被删除,只能从备份恢复;同时恢复与数据库匹配的 .env,否则旧的加密 key 无法解密提供商配置。

总结

FreeLLMAPI 的推荐路径是使用固定版本的 GHCR 镜像和 Docker Compose:ENCRYPTION_KEY 保护 SQLite 中的提供商密钥,freellmapi-data 命名卷保存账号与路由配置,/api/pingdocker compose ps 提供基础健康验收。默认只绑定本机;局域网或公网访问前,应先配置可信网络、TLS、访问控制、备份和可验证的恢复流程。

参考资料

全部公开文章由同一个站点构建和发布。