Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
97d0933
Add files via upload
SmartAppStarter435667 Jul 2, 2026
914be6d
Delete nextchat-cf-deploy.zip
SmartAppStarter435667 Jul 2, 2026
c2557cf
Add files via upload
SmartAppStarter435667 Jul 2, 2026
4814a1e
Rename providers.tf to terraform/providers.tf
SmartAppStarter435667 Jul 2, 2026
96eb68d
Add files via upload
SmartAppStarter435667 Jul 2, 2026
f6e79b4
Add Terraform files and directories to .gitignore
SmartAppStarter435667 Jul 2, 2026
56c7bd3
Add files via upload
SmartAppStarter435667 Jul 2, 2026
7d46d06
Add files via upload
SmartAppStarter435667 Jul 2, 2026
ed409b2
Add files via upload
SmartAppStarter435667 Jul 2, 2026
e237346
Remove unused deployment zip file
SmartAppStarter435667 Jul 2, 2026
f7eef22
Add files via upload
SmartAppStarter435667 Jul 2, 2026
28f97ca
Add files via upload
SmartAppStarter435667 Jul 2, 2026
95aaaa9
Add files via upload
SmartAppStarter435667 Jul 2, 2026
28d2e75
GitHub Actionsのデプロイ設定を更新し、中国国内ミラーによるタイムアウトを回避するためにnpmレジストリを正規のものに強制書き…
SmartAppStarter435667 Jul 2, 2026
d9af44e
Add files via upload
SmartAppStarter435667 Jul 3, 2026
6e95481
Add files via upload
SmartAppStarter435667 Jul 3, 2026
48698e5
Add files via upload
SmartAppStarter435667 Jul 4, 2026
31d52d0
Add files via upload
SmartAppStarter435667 Jul 4, 2026
9e66c5c
Add files via upload
SmartAppStarter435667 Jul 4, 2026
3b00b60
Add files via upload
SmartAppStarter435667 Jul 4, 2026
99c025a
Add files via upload
SmartAppStarter435667 Jul 4, 2026
d522c22
Add files via upload
SmartAppStarter435667 Jul 4, 2026
995483f
Add files via upload
SmartAppStarter435667 Jul 4, 2026
388c131
Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next…
actions-user Jul 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
232 changes: 232 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
name: Deploy NextChat to Cloudflare Pages

# このファイルを NextChat (フォーク後の) リポジトリの .github/workflows/deploy.yml
# として配置してください。main への push で自動デプロイされます。

on:
push:
branches: [main]
workflow_dispatch: {} # 手動実行用

# 同時実行を1つに制限(Pages側の競合デプロイ防止)
concurrency:
group: cloudflare-pages-deploy
cancel-in-progress: true

env:
NODE_VERSION: "20.1"
# Cloudflare Pages のプロジェクト名。Terraform の cloudflare_pages_project.name と一致させること
CF_PAGES_PROJECT_NAME: ${{ vars.CF_PAGES_PROJECT_NAME || 'nextchat' }}
# next-on-pages のPages Functionsを動かすのに必須。Terraform側の設定と揃えること
CF_COMPATIBILITY_DATE: "2025-03-07"

jobs:
build-and-deploy:
runs-on: ubuntu-latest
permissions:
contents: read
deployments: write
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}

# NextChat はバージョンによって yarn / pnpm いずれかを使用しているため
# ロックファイルを見て自動判定する
- name: Detect package manager
id: pm
run: |
if [ -f pnpm-lock.yaml ]; then
echo "manager=pnpm" >> "$GITHUB_OUTPUT"
elif [ -f yarn.lock ]; then
echo "manager=yarn" >> "$GITHUB_OUTPUT"
else
echo "manager=npm" >> "$GITHUB_OUTPUT"
fi

- name: Enable Corepack (pnpm/yarn)
if: steps.pm.outputs.manager != 'npm'
run: corepack enable

# NextChat のロックファイルは中国国内ミラー(華為クラウド/淘宝/騰訊等)を
# 参照していることがあり、GitHub Actionsのランナー(中国国外)からは
# 到達性が悪く "Socket connection timeout" で失敗する。
# ロックファイルに記録された解決済みURLと、レジストリ設定の両方を
# 公式npmレジストリへ強制的に書き換える。
- name: Normalize registry to official npm (avoid CN mirror timeouts)
run: |
set -e
MIRROR_RE='https://(mirrors\.huaweicloud\.com/repository/npm|repo\.huaweicloud\.com/repository/npm|registry\.npmmirror\.com|registry\.npm\.taobao\.org|mirrors\.cloud\.tencent\.com/npm|mirrors\.tencent\.com/npm|r\.cnpmjs\.org)/?'

for f in yarn.lock package-lock.json npm-shrinkwrap.json; do
if [ -f "$f" ] && grep -qE "$MIRROR_RE" "$f"; then
echo "Rewriting mirror URLs found in $f"
sed -i -E "s#${MIRROR_RE}#https://registry.npmjs.org/#g" "$f"
fi
done

# 既存の .yarnrc / .npmrc に registry 指定があれば取り除き、公式レジストリと
# 長めの network-timeout を追記する(新規解決分・再解決分の保険)
if [ -f .yarnrc ]; then
grep -v '^registry ' .yarnrc > .yarnrc.tmp || true
mv .yarnrc.tmp .yarnrc
fi
{
echo 'registry "https://registry.npmjs.org/"'
echo 'network-timeout 300000'
} >> .yarnrc

if [ -f .npmrc ]; then
grep -v '^registry' .npmrc > .npmrc.tmp || true
mv .npmrc.tmp .npmrc
fi
echo 'registry=https://registry.npmjs.org/' >> .npmrc

- name: Install dependencies
run: |
set -e
install_cmd() {
case "${{ steps.pm.outputs.manager }}" in
pnpm) pnpm install --frozen-lockfile ;;
yarn) yarn install --frozen-lockfile --network-timeout 300000 ;;
npm) npm ci ;;
esac
}
# 一時的なネットワーク断にも耐えられるよう3回までリトライ
for attempt in 1 2 3; do
if install_cmd; then
exit 0
fi
echo "Install attempt $attempt failed, retrying in 10s..."
sleep 10
done
exit 1

# NextChat 公式ドキュメント推奨のビルドコマンド。
# 通常の `next build` は node:buffer 関連の既知バグで Pages 上で動作しないため使用しない。
- name: Build for Cloudflare Pages (next-on-pages)
run: npx @cloudflare/next-on-pages --experimental-minify
env:
NEXT_TELEMETRY_DISABLE: "1"
# --- NextChat 実行時設定(必要に応じて GitHub Secrets/Variables を追加) ---
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENAI_ORG_ID: ${{ secrets.OPENAI_ORG_ID }}
CODE: ${{ secrets.NEXTCHAT_ACCESS_CODE }}
HIDE_USER_API_KEY: ${{ vars.HIDE_USER_API_KEY }}
DISABLE_GPT4: ${{ vars.DISABLE_GPT4 }}
ENABLE_BALANCE_QUERY: ${{ vars.ENABLE_BALANCE_QUERY }}
DISABLE_FAST_LINK: ${{ vars.DISABLE_FAST_LINK }}

# wrangler pages deploy は対象プロジェクトが存在しないと
# "Project not found [code: 8000007]" で失敗する。CI(非対話環境)では
# 自動作成の確認プロンプトを出せないため、事前に明示的に作成しておく。
# 既に存在する場合はエラーになるが、それは想定内なのでジョブは継続する
# (本当に認証情報などに問題がある場合は、直後の deploy ステップで
# 同じくエラーになるので気づける)。
- name: Ensure Cloudflare Pages project exists
continue-on-error: true
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages project create ${{ env.CF_PAGES_PROJECT_NAME }} --production-branch=main --compatibility-date=${{ env.CF_COMPATIBILITY_DATE }} --compatibility-flags=nodejs_compat

# 【今回のエラーが直らなかった本当の原因】
# このステップは元々 deploy の"後"に置いていたが、それが間違いだった。
# Cloudflare Pages は「compatibility flags 等のプロジェクト設定を変更しても、
# 既に存在するデプロイには遡って適用されない。設定変更後に新しくデプロイし直して
# 初めて反映される」という仕様(公式・非公式の複数の情報源で確認済み。
# dashboardで設定を変えた場合も同様に "redeploy" が必要と案内されている)。
# つまり deploy → patch の順序だと、patchで直した内容は「次回以降のデプロイ」
# にしか効かず、その回に公開されたデプロイ自体は直らないまま残っていた。
# なので patch を deploy より前に移動し、この設定が反映された状態で
# 新しいデプロイが作られるようにする。
#
# (方式としては、wrangler.jsonc をデプロイ時に読ませる案も試したが、
# Cloudflare Pages は設定ファイルを使うとダッシュボード/API側と
# ソースオブトゥルースが競合する仕様があり、next-on-pagesが生成する
# _worker.js 側の設定と衝突して無視される事例が複数報告されていたため、
# 採用せず Cloudflare API を直接叩く方式にしている)
- name: Enforce nodejs_compat via Cloudflare API
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
run: |
set -e
API="https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/pages/projects/${{ env.CF_PAGES_PROJECT_NAME }}"
AUTH_HEADER="Authorization: Bearer ${CLOUDFLARE_API_TOKEN}"

# 1. 現在のプロジェクト設定を取得する
# (Terraformで設定した環境変数などを上書きで消さないため)
get_code=$(curl -sS -o /tmp/pages-project-current.json -w '%{http_code}' \
"$API" -H "$AUTH_HEADER")
if [ "$get_code" -ge 300 ]; then
cat /tmp/pages-project-current.json
echo "::error::Cloudflare Pages プロジェクト情報の取得に失敗しました (HTTP $get_code)。CLOUDFLARE_API_TOKEN / CLOUDFLARE_ACCOUNT_ID を確認してください。"
exit 1
fi

# 2. compatibility_date / compatibility_flags だけを上書きしたJSONを作る
# (他の既存項目=環境変数やbinding等はそのまま保持する)
jq --arg date "${{ env.CF_COMPATIBILITY_DATE }}" '
.result.deployment_configs.production.compatibility_date = $date
| .result.deployment_configs.production.compatibility_flags = ["nodejs_compat"]
| .result.deployment_configs.preview.compatibility_date = $date
| .result.deployment_configs.preview.compatibility_flags = ["nodejs_compat"]
| {deployment_configs: .result.deployment_configs}
' /tmp/pages-project-current.json > /tmp/pages-compat-patch.json

# 3. PATCHで反映(これが完了してから、この後のステップでdeployする)
patch_code=$(curl -sS -o /tmp/pages-compat-response.json -w '%{http_code}' -X PATCH \
"$API" -H "$AUTH_HEADER" -H "Content-Type: application/json" \
--data @/tmp/pages-compat-patch.json)

cat /tmp/pages-compat-response.json
echo
success=$(jq -r '.success' /tmp/pages-compat-response.json)
if [ "$patch_code" -ge 300 ] || [ "$success" != "true" ]; then
echo "::error::Cloudflare Pages への compatibility flags 設定(PATCH)に失敗しました (HTTP $patch_code)"
exit 1
fi
echo "✅ nodejs_compat を production/preview 両方に設定しました(この後デプロイします)"

# ここで初めてデプロイする。上のステップで nodejs_compat 設定済みのプロジェクトに
# 対して新しいデプロイを作るので、今回のデプロイから正しく反映される。
- name: Deploy to Cloudflare Pages
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy .vercel/output/static --project-name=${{ env.CF_PAGES_PROJECT_NAME }} --branch=main

# OPENAI_API_KEY等はビルド成果物に含めず、Pages Functionsの実行時
# シークレットとして直接登録する(Terraformのstateにも残らない)
#
# 注: GitHub Actionsの仕様上 `secrets` コンテキストは if: 条件式では使えない
# ("Unrecognized named-value: 'secrets'" エラーの原因)。そのためステップ自体は
# 常に実行し、各シークレットの有無はステップ内のシェルスクリプトでチェックする。
- name: Sync runtime secrets to Cloudflare Pages
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENAI_ORG_ID: ${{ secrets.OPENAI_ORG_ID }}
NEXTCHAT_ACCESS_CODE: ${{ secrets.NEXTCHAT_ACCESS_CODE }}
run: |
set -e
if [ -n "$OPENAI_API_KEY" ]; then
printf '%s' "$OPENAI_API_KEY" | npx wrangler pages secret put OPENAI_API_KEY \
--project-name="${{ env.CF_PAGES_PROJECT_NAME }}"
fi
if [ -n "$OPENAI_ORG_ID" ]; then
printf '%s' "$OPENAI_ORG_ID" | npx wrangler pages secret put OPENAI_ORG_ID \
--project-name="${{ env.CF_PAGES_PROJECT_NAME }}"
fi
if [ -n "$NEXTCHAT_ACCESS_CODE" ]; then
printf '%s' "$NEXTCHAT_ACCESS_CODE" | npx wrangler pages secret put CODE \
--project-name="${{ env.CF_PAGES_PROJECT_NAME }}"
fi
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,10 @@ masks.json

# mcp config
app/mcp/mcp_config.json

terraform.tfvars
*.tfstate
*.tfstate.*
.terraform/
.terraform.lock.hcl
crash.log
79 changes: 79 additions & 0 deletions README (1).md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# NextChat → Cloudflare Pages CI/CD 一式

NextChat (ChatGPTNextWeb) を Cloudflare Pages に、GitHub Actions + Terraform で
デプロイ/運用するための構成一式です。

## 構成

```
.github/workflows/deploy.yml # main push で build → deploy を自動実行
terraform/
providers.tf # cloudflare / github プロバイダ
variables.tf # 入力変数
main.tf # Cloudflare Pagesプロジェクト(Direct Upload)
github_secrets.tf # ★ GitHub Secrets / Variables を自動投入
outputs.tf
terraform.tfvars.example
```

## できること・できないこと(重要)

- Terraform を **1回 `apply`** すれば、Cloudflare Pages プロジェクトの作成と、
GitHub Actions が必要とする Secrets(`CLOUDFLARE_API_TOKEN` など)・Variables の
登録まで自動化されます。ダッシュボードで手動コピペする作業は不要です。
- ただし **その `terraform apply` を実行する最初の1回だけ**、あなた自身が
Cloudflare API Token と GitHub の Personal Access Token(PAT)を用意する必要が
あります。この「最初の鍵」はどこかの人間が持たなければならず、完全に人手ゼロには
できません(これはTerraform/CI全般に共通する制約です)。
- OpenAI の API キーのような実行時シークレットは、Terraform の state に残さない
ため、`cloudflare_pages_project` には含めず GitHub Actions の中で
`wrangler pages secret put` により都度同期する設計にしています。

## セットアップ手順

### 1. 事前準備(あなたが1回だけ行う)

1. [GitHub](https://github.com/ChatGPTNextWeb/NextChat) の NextChat を Fork する
2. 本一式(`.github/workflows/deploy.yml` と `terraform/`)をForkしたリポジトリに追加してpush
3. Cloudflare API Token を発行([dash.cloudflare.com](https://dash.cloudflare.com/profile/api-tokens) → 「Pages 編集」権限を持つカスタムトークン)
4. GitHub の Fine-grained PAT を発行
(対象リポジトリに対して **Secrets: Read & write** / **Variables: Read & write** / **Administration: Read & write** 権限)

### 2. Terraform 実行

```bash
cd terraform
cp terraform.tfvars.example terraform.tfvars
# terraform.tfvars を編集して各値を埋める(絶対にコミットしない)

terraform init
terraform plan
terraform apply
```

これで以下が自動的に行われます。

- Cloudflare Pages プロジェクト `nextchat` の作成(compatibility flag: `nodejs_compat` 設定済み)
- GitHub Secrets 登録: `CLOUDFLARE_API_TOKEN`, `CLOUDFLARE_ACCOUNT_ID`,
`OPENAI_API_KEY`(指定時), `OPENAI_ORG_ID`(指定時), `NEXTCHAT_ACCESS_CODE`(指定時)
- GitHub Variables 登録: `CF_PAGES_PROJECT_NAME`, `HIDE_USER_API_KEY`,
`DISABLE_GPT4`, `ENABLE_BALANCE_QUERY`, `DISABLE_FAST_LINK`

### 3. デプロイ確認

`main` ブランチに push するか、GitHub上で Actions → `Deploy NextChat to Cloudflare Pages` →
`Run workflow` を実行すると、ビルドとデプロイが走ります。
完了後、Terraformの出力 `pages_default_domain`(`https://<project>.pages.dev`)でアクセスできます。

## 補足

- Node.js は `20.1`、ビルドコマンドは NextChat 公式ドキュメント推奨の
`npx @cloudflare/next-on-pages --experimental-minify` を使用しています
(通常の `next build` は既知の `node:buffer` バグでPages上では動きません)。
- ロックファイル(`pnpm-lock.yaml` / `yarn.lock`)を見てパッケージマネージャを
自動判定するようにしているので、Fork元のバージョン差異に強くしてあります。
- 独自ドメインを使う場合は `terraform.tfvars` の `custom_domain` を設定してください
(対象ドメインが同じCloudflareアカウントにゾーンとして存在している必要があります)。
- `terraform.tfstate` には機密値を含む可能性があるため、ローカル保管ではなく
リモートバックエンド(Terraform Cloud等)+アクセス制御を推奨します
(`providers.tf` にコメントアウトの雛形あり)。
Loading