07 通过Docker部署Chatbox API

Chatbox界面简洁,速度很快,隐私性强,又可以方便地自定义system提示词,是众多ChatGPT客户端中脱颖而出的一款。除了使用作者提供的付费License之外,也可以自己填入OpenAI API Key来使用。但是,API Key直接Copy给别人似乎有点不妥,直接用OpenAI的API地址还需要科学上网,多少有点不便。

作者一早提供了Docker方式搭建自己的OpenAI API Service的方案,但由于手头一直没有Linux VPS,所以没有实践。现在条件已经具备,走起!

首先配置Docker环境。这一步非常简单:

curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

第二步,根据作者提示,推荐采用HTTPS方式提供Service,当然我们就选用这种方式。

docker run -p 80:80 -p 443:443 \
-v ./caddy_config:/config -v ./caddy_data:/data \
-e HOST=<YOUR_DOMAIN> \
-e KEY=<YOUR_OPENAI_KEY> \
bensdocker/chatbox-team

第一个错误提示:443端口已被占用。由此可见,docker的端口如果想要映射宿主机的443端口,它是独占方式映射,不能和nginx“共享”443端口。这种情况下,就必须将宿主机的443端口变成另一个端口,例如3001端口,同时把nginx中的443端口对应的域名网站,通过proxy_pass反向代理到3001端口,这样就可以实现和谐共存。

此外,默认的80:80映射似乎也用不上,删掉它。改成这样运行:

docker run -p 3001:443 \
-v ./caddy_config:/config -v ./caddy_data:/data \
-e HOST=<YOUR_DOMAIN> \
-e KEY=<YOUR_OPENAI_KEY> \
bensdocker/chatbox-team

依然报错,这次报错502 Bad Gateway,这看上去似乎是SSL哪里出了问题。考虑到nginx是反向代理到3001,再由docker映射到内部的443端口,我猜测此时docker的运行已经与域名无关,于是将HOST参数修改为127.0.0.1,错误依旧。继续修改HOST为0.0.0.0,错误依旧。

由于前面的测试均在docker run后面加上了-d参数,所以没有详细的日志输出。现在将-d去掉,从详细日志中,很快发现,docker是通过caddy去访问Let's Encrypt,并尝试获取HOST参数对应域名的TLS证书,失败之后,又自动进行所谓的HTTP-01挑战,由于没有事先配置Challenge文件,挑战当然会失败。而我的HOST对应的域名,并非通过Let's Encrypt申请的证书,这也是为什么caddy总是验证失败的原因。

【20231104补充】现在已经清楚,作者本意是自动使用脚本在Let's Encrypt上申请证书。而这么做的前提是,需要首先打开80端口的HTTP服务。由于我一开始就关闭了80端口,这是它配置失败的原因。另外,我已经手动申请了SSL证书,且宿主机使用的并非443端口,所以在本例中,还是手动配置更合适。

怪不得作者的readme.md没有介绍如何配置HTTPS网站,敢情它是傻瓜到家了,“妄图”用脚本帮你完成自动配置,你只需要做一个DNS解析就行了。可惜帮忙帮的太多,反而搞不定啦。

搞清楚了原因,解决就简单了。我们不要让HTTPS的TLS验证在docker内部执行,这件事儿交给nginx来做就行了。像通常那样设置好域名、443端口,绑定pem、Key文件,然后反向代理到3001。docker run时,将3001映射到docker的80端口即可。既然采用了80端口使用的是HTTP协议,那么HOST这个参数就必须删掉。否则程序只要看到HOST有定义,就会将容器内部的80再次重定向443,而为127.0.0.1设置443结果显然会失败。

docker run -d -p 3001:80 \ 
-v ./caddy_config:/config -v ./caddy_data:/data \ 
-e KEY=<YOUR_OPENAI_KEY> \ 
bensdocker/chatbox-team

Boom!成功。

By the way,如果要让docker开机自启动,加上参数:

--restart unless-stopped \

即可。