搞 AI 应用的开发者和运维应该对 New-API 不陌生了。一句话解释,它就是一个大模型 API 统一网关:把 OpenAI、Claude、Gemini、DeepSeek、智谱、Ollama 等各种各样的渠道接进来,然后对外输出一套标准的 OpenAI 兼容接口,统一管密钥、管额度、管日志、管用户权限。很多团队直接拿它当 AI API 网关用,省掉了在每个业务系统里单独维护密钥和计费逻辑的重复劳动。这篇文章我会从零开始,把 New-API 的在线部署和离线部署完整梳理一遍,技术栈就锁定 MySQL + Docker。无论你是在有外网的开发机上快速体验,还是在内网服务器上闭门造车,都能照着做。
先说清楚:New-API 本身用 Go 写的,部署非常简单,难点反而在数据层和容器编排上。MySQL 负责持久化渠道、令牌、日志、用户信息;Docker 负责把应用和数据库隔离在同一套环境里;Docker Compose 负责一键拉起这两个服务。把这个组合装明白了,后续的升级、备份、迁机都变得很直观。下面直接进入正文。
1. 部署前的整体思路与方案选型
1.1 New-API 是什么,为什么值得用
New-API 是 one-api 的一个高活跃度分支,在保留原有核心能力的基础上,补了很多适合团队使用的功能。它的核心模型可以概括成三层:第一层是“渠道”,也就是上游的大模型服务,比如 DeepSeek、通义千问、OpenAI,甚至你本地起的 Ollama;第二层是“令牌”,类似 API Key,给不同业务线、不同同事分配一个独立令牌;第三层是“日志”,所有请求都会留下轨迹,方便看调用量、延迟和失败原因。
我对这套东西最满意的地方是“模型映射”能力。比如你的业务代码里写死了gpt-4o,但实际想用某个国产模型顶上,不用改代码,直接在渠道里做一个模型映射,把gpt-4o指到deepseek-chat上。对上层应用来说,它只认识一个 OpenAI 格式的接口,后端换成什么模型完全不影响。这种解耦方式在多模型切换、灰度测试、成本控制的场景下特别好用。
1.2 为什么数据库一定要用 MySQL,而不是默认的 SQLite
New-API 本身支持 SQLite,本地快速玩玩用 SQLite 完全没问题,但我强烈建议正式环境直接用 MySQL。原因有几个:
- 并发能力:API 网关是高并发写入场景,每个请求都要记录日志,SQLite 的锁机制容易成为瓶颈。MySQL 在并发写入和查询上稳定太多。
- 数据安全与备份:MySQL 可以做到在线备份、主从同步、按时间点恢复,SQLite 想在线备份还得费一番功夫。
- 运维生态:团队里会 MySQL 的人远比懂 SQLite 的人多,出问题也好找人排查。
- 数据迁移:将来 New-API 要换机器、换部署方式,MySQL 的数据文件或者 mysqldump 都容易操作。
所以这篇文章的统一前提就是用 MySQL 8.0,容器化方式运行,和 New-API 一样都用 Docker 管理。
1.3 在线和离线部署的差异点在哪
在线环境部署的核心就是拉镜像、跑容器,没什么磕绊。离线环境则完全换了一套玩法:目标机器上不了 Docker Hub,也没法直接用 apt/yum 在线装 Docker。因此离线部署的关键在于两件事:第一,提前在有网机器上拉好镜像、导成 tar 包;第二,提前准备好 Docker 和 Docker Compose 的离线安装包,一起拷贝到内网服务器。
很多人在离线部署时翻车,不是 New-API 本身的问题,而是卡在 Docker 装不上去、镜像加载不进去。所以下面我专门安排了一节,把离线准备镜像、离线安装 Docker、离线加载镜像的路径捋顺。
2. 环境准备与目标规划
2.1 主机资源与端口规划
先说主机要求。New-API 本身是 Go 写的,内存占用不高,MySQL 才是大头。个人测试用 1 核 2G 就够了,生产环境建议 2 核 4G 以上,磁盘至少给 10G。操作系统建议用 Ubuntu 20.04/22.04 LTS 或者 CentOS 7.9/Stream 8,Windows 的 Docker Desktop 也能跑,但服务器环境更推荐 Linux。
端口规划上,New-API 默认监听 3000 端口,MySQL 默认 3306。部署时我给 MySQL 做了“屏蔽”——不把 3306 映射到宿主机,只让容器内网访问,这样避免数据库端口直接暴露。如果你需要从宿主机连接数据库排查问题,可以在需要时临时加映射,用完再关。
目录规划同样重要,我习惯把整个项目放在/opt/new-api下,里面再分成数据目录和配置文件目录。数据目录单独挂载,之后升级、备份都不动它。
2.2 在线安装 Docker 和 Docker Compose
在线环境的 Docker 安装没什么难度。Ubuntu 用户可以用官方脚本:
curl -fsSL https://get.docker.com | sh systemctl enable --now dockerCentOS 用户也可以先用官方脚本。装完验证一下:
docker version docker compose version新版 Docker 已经内置了docker compose插件,老机器如果提示没有 compose,可以单独装插件,或者用docker-compose二进制放到/usr/local/bin/docker-compose并加执行权限。本文示例命令统一用docker compose空格形式,如果你用的是老版本且只有docker-compose,把命令中间的空格换成短横线即可。
2.3 镜像选择与版本策略
镜像选型是部署能否顺利推进的第一步。New-API 官方镜像在 Docker Hub 上有多个仓库,我这边用过比较多的是calciumion/new-api,版本标签建议直接看官方 GitHub Releases 页面,选最新的稳定版,不要无脑用latest。生产环境我习惯把版本号固定下来,比如calciumion/new-api:v1.1.1,这样升级和回滚都能精确控制。
MySQL 镜像用mysql:8.0,这个版本经过多年验证,兼容性和稳定性都足够好。如果你所在机构有内网镜像仓库,可以在线环境先把镜像推到私有仓库,离线环境直接从内网仓库拉,更加标准。如果没有,就走后续的 tar 包方案。为了避免拉取 Docker Hub 太慢,在线环境也可以配置国内的镜像加速器之后再拉取,按自己网络实际情况来。
3. 在线环境快速部署(Docker Compose 一次成型)
3.1 编写 docker-compose.yml
在线部署最舒服的方式就是 Docker Compose。我先把一份可以开箱即用的 compose 文件贴出来,然后逐项解释关键配置。
services: mysql: image: mysql:8.0 container_name: newapi-mysql restart: always environment: TZ: Asia/Shanghai MYSQL_ROOT_PASSWORD: change_root_password MYSQL_DATABASE: new-api MYSQL_USER: newapi MYSQL_PASSWORD: change_newapi_password command: - --character-set-server=utf8mb4 - --collation-server=utf8mb4_unicode_ci volumes: - ./mysql-data:/var/lib/mysql healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 5s timeout: 5s retries: 20 new-api: image: calciumion/new-api:latest container_name: new-api restart: always depends_on: mysql: condition: service_healthy ports: - "3000:3000" environment: TZ: Asia/Shanghai SQL_DSN: newapi:change_newapi_password@tcp(mysql:3306)/new-api?charset=utf8mb4&parseTime=True&loc=Local SESSION_SECRET: please_change_this_secret LOG_LEVEL: info volumes: - ./new-api-data:/data注意,新版 Docker Compose 已经可以不写version字段,所以这里直接以services:开始。老版本如果要写,就补一行version: "3.8"放在最前面,两种写法都行。
3.2 关键配置逐条解释
mysql服务里有几个细节必须说清楚。第一,MYSQL_DATABASE和MYSQL_USER、MYSQL_PASSWORD这三个变量会在 MySQL 容器首次初始化数据目录时自动创建一个名为new-api的库,并创建一个只拥有该库权限的用户newapi。这是最省心的方式,你不需要提前连进去手动建库。第二,command里强制指定了utf8mb4字符集和排序规则,这是为了完整支持表情符号和多语言文本,日志内容里可能会带上各种奇怪字符。第三,我加了healthcheck,让 MySQL 在完成初始化和就绪之前,不被new-api视为可依赖服务。
new-api服务里的核心环境变量是SQL_DSN。这个连接串的格式必须严格匹配:用户名、密码、tcp(mysql:3306)里的mysql指向上面的 MySQL 服务名,而不是127.0.0.1。在 Docker Compose 网络中,服务名mysql可以被同一个网络下的new-api容器直接解析。parseTime=True和loc=Local是 Go 的 MySQL 驱动处理时间字段的必要参数,少了它们可能遇到时间格式问题。
SESSION_SECRET是会话加密密钥,一定要改成你自己的随机字符串,别用示例里的值。这个值如果换成新的,所有登录态会失效,用户要重新登录。我踩过一次坑,升级后忘了保留这个环境变量,结果线上所有用户被强制踢下线。
3.3 首次启动、初始化与创建管理员
配置文件准备好后,在/opt/new-api目录下执行:
docker compose up -d第一次启动会比想象中慢,因为 MySQL 要在空白数据目录里做初始化。你可以用下面的命令观察日志:
docker compose logs -f mysql docker compose logs -f new-api看到 MySQL 日志里出现“ready for connections”,New-API 日志里没有报错后,打开浏览器访问http://你的服务器IP:3000。首次访问会引导你初始化管理员账号,填一个邮箱和密码即可。第一次访问的注册行为是否开放,其实由环境变量控制,默认首次注册即可成为超级管理员,建议初始化完成之后立刻进后台关闭“允许注册”,避免暴露在公网时被陌生人注册。
初始化完成后,建议先做一个基础验证。在后台“令牌”页面创建一个新令牌,然后命令行里用 curl 测试一下:
curl http://127.0.0.1:3000/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer 你的令牌" \ -d '{"model": "deepseek-chat", "messages": [{"role": "user", "content": "你好"}]}'如果你还没有任何渠道,这一步会报错提示没有可用渠道,这是正常现象。下一步就是去“渠道”页面接一个上游模型。
3.4 添加渠道:以 DeepSeek 和本地 Ollama 为例
添加 DeepSeek 很简单,后台渠道类型选“DeepSeek”,BaseURL 填官方 API 地址https://api.deepseek.com,密钥填你在 DeepSeek 开放平台生成的 API Key,模型列表填deepseek-chat,deepseek-reasoner。保存后刚才的 curl 测试就能通了。
如果你的内网或本机跑着 Ollama,比如本地已经用ollama run qwen2.5拉好了模型,也可以在 New-API 里添加一个 Ollama 渠道。这里有个坑:New-API 跑在 Docker 容器里,它访问宿主机的 Ollama 不能直接写127.0.0.1。在 Windows/Mac 的 Docker Desktop 下可以用http://host.docker.internal:11434;在 Linux 下建议直接用宿主机内网 IP,比如http://192.168.1.100:11434。模型名填 Ollama 里实际的模型名,如qwen2.5。这样你的业务系统只需要用 New-API 的地址,就能间接调用本地模型,不用去管 Ollama 的位置。
3.5 在线部署时的升级与回滚
在线环境升级 New-API 很流畅,但前提是你要把数据备份做好。升级前先备份数据库:
docker exec newapi-mysql mysqldump -unewapi -pchange_newapi_password new-api > backup_$(date +%F).sql然后更新镜像并重启:
docker compose pull new-api docker compose up -d回滚的做法是:在 compose 文件里把image改回旧版本号,然后docker compose up -d。只要数据库没有做破坏性迁移,旧版本基本都能正常连上。
4. 离线环境部署全流程
离线部署是很多内网项目的关键诉求。下面我按照“有网准备机 → 目标内网机”两段式流程来写,保证每一步都能落地。
4.1 在有网环境准备镜像和安装包
先在任意一台能访问 Docker Hub 的 Linux 机器上,拉取目标镜像并导出成 tar 包。
docker pull calciumion/new-api:latest docker pull mysql:8.0 docker save -o new-api.tar calciumion/new-api:latest docker save -o mysql-8.0.tar mysql:8.0docker save会把镜像完整导出,包括所有历史层,所以 tar 包会比较大。MySQL 8.0 的镜像一般 500MB 左右,New-API 大概几十到一百多 MB。你可以用gzip压缩一下再传:
gzip new-api.tar mysql-8.0.tar另外还要准备 Docker 本身的离线安装包。如果是 Ubuntu,可以在有网机器上先下载所有需要的 deb 包,再拷贝到内网安装;更通用的做法是下载 Docker 官方静态二进制包。访问 Docker 官方 GitHub Releases,下载对应架构(amd64/arm64)的docker-27.x.tgz,同时把docker-compose插件二进制或者老版本docker-compose二进制也下载好。把这些文件和两个镜像 tar 包放到同一个传输目录,用 scp 或者运维系统的文件分发通道传到内网目标机器。
4.2 离线安装 Docker 与 Compose
目标机器如果是 CentOS/Ubuntu,可以优先尝试用系统自带的软件包离线安装方式。这里以静态二进制包为例,兼容性最稳:
tar -xzf docker-27.x.tgz cp docker/* /usr/local/bin/然后写 systemd 服务文件,让 Docker 进程由 systemd 托管。官方仓库里自带contrib/systemd目录下的 unit 文件,拷贝到/etc/systemd/system/下即可。之后执行:
systemctl daemon-reload systemctl enable --now docker如果没有官方 systemd 文件,也可以先手动启动dockerd &验证,但生产环境还是建议用 systemd 托管,不然重启后 Docker 起不来。
Compose 插件的离线安装:把之前下载的docker-compose二进制放到/usr/local/lib/docker/cli-plugins/docker-compose,并加执行权限:
chmod +x /usr/local/lib/docker/cli-plugins/docker-compose docker compose version如果放插件路径不生效,直接把二进制复制为/usr/local/bin/docker-compose也可以,用docker-compose命令调用。
4.3 加载镜像并启动服务
目标机器上先创建部署目录:
mkdir -p /opt/new-api && cd /opt/new-api把之前准备的new-api.tar.gz、mysql-8.0.tar.gz解压后,用docker load导入镜像:
gzip -d new-api.tar.gz mysql-8.0.tar.gz docker load -i new-api.tar docker load -i mysql-8.0.tar执行后可以用docker images确认两个镜像已在本地。接着把在线环境用的那份docker-compose.yml复制到/opt/new-api下,注意修改 SQL_DSN 和管理密码。因为目标机器不会去 Docker Hub 拉镜像,compose 文件里的 image 名字必须和你 load 进来的镜像名完全一致,比如calciumion/new-api:latest和mysql:8.0。如果 Load 进来的镜像名是calciumion/new-api:latest,但 compose 里写的是calciumion/new-api:latest,那就没问题。如果之前是从私有仓库拉取的,load 后名字可能会带内网仓库路径,这时候要先把镜像重新打上 tag,再跑 compose:
docker tag 内网仓库域名/calciumion/new-api:latest calciumion/new-api:latest最后启动:
docker compose up -d离线环境的启动流程和在线环境完全一样,看日志、等 MySQL 初始化、访问页面初始化管理员。唯一容易碰壁的坑是:MySQL 首次初始化时如果数据目录在 NFS 或特定挂载磁盘上,可能因为权限问题失败。解决办法是给数据目录一个足够宽松的权限:
mkdir -p /opt/new-api/mysql-data chmod 777 /opt/new-api/mysql-data不过生产环境不建议一直用 777,初始化完可以收紧权限,改成当前运行容器进程的 UID 对应的属主。
4.4 离线环境怎么升级
离线升级不比在线难多少,只是需要把“准备新镜像”这一步也搬到有网环境。流程是:
- 有网环境重新拉取新版本 New-API 镜像,
docker save导出。 - 把新 tar 包传到内网机器,
docker load导入。 - 修改 compose 文件里的 image 标签版本号,
docker compose up -d。 - 如果升级失败,再把旧镜像重新 load 并改回旧版本号,启动即可回滚。
所以离线环境最值钱的其实是那套 compose 文件和 mysql-data 数据目录。只要数据目录在,换机器、换镜像都只是时间问题。
5. 常见问题与排查技巧实录
5.1 问题速查表
我在部署和给朋友排查的过程中,把高频问题整理成了下面的表格,可以当速查手册用。
| 问题现象 | 可能原因 | 解决办法 |
|---|---|---|
| new-api 容器反复重启 | SQL_DSN 连接串错误,或 MySQL 还没就绪 | 检查 SQL_DSN 密码、服务名;看docker compose logs new-api |
| 页面提示数据库连接失败 | SQL_DSN 里写成 127.0.0.1 | Compose 环境内必须用服务名mysql |
| MySQL 容器启动后立刻退出 | 数据目录权限不对,或端口冲突 | 删掉 mysql-data 重新初始化,或检查端口占用 |
| 访问 3000 端口超时 | 宿主机防火墙未放行 | 开放端口:firewall-cmd --add-port=3000/tcp或 ufw allow 3000 |
| 日志全是乱码或时间不对 | 容器时区没有设置 | 给所有服务都加上TZ: Asia/Shanghai |
| Windows Docker Desktop 提示 virtualization not detected | 宿主机 BIOS 未开启虚拟化 | 重启进 BIOS 开启 VT-x/AMD-V,并启用 Hyper-V/WSL2 |
| 添加 Ollama 渠道后调用报 connection refused | 容器内访问宿主机地址错误 | Linux 用宿主机 IP,Win/Mac 用 host.docker.internal |
| 登录后台后点击某些页面白屏 | New-API 版本与浏览器缓存不兼容 | 清缓存或无痕窗口重试;升级到最新版本 |
5.2 日志排查三板斧
遇到问题先别急着重启,按顺序做三道检查。第一道看 MySQL 日志,确认数据库是否正常启动;第二道看 New-API 日志,重点看里面有没有带SQL_DSN、connect、refused字样的报错;第三道进容器里手动连一下数据库:
docker exec -it newapi-mysql mysql -unewapi -pchange_newapi_password new-api -e "select 1;"能输出1,说明数据库连接没问题,问题出在应用层。两边都正常还是不行,就把LOG_LEVEL环境变量改成debug,重启 New-API 再试,日志会详细很多。我在线上排查过几次类似问题,80% 都是 SQL_DSN 写错或者 MySQL 数据目录权限不对。
5.3 一个容易被忽略的数据安全细节
New-API 的日志表会一直增长,尤其是接入多个业务系统后,每天可能产生几十万条请求日志。MySQL 数据目录如果不定期清理,磁盘会逐渐打满。我习惯在后台日志页面定期清理老日志,或者直接写一个定时任务,删除 30 天前的日志表数据。如果业务上不需要长期审计,可以用 cron 定期执行清理:
docker exec newapi-mysql mysql -unewapi -pchange_newapi_password new-api -e "DELETE FROM logs WHERE created_at < DATE_SUB(NOW(), INTERVAL 30 DAY);"这种方式虽然简单粗暴,但真的能让 MySQL 长期保持轻量。删除前记得确认下 New-API 的相关表结构,不同版本表名可能有差异。
我个人在实际操作中的体会是,New-API 部署本身不难,难的是把数据层和容器生命周期维护好。尤其离线环境,很多团队把镜像和数据包拖进内网后就以为万事大吉,真正跑起来才发现权限、服务名、时区、防火墙各种细碎问题。所以在一开始就把 compose 文件、数据目录、环境变量定义清楚,后面会省很多事。最后再分享一个我养成的习惯:每次部署或升级结束,我都在/opt/new-api下额外保存一份和当前运行的 compose 文件完全一致的副本,并在文件名里加上日期。如果真的把环境搞坏了,直接照着旧配置恢复,比临时回忆快得多。这套 MySQL + Docker 的组合,我用了很久,无论是个人项目还是团队网关,都跑得很稳定。