Spaces:
Paused
Paused
icebear0828 commited on
Commit ·
7ff102d
1
Parent(s): d44918f
feat: Docker image auto-publish to GHCR + Watchtower support
Browse files- Add docker-publish.yml workflow: multi-arch (amd64/arm64) build on
every push to master, published to ghcr.io/icebear0828/codex-proxy
- Switch docker-compose.yml from local build to pre-built GHCR image
- Add commented Watchtower service block for automatic updates
- Simplify README Docker section: no git clone needed, just curl configs
- Update dashboard Docker hint to mention Watchtower option
- Add dockerAutoUpdateHint i18n key (en/zh)
- .github/workflows/docker-publish.yml +52 -0
- CHANGELOG.md +1 -0
- README.md +25 -9
- docker-compose.yml +11 -1
- shared/i18n/translations.ts +2 -0
- src/routes/web.ts +1 -1
- web/src/components/UpdateModal.tsx +11 -6
.github/workflows/docker-publish.yml
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Publish Docker Image
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
push:
|
| 5 |
+
branches: [master]
|
| 6 |
+
workflow_dispatch:
|
| 7 |
+
|
| 8 |
+
concurrency:
|
| 9 |
+
group: docker-publish
|
| 10 |
+
cancel-in-progress: true
|
| 11 |
+
|
| 12 |
+
permissions:
|
| 13 |
+
contents: read
|
| 14 |
+
packages: write
|
| 15 |
+
|
| 16 |
+
jobs:
|
| 17 |
+
publish:
|
| 18 |
+
runs-on: ubuntu-latest
|
| 19 |
+
steps:
|
| 20 |
+
- uses: actions/checkout@v4
|
| 21 |
+
|
| 22 |
+
- name: Read version from package.json
|
| 23 |
+
id: version
|
| 24 |
+
run: echo "version=$(node -p "require('./package.json').version")" >> "$GITHUB_OUTPUT"
|
| 25 |
+
|
| 26 |
+
- uses: docker/setup-qemu-action@v3
|
| 27 |
+
|
| 28 |
+
- uses: docker/setup-buildx-action@v3
|
| 29 |
+
|
| 30 |
+
- uses: docker/login-action@v3
|
| 31 |
+
with:
|
| 32 |
+
registry: ghcr.io
|
| 33 |
+
username: ${{ github.actor }}
|
| 34 |
+
password: ${{ secrets.GITHUB_TOKEN }}
|
| 35 |
+
|
| 36 |
+
- uses: docker/metadata-action@v5
|
| 37 |
+
id: meta
|
| 38 |
+
with:
|
| 39 |
+
images: ghcr.io/icebear0828/codex-proxy
|
| 40 |
+
tags: |
|
| 41 |
+
type=raw,value=latest
|
| 42 |
+
type=raw,value=v${{ steps.version.outputs.version }}
|
| 43 |
+
|
| 44 |
+
- uses: docker/build-push-action@v6
|
| 45 |
+
with:
|
| 46 |
+
context: .
|
| 47 |
+
platforms: linux/amd64,linux/arm64
|
| 48 |
+
push: true
|
| 49 |
+
tags: ${{ steps.meta.outputs.tags }}
|
| 50 |
+
labels: ${{ steps.meta.outputs.labels }}
|
| 51 |
+
cache-from: type=gha
|
| 52 |
+
cache-to: type=gha,mode=max
|
CHANGELOG.md
CHANGED
|
@@ -8,6 +8,7 @@
|
|
| 8 |
|
| 9 |
### Added
|
| 10 |
|
|
|
|
| 11 |
- 双窗口配额显示:Dashboard 账号卡片同时展示主窗口(小时限制)和次窗口(周限制)的用量百分比、进度条和重置时间,后端 `secondary_window` 不再被忽略
|
| 12 |
- 更新弹窗 + 自动重启:点击"有可用更新"弹出 Modal 显示 changelog,一键更新后服务器自动重启、前端自动刷新,零人工干预(git 模式 spawn 新进程、Docker/Electron 显示对应操作指引)
|
| 13 |
- Model-aware 多计划账号路由:不同 plan(free/plus/business)的账号自动路由到各自支持的模型,business 账号可继续使用 gpt-5.4 等高端模型 (#57)
|
|
|
|
| 8 |
|
| 9 |
### Added
|
| 10 |
|
| 11 |
+
- Docker 镜像自动发布:push master 自动构建多架构(amd64/arm64)镜像到 GHCR(`ghcr.io/icebear0828/codex-proxy`),docker-compose.yml 切换为预构建镜像,支持 Watchtower 自动更新
|
| 12 |
- 双窗口配额显示:Dashboard 账号卡片同时展示主窗口(小时限制)和次窗口(周限制)的用量百分比、进度条和重置时间,后端 `secondary_window` 不再被忽略
|
| 13 |
- 更新弹窗 + 自动重启:点击"有可用更新"弹出 Modal 显示 changelog,一键更新后服务器自动重启、前端自动刷新,零人工干预(git 模式 spawn 新进程、Docker/Electron 显示对应操作指引)
|
| 14 |
- Model-aware 多计划账号路由:不同 plan(free/plus/business)的账号自动路由到各自支持的模型,business 账号可继续使用 gpt-5.4 等高端模型 (#57)
|
README.md
CHANGED
|
@@ -79,32 +79,48 @@ Docker 就像一个"打包好的盒子",不需要你自己装各种依赖,
|
|
| 79 |
|
| 80 |
**前置条件**:电脑上已安装 Docker。如果没有,先去 [docker.com](https://www.docker.com/products/docker-desktop/) 下载安装 Docker Desktop。
|
| 81 |
|
| 82 |
-
**第 1 步:
|
| 83 |
|
| 84 |
打开终端(Windows 搜索"cmd"或"PowerShell";macOS 搜索"终端"),输入:
|
| 85 |
|
| 86 |
```bash
|
| 87 |
-
|
| 88 |
-
cd codex-proxy
|
| 89 |
```
|
| 90 |
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
**第 2 步:创建配置文件并启动**
|
| 94 |
|
| 95 |
```bash
|
|
|
|
|
|
|
| 96 |
cp .env.example .env # 复制一份配置模板
|
| 97 |
-
docker compose up -d # 启动服务(后台运行)
|
| 98 |
```
|
| 99 |
|
| 100 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
|
| 102 |
打开浏览器,访问 `http://localhost:8080`,用 ChatGPT 账号登录。
|
| 103 |
|
| 104 |
-
> 你的账号数据会保存在
|
| 105 |
>
|
| 106 |
> **其他 Docker 容器要连本服务?** 用你电脑的局域网 IP(如 `http://192.168.x.x:8080/v1`),不要用 `localhost`。
|
| 107 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
---
|
| 109 |
|
| 110 |
### 方式三:源码运行(开发者 / 想改代码的用户)
|
|
|
|
| 79 |
|
| 80 |
**前置条件**:电脑上已安装 Docker。如果没有,先去 [docker.com](https://www.docker.com/products/docker-desktop/) 下载安装 Docker Desktop。
|
| 81 |
|
| 82 |
+
**第 1 步:创建项目目录**
|
| 83 |
|
| 84 |
打开终端(Windows 搜索"cmd"或"PowerShell";macOS 搜索"终端"),输入:
|
| 85 |
|
| 86 |
```bash
|
| 87 |
+
mkdir codex-proxy && cd codex-proxy
|
|
|
|
| 88 |
```
|
| 89 |
|
| 90 |
+
**第 2 步:下载配置文件**
|
|
|
|
|
|
|
| 91 |
|
| 92 |
```bash
|
| 93 |
+
curl -O https://raw.githubusercontent.com/icebear0828/codex-proxy/master/docker-compose.yml
|
| 94 |
+
curl -O https://raw.githubusercontent.com/icebear0828/codex-proxy/master/.env.example
|
| 95 |
cp .env.example .env # 复制一份配置模板
|
|
|
|
| 96 |
```
|
| 97 |
|
| 98 |
+
> 也可以用 `git clone` 下载完整源码,然后在项目目录中 `docker compose up -d`。
|
| 99 |
+
|
| 100 |
+
**第 3 步:启动**
|
| 101 |
+
|
| 102 |
+
```bash
|
| 103 |
+
docker compose up -d # 拉取镜像并启动(后台运行)
|
| 104 |
+
```
|
| 105 |
+
|
| 106 |
+
**第 4 步:登录**
|
| 107 |
|
| 108 |
打开浏览器,访问 `http://localhost:8080`,用 ChatGPT 账号登录。
|
| 109 |
|
| 110 |
+
> 你的账号数据会保存在 `data/` 文件夹里,重启不会丢失。
|
| 111 |
>
|
| 112 |
> **其他 Docker 容器要连本服务?** 用你电脑的局域网 IP(如 `http://192.168.x.x:8080/v1`),不要用 `localhost`。
|
| 113 |
|
| 114 |
+
**可选:自动更新**
|
| 115 |
+
|
| 116 |
+
取消 `docker-compose.yml` 中 Watchtower 服务的注释,即可实现自动更新:
|
| 117 |
+
|
| 118 |
+
```bash
|
| 119 |
+
docker compose up -d # 重新启动,Watchtower 将每小时检查更新
|
| 120 |
+
```
|
| 121 |
+
|
| 122 |
+
Watchtower 会自动检测新镜像版本,拉取并重启容器,无需手动操作。
|
| 123 |
+
|
| 124 |
---
|
| 125 |
|
| 126 |
### 方式三:源码运行(开发者 / 想改代码的用户)
|
docker-compose.yml
CHANGED
|
@@ -1,6 +1,8 @@
|
|
| 1 |
services:
|
| 2 |
codex-proxy:
|
| 3 |
-
|
|
|
|
|
|
|
| 4 |
extra_hosts:
|
| 5 |
- "host.docker.internal:host-gateway"
|
| 6 |
ports:
|
|
@@ -15,3 +17,11 @@ services:
|
|
| 15 |
environment:
|
| 16 |
- NODE_ENV=production
|
| 17 |
- PORT=8080
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
services:
|
| 2 |
codex-proxy:
|
| 3 |
+
image: ghcr.io/icebear0828/codex-proxy:latest
|
| 4 |
+
# To build from source instead: comment out 'image' above, uncomment 'build' below
|
| 5 |
+
# build: .
|
| 6 |
extra_hosts:
|
| 7 |
- "host.docker.internal:host-gateway"
|
| 8 |
ports:
|
|
|
|
| 17 |
environment:
|
| 18 |
- NODE_ENV=production
|
| 19 |
- PORT=8080
|
| 20 |
+
|
| 21 |
+
# -- Automatic updates (uncomment to enable) --
|
| 22 |
+
# watchtower:
|
| 23 |
+
# image: containrrr/watchtower
|
| 24 |
+
# volumes:
|
| 25 |
+
# - /var/run/docker.sock:/var/run/docker.sock
|
| 26 |
+
# command: --cleanup --interval 3600 codex-proxy
|
| 27 |
+
# restart: unless-stopped
|
shared/i18n/translations.ts
CHANGED
|
@@ -151,6 +151,7 @@ export const translations = {
|
|
| 151 |
dockerUpdateCmd: "Run to update:",
|
| 152 |
downloadUpdate: "Download",
|
| 153 |
electronUpdateHint: "Updates are handled automatically. Restart the app or check the system tray for update notifications.",
|
|
|
|
| 154 |
updateTitle: "Update Available",
|
| 155 |
updateRestarting: "Restarting server...",
|
| 156 |
updatePulling: "Pulling code...",
|
|
@@ -329,6 +330,7 @@ export const translations = {
|
|
| 329 |
dockerUpdateCmd: "\u6267\u884c\u66f4\u65b0\u547d\u4ee4\uff1a",
|
| 330 |
downloadUpdate: "\u4e0b\u8f7d",
|
| 331 |
electronUpdateHint: "\u66f4\u65b0\u7531\u684c\u9762\u7aef\u81ea\u52a8\u5904\u7406\u3002\u91cd\u542f\u5e94\u7528\u6216\u68c0\u67e5\u7cfb\u7edf\u6258\u76d8\u7684\u66f4\u65b0\u901a\u77e5\u3002",
|
|
|
|
| 332 |
updateTitle: "\u6709\u53ef\u7528\u66f4\u65b0",
|
| 333 |
updateRestarting: "\u6b63\u5728\u91cd\u542f\u670d\u52a1...",
|
| 334 |
updatePulling: "\u62c9\u53d6\u4ee3\u7801...",
|
|
|
|
| 151 |
dockerUpdateCmd: "Run to update:",
|
| 152 |
downloadUpdate: "Download",
|
| 153 |
electronUpdateHint: "Updates are handled automatically. Restart the app or check the system tray for update notifications.",
|
| 154 |
+
dockerAutoUpdateHint: "Or enable Watchtower in docker-compose.yml for automatic updates",
|
| 155 |
updateTitle: "Update Available",
|
| 156 |
updateRestarting: "Restarting server...",
|
| 157 |
updatePulling: "Pulling code...",
|
|
|
|
| 330 |
dockerUpdateCmd: "\u6267\u884c\u66f4\u65b0\u547d\u4ee4\uff1a",
|
| 331 |
downloadUpdate: "\u4e0b\u8f7d",
|
| 332 |
electronUpdateHint: "\u66f4\u65b0\u7531\u684c\u9762\u7aef\u81ea\u52a8\u5904\u7406\u3002\u91cd\u542f\u5e94\u7528\u6216\u68c0\u67e5\u7cfb\u7edf\u6258\u76d8\u7684\u66f4\u65b0\u901a\u77e5\u3002",
|
| 333 |
+
dockerAutoUpdateHint: "\u6216\u5728 docker-compose.yml \u4e2d\u542f\u7528 Watchtower \u5b9e\u73b0\u81ea\u52a8\u66f4\u65b0",
|
| 334 |
updateTitle: "\u6709\u53ef\u7528\u66f4\u65b0",
|
| 335 |
updateRestarting: "\u6b63\u5728\u91cd\u542f\u670d\u52a1...",
|
| 336 |
updatePulling: "\u62c9\u53d6\u4ee3\u7801...",
|
src/routes/web.ts
CHANGED
|
@@ -290,7 +290,7 @@ export function createWebRoutes(accountPool: AccountPool): Hono {
|
|
| 290 |
error: "Self-update not available in this deploy mode",
|
| 291 |
mode,
|
| 292 |
hint: mode === "docker"
|
| 293 |
-
? "Run: docker compose pull && docker compose up -d"
|
| 294 |
: mode === "electron"
|
| 295 |
? "Updates are handled automatically by the desktop app. Check the system tray for update notifications, or restart the app to trigger a check."
|
| 296 |
: "Git is not available in this environment",
|
|
|
|
| 290 |
error: "Self-update not available in this deploy mode",
|
| 291 |
mode,
|
| 292 |
hint: mode === "docker"
|
| 293 |
+
? "Run: docker compose pull && docker compose up -d (or enable Watchtower for automatic updates)"
|
| 294 |
: mode === "electron"
|
| 295 |
? "Updates are handled automatically by the desktop app. Check the system tray for update notifications, or restart the app to trigger a check."
|
| 296 |
: "Git is not available in this environment",
|
web/src/components/UpdateModal.tsx
CHANGED
|
@@ -179,12 +179,17 @@ export function UpdateModal({
|
|
| 179 |
{applying ? t("applyingUpdate") : t("updateNow")}
|
| 180 |
</button>
|
| 181 |
) : mode === "docker" ? (
|
| 182 |
-
<
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 188 |
) : (
|
| 189 |
<span class="text-xs text-slate-500 dark:text-text-dim italic">
|
| 190 |
{t("electronUpdateHint")}
|
|
|
|
| 179 |
{applying ? t("applyingUpdate") : t("updateNow")}
|
| 180 |
</button>
|
| 181 |
) : mode === "docker" ? (
|
| 182 |
+
<div class="flex flex-col items-end gap-1.5">
|
| 183 |
+
<button
|
| 184 |
+
onClick={() => { navigator.clipboard.writeText("docker compose pull && docker compose up -d"); }}
|
| 185 |
+
class="px-4 py-2 text-xs font-semibold bg-primary text-white rounded-lg hover:bg-primary-hover transition-colors"
|
| 186 |
+
>
|
| 187 |
+
{t("copy")} docker compose pull && docker compose up -d
|
| 188 |
+
</button>
|
| 189 |
+
<span class="text-[10px] text-slate-400 dark:text-text-dim">
|
| 190 |
+
{t("dockerAutoUpdateHint")}
|
| 191 |
+
</span>
|
| 192 |
+
</div>
|
| 193 |
) : (
|
| 194 |
<span class="text-xs text-slate-500 dark:text-text-dim italic">
|
| 195 |
{t("electronUpdateHint")}
|