OneAPI Pro · Go 言語で構築されたエンタープライズ向け AI API Gateway
one-api を深くリファクタリングして開発されました。原作者のオープンソースへの貢献に感謝します。
👉 オンライン Demo を見る:http://demo.one-api.pro
·
👉 デモアカウント:root / 123456
·
👉 開発・利用ドキュメント:http://doc.one-api.pro/
简体中文 · English · 繁體中文 · 日本語 · Русский · 한국어 · العربية · Deutsch
- 🚀 クイックスタート
- 🔧 技術スタック
- ✨ 機能ハイライト
- 🔥 one-api との比較
- 📸 スクリーンショット
- ⚙️ 設定
- 📖 API ドキュメント
- 📦 デプロイ
- 🗺️ ロードマップ
- License
GitHub Releases からプリコンパイル済みのバージョンをダウンロードするか、ソースからビルドします:
git clone https://github.com/modelbus/one-api-pro.git
cd one-api-procd web
sh build.sh # web/THEMES に従って各テーマをビルド(デフォルトは default-pro)
cd ..バックエンドはフロントエンドのビルド完了後にコンパイルする必要があります。最新のフロントエンド成果物を組み込むためです。
go build -ldflags "-s -w" -o one-api-proルートディレクトリの release.sh スクリプトを使用すると、依存関係のダウンロード、フロントエンドビルド、マルチプラットフォームのクロスコンパイルをワンクリックで実行できます:
./release.sh # VERSION ファイルをバージョン番号として使用
./release.sh v0.1.0 # バージョン番号を指定
./release.sh v0.1.0 --skip-frontend # フロントエンドのビルドをスキップ(既存の web/build を再利用)前提要件:
go、node、npm。バージョン番号はルートディレクトリのVERSIONファイルから取得されます(vプレフィックスの有無を自動判別)。
パッケージング成果物は静的リンクされた裸の実行可能ファイルです(解凍不要、直接実行可能)、dist/ ディレクトリに出力されます:
dist/one-api-pro-linux-amd64
dist/one-api-pro-linux-arm64
dist/one-api-pro-windows-amd64.exe
dist/one-api-pro-darwin-amd64
dist/one-api-pro-darwin-arm64
このうち
linux-*は静的リンクされており、CentOS / Ubuntu で共通に使用できます。GitHub Releases は.github/workflows/release.ymlによりv*タグがプッシュされた際に自動でビルド・公開されます。ローカルのrelease.shの出力ロジックと一致します。
./one-api-pro --port 3000 --log-dir ./logshttp://localhost:3000 にアクセスし、初期アカウント root / 123456 でログインします。
詳細なデプロイ方法は 📦 デプロイ、API ドキュメントは 📖 API ドキュメント を参照してください。
本プロジェクトは以下のオープンソース技術を基に構築されています。すべてのオープンソースプロジェクトの作者に感謝します。
| 技術 | 用途 |
|---|---|
| Gin | HTTP Web フレームワーク |
| GORM | ORM ライブラリ、SQLite / MySQL / PostgreSQL をサポート |
| go-redis/redis | Redis クライアント |
| golang-jwt/jwt | JWT 認証 |
| AWS SDK for Go v2 | AWS Bedrock 連携 |
| Google API Go Client | Google Gemini / PaLM2 連携 |
| pkoukk/tiktoken-go | Token カウント |
| gorilla/websocket | WebSocket 対応(訊飛などのチャネル) |
| joho/godotenv | .env 設定ファイルの読み込み |
| 技術 | 用途 |
|---|---|
| Vue 3 | フロントエンドフレームワーク(Composition API) |
| Vite | ビルドツール |
| Arco Design Vue | UI コンポーネントライブラリ |
| Pinia | 状態管理 |
| Vue Router 4 | ルーティング管理 |
| Axios | HTTP クライアント |
| ECharts | データビジュアライゼーショングラフ |
| vue-i18n | 国際化 |
One Api Pro はエンタープライズ向け AI API ゲートウェイであり、Go 言語 + Vue 3 で新たに構築されました。オリジナルの one-api の全機能を維持した上で、アーキテクチャレベルのリファクタリングとエンタープライズ向けの強化が施されています。
新しい Vue 3 + Arco Design 管理画面は、データビジュアライゼーションのダッシュボードを提供し、主要指標、利用トレンド、モデル別の使用量分布を一目で把握できます。
| 主要指標カード | 利用トレンドグラフ |
|---|---|
![]() |
![]() |
多次元のトークン管理をサポート:使用可能モデルのホワイトリスト、IP サブネット制限、クォータ上限、有効期限、無制限クォータ。権限の粒度は単一モデルまで細分化できます。
| トークン管理 |
|---|
![]() |
プランとサブスクリプションの完全な体系を内蔵:Token / リクエスト単位の課金、周期レート制限(時間 / 週 / 月)、モデル別のきめ細かい管理、おすすめプランと価格設定をサポートします。
| プラン管理 | サブスクリプション管理 |
|---|---|
![]() |
![]() |
各プランの注文は完全な注文監査記録(注文番号、ユーザー、プランスナップショット JSON、金額、支払い方法、ステータス、支払い時刻、チャネル取引番号)を残します。プラン / チャージの 2 種類の注文タイプをサポートし、微信支付 Native(PC スキャン)と支付宝当面付(TradePrecreate)をネイティブに連携し、銀行 / オフライン / 無料の 3 つの管理側チャネルも用意されています。プランアップグレードの差額は残り日数の割合で自動計算され、積み上げモードでは新旧プランが並行して有効になり、すべてのルールは「設定 → プラン運営」サブタブでホットスイッチできます。注文センターテーブルに「注文タイプ」列(プラン / チャージ の 2 色 chip)を追加し、決済コールバック processNotify は order.Type に応じてプランを有効化するかチャージをアカウントに加算するかを振り分けます。
コントロールパネルの「マイ残高」カードからオンラインで残高をチャージできるようになりました。同一の微信 / 支付宝チャネルを复用し、TopupModal で金額(プリセット chip + カスタム金額)を選択して送信すると非同期でアカウントに反映されます。「設定 → チャージ」タブで設定可能:
- マスタースイッチ:
topup.enabled、オフにするとダッシュボードのチャージ入口が無効化されます - プリセット金額:
topup.presets、管理者が{金額, 獲得 quota}の組を複数設定しフロントでは chip として表示 - カスタム金額:
topup.allow_custom、有効化すると末尾に「カスタム」chip が追加され、クリック後にのみ入力ボックスが表示されます - 換算レート:
topup.exchange_rate、デフォルト1(1 元 = 1 quota)、カスタム金額にのみ適用、プリセットは各自のbonus_quotaで独立して加算
注文タイプ = 2(OrderTypeTopup)は同じ orders テーブルに書き込まれ、注文番号プレフィックスは TP、加算は冪等(支払い済みは即 return)、有効化時に IncreaseUserQuota + RecordTopupLog を実行します。
分散型アクティブ・アクティブクラスタのデプロイをサポートします。各ノードは独立した MySQL + Redis を持ち、アプリケーション層のイベント同期でデータ相互信頼を実現します。データベース共有は不要で、グローバルな複数地域への最寄りアクセスを自然にサポートします。
| クラスタノード管理 |
|---|
![]() |
- 30+ のモデルプラットフォーム連携:OpenAI / Anthropic / Gemini / DeepSeek / 通義千問 / 文心一言 / 訊飛 / 智譜 などの主要プラットフォームを網羅し、OpenAI 互換インターフェースに統一
- 正確なコスト計算:Token 単位またはリクエスト単位の課金、Prompt / Completion / Cached の独立した価格設定、グループ割引の積み上げ、周期使用量の追跡
- チャネル負荷分散:重み付きランダム割り当て、自動フェイルオーバー、クールダウン / 無効化ポリシー、チャネル並行性と RPM レート制限
- 多段階権限システム:Guest / User / Admin / Root の 4 段階、オリジナルの API 権限の脆弱性を修正、管理者操作権限をきめ細かく制御
- エンタープライズ向けセキュリティ:全経路 HTTPS、Token 認証、サブネット IP 制限、監査ログのリアルタイム追跡
| 比較観点 | one-api | one-api-pro |
|---|---|---|
| プロジェクト名 | one-api | one-api-pro |
| Adaptor アーキテクチャ | 集中定数管理(channeltype/define.go の 56 行の iota + url.go の平行配列 + helper.go の二重 switch)、プロバイダーを追加するには 4 つのフレームワークファイルを変更する必要がある | 自己登録メカニズム(registry + register.go)、プロバイダーを追加するにはパッケージを作成して登録するだけでよく、フレームワークコードの変更はゼロ |
| 権限のきめ細かさ | 管理者と一般ユーザーの権限境界が曖昧で、誰でも API で設定項目を操作できる | 階層型権限システム、API 権限の脆弱性を修正、管理者操作権限をきめ細かく制御 |
| サブスクリプションモード | プラン/サブスクリプション体系なし | 完全なプラン・サブスクリプション + 周期レート制限 + モデル別管理 |
| 分散クラスタ | 独立したクラスタサポートなし、マルチホストデプロイでは MySQL を共有する必要がある | 分散型アクティブ・アクティブクラスタをサポート、各ノードが独立した MySQL + Redis を持ち、アプリケーション層のイベント同期でデータ相互信頼を実現、データベース共有不要 |
| ディレクトリ構造 | relay/adaptor/ に 40 個のディレクトリをフラットに配置、基本プロトコルとプロバイダーが混在、relay/model/ がルートの model/ と衝突 | adaptor/openai/、adaptor/anthropic/ を基本プロトコルとして独立配置、adaptor/provider/ に 37 社のプロバイダーを統合、relay/schema/ で名前の衝突を解消 |
| 管理画面 | 3 種類のフロントエンドテーマ(default/berry/air)、基本管理機能 | Vue 3 + Arco Design の新しい管理画面、ビジュアルダッシュボード |
| 継続更新 | 元プロジェクトは 2024 年に更新を停止した | 継続的に保守・更新、エンタープライズ向けシナリオに最適化 |
システム自体はインストール直後から使用可能です。
環境変数やコマンドライン引数で設定できます。起動後、root ユーザーで管理画面にログインして設定を続行できます。
ヒント:設定項目の意味がわからない場合は、一時的に値(バリュー)を削除すると詳細なヒントテキストが表示されます。
One Api Pro は
.envファイルから環境変数を読み取ることをサポートします。.env.exampleファイルを参照し、使用時には.envに名前を変更してください。--env引数で設定ファイルのパス(相対パス対応)を指定することもできます。詳細はコマンドライン引数の節を参照してください。
REDIS_CONN_STRING:設定後、Redis をキャッシュとして使用します。- 例:
REDIS_CONN_STRING=redis://default:redispw@localhost:49153 - データベースアクセスの遅延が非常に低い場合、Redis を有効にする必要はありません。有効にすると逆にデータ遅延の問題が発生します。
- センチネルまたはクラスタモードを使用する場合:
- その環境変数をノードリストに設定する必要があります。例:
localhost:49153,localhost:49154,localhost:49155。 - その他に以下の環境変数も設定する必要があります:
REDIS_PASSWORD:Redis クラスタまたはセンチネルモードでのパスワード設定。REDIS_MASTER_NAME:Redis センチネルモードでのマスターノードの名前。
- その環境変数をノードリストに設定する必要があります。例:
- 例:
SESSION_SECRET:設定後、固定のセッションキーを使用します。これによりシステム再起動後もログイン済みユーザーの cookie が引き続き有効になります。- 例:
SESSION_SECRET=random_string
- 例:
SQL_DSN:設定後、SQLite ではなく指定のデータベースを使用します。MySQL または PostgreSQL を使用してください。- 例:
- MySQL:
SQL_DSN=root:123456@tcp(localhost:3306)/oneapi - PostgreSQL:
SQL_DSN=postgres://postgres:123456@localhost:5432/oneapi(対応中、フィードバック歓迎)
- MySQL:
- 事前にデータベース
oneapiを作成しておく必要があります。テーブルの手動作成は不要で、プログラムが自動で作成します。 - クラウドデータベースを使用する場合:クラウドサーバーが認証を要求する場合は、接続パラメータに
?tls=skip-verifyを追加する必要があります。 - データベース設定に応じて以下のパラメータを変更してください(またはデフォルト値を維持):
SQL_MAX_IDLE_CONNS:最大空き接続数、デフォルトは100。SQL_MAX_OPEN_CONNS:最大開いた接続数、デフォルトは1000。Error 1040: Too many connectionsエラーが出る場合は、この値を適宜減らしてください。
SQL_CONN_MAX_LIFETIME:接続の最大ライフタイム、デフォルトは60、単位は分。
- 例:
LOG_SQL_DSN:設定後、logsテーブル用に独立したデータベースを使用します。MySQL または PostgreSQL を使用してください。FRONTEND_BASE_URL:設定後、ページリクエストを指定されたアドレスにリダイレクトします。サーバーからのみ設定可能です。- 例:
FRONTEND_BASE_URL=https://openai.justsong.cn
- 例:
MEMORY_CACHE_ENABLED:メモリキャッシュを有効にします。ユーザー額度の更新に一定の遅延が生じます。trueとfalseを選択でき、未設定の場合はfalseになります。- 例:
MEMORY_CACHE_ENABLED=true
- 例:
SYNC_FREQUENCY:キャッシュを有効にした場合にデータベースと設定を同期する頻度、単位は秒、デフォルトは600秒。- 例:
SYNC_FREQUENCY=60
- 例:
NODE_TYPE:設定後、ノードタイプを指定します。masterとslaveから選択でき、未設定の場合はmasterがデフォルト。- 例:
NODE_TYPE=slave
- 例:
CHANNEL_UPDATE_FREQUENCY:設定後、チャネル残高を定期的に更新します。単位は分、未設定の場合は更新しません。- 例:
CHANNEL_UPDATE_FREQUENCY=1440
- 例:
CHANNEL_TEST_FREQUENCY:設定後、チャネルを定期的にチェックします。単位は分、未設定の場合はチェックしません。- 例:
CHANNEL_TEST_FREQUENCY=1440
- 例:
POLLING_INTERVAL:チャネル残高の一括更新および可用性テスト時のリクエスト間隔、単位は秒、デフォルトは間隔なし。- 例:
POLLING_INTERVAL=5
- 例:
BATCH_UPDATE_ENABLED:データベースのバッチ更新集約を有効にします。ユーザー額度の更新に一定の遅延が生じます。trueとfalseを選択でき、未設定の場合はfalseになります。- 例:
BATCH_UPDATE_ENABLED=true - データベース接続数が多すぎる問題が発生した場合は、このオプションの有効化を試してください。
- 例:
BATCH_UPDATE_INTERVAL=5:バッチ更新集約の時間間隔、単位は秒、デフォルトは5。- 例:
BATCH_UPDATE_INTERVAL=5
- 例:
- リクエスト頻度制限:
GLOBAL_API_RATE_LIMIT:グローバル API レート制限(リレーリクエストを除く)、単一 IP の 3 分以内の最大リクエスト数、デフォルトは180。GLOBAL_WEB_RATE_LIMIT:グローバル Web レート制限、単一 IP の 3 分以内の最大リクエスト数、デフォルトは60。
- エンコーダキャッシュ設定:
TIKTOKEN_CACHE_DIR:プログラム起動時にオンラインで汎用モデルのトークンエンコーダ(例:gpt-3.5-turbo、gpt-4、gpt-4o)をダウンロードします。ネットワークが制限されているかオフラインの場合、ダウンロードがタイムアウト(約 30 秒)すると自動的に近似 token カウント(約0.38 × 文字数)にフォールバックし、サービスは正常に起動できます。正確な課金が必要な場合は、オンライン環境で事前にエンコーダファイルをこのディレクトリにダウンロードし、オフライン環境へ移行してください。DATA_GYM_CACHE_DIR:現時点ではこの設定の役割はTIKTOKEN_CACHE_DIRと同じですが、それより優先度は低くなります。
RELAY_TIMEOUT:リレータイムアウト設定、単位は秒、デフォルトではタイムアウト未設定。RELAY_PROXY:設定後、そのプロキシを使用して API をリクエストします。USER_CONTENT_REQUEST_TIMEOUT:ユーザーコンテンツのダウンロードタイムアウト時間、単位は秒。USER_CONTENT_REQUEST_PROXY:設定後、そのプロキシを使用してユーザーがアップロードしたコンテンツ(例:画像)をリクエストします。SQLITE_BUSY_TIMEOUT:SQLite ロック待ちタイムアウト設定、単位はミリ秒、デフォルトは3000。GEMINI_SAFETY_SETTING:Gemini の安全設定、デフォルトはBLOCK_NONE。GEMINI_VERSION:One Api Pro が使用する Gemini のバージョン、デフォルトはv1。THEME:システムのテーマ設定、デフォルトはdefault-pro(Vue 3 管理画面)、default/berry/air(旧 React テーマ)にも切り替え可能です。具体的な選択肢はこちらを参照してください。ENABLE_METRIC:リクエスト成功率に基づいてチャネルを無効化するかどうか、デフォルトでは無効、trueとfalseを選択できます。METRIC_QUEUE_SIZE:リクエスト成功率統計のキューサイズ、デフォルトは10。METRIC_SUCCESS_RATE_THRESHOLD:リクエスト成功率のしきい値、デフォルトは0.8。INITIAL_ROOT_TOKEN:設定した場合、システム初回起動時にこの環境変数値を値とする root ユーザートークンを自動作成します。INITIAL_ROOT_ACCESS_TOKEN:設定した場合、システム初回起動時にこの環境変数値を値とする root ユーザーのシステム管理用アクセストークンを自動作成します。ENFORCE_INCLUDE_USAGE:stream モデルでの usage 返却在を強制するかどうか、デフォルトでは無効、trueとfalseを選択できます。TEST_PROMPT:モデルテスト時のユーザー prompt、デフォルトはPrint your model name exactly and do not output without any other text.。
以下の環境変数を設定しない場合、システムは単一ノードモードで動作し、副作用はありません。
CLUSTER_ENABLED:クラスタモードを有効にするかどうか、デフォルトでは無効。- 例:
CLUSTER_ENABLED=true
- 例:
CLUSTER_NODE_ID:ノード番号(1-49)、MySQL のauto_increment_offsetと一致する必要があり、異なるノードで重複できません。- 例:
CLUSTER_NODE_ID=1
- 例:
CLUSTER_NODE_NAME:ノード名、識別しやすくするため、デフォルトはnode-{NODE_ID}。- 例:
CLUSTER_NODE_NAME=node-cn
- 例:
CLUSTER_NODE_ADDRESS:本ノードの公開アクセスアドレス(プロトコルプレフィックスを含める必要があります)、他のノードはこのアドレスにデータをプッシュします。- 例:
CLUSTER_NODE_ADDRESS=https://cn.example.com
- 例:
CLUSTER_SECRET:本ノードの初期 secret、各ノード独立。初回起動時に初期 secret としてデータベースに書き込まれ、その後 admin が変更可能。- 例:
CLUSTER_SECRET=MyClusterSecret123abc
- 例:
CLUSTER_SEEDS:シードノードアドレス(カンマ区切り)、新規ノード起動時にシードノードに登録してクラスタ情報を取得します。到達可能なノードを 1 つ設定すれば十分です。最初のノードは設定しないか、自分のアドレスを設定できます。- 例:
CLUSTER_SEEDS=https://cn.example.com - 複数のシード:
CLUSTER_SEEDS=https://cn.example.com,https://us.example.com
- 例:
CLUSTER_PUSH_INTERVAL:同期イベントプッシュ間隔、単位は秒、デフォルトは3。CLUSTER_DISCOVERY_INTERVAL:ノード発見間隔、単位は秒、存続ノードは毎周期お互いに ping し合い、デフォルトは30。CLUSTER_DEAD_PING_INTERVAL:失敗ノードの ping 間隔、単位は秒、存続間隔より長くして無効なリクエストを減らします、デフォルトは120。CLUSTER_MAX_PING_FAILURES:連続 ping 失敗回数、これに達するとノードを失敗状態としてマーク、デフォルトは3。CLUSTER_SYNC_LOGS:ログテーブルを同期するかどうか、ログデータ量が大きい場合は必要に応じて無効化、デフォルトはtrue。- 例:
CLUSTER_SYNC_LOGS=false
- 例:
CLUSTER_BATCH_SIZE:毎回のプッシュ最大イベント数、デフォルトは50。
--port <port_number>: サーバーがリッスンするポート番号を指定、デフォルトは3000。- 例:
--port 3000
- 例:
--log-dir <log_dir>: ログフォルダを指定、未設定の場合は作業ディレクトリのlogsフォルダに保存。- 例:
--log-dir ./logs
- 例:
--env <env_file_path>: 設定ファイルのパスを指定、相対パスと絶対パスに対応。未指定時はカレントディレクトリの.envファイルを自動ロード。- 例:
--env ./config.env - 例:
--env /etc/one-api-pro/production.env - 複数インスタンスデプロイ例:
./one-api-pro --env ./instances/instance1.env --port 3001 & ./one-api-pro --env ./instances/instance2.env --port 3002 &
- 設定の優先順位:コマンドライン引数 > システム環境変数 >
--envで指定した設定ファイル > デフォルト値
- 例:
--version: システムバージョン番号を表示して終了。- 例:
./one-api-pro --version - バージョン番号の由来(優先度が高い順):
- カレント作業ディレクトリまたは実行可能ファイルと同ディレクトリの
VERSIONファイル(vプレフィックスの有無を自動判別、例:0.0.2またはv0.0.2); - ビルド時に
-ldflags "-X .../common.Version=..."で注入されたバージョン番号(release.shと CI の両方が自動注入); - ソース内のデフォルト値
common/constants.go。
- カレント作業ディレクトリまたは実行可能ファイルと同ディレクトリの
- したがって、ルートディレクトリの
VERSIONファイルを 1 箇所だけ管理すれば、--version、起動ログ、/api/statusインターフェース、フロントエンドダッシュボードに表示されるバージョン番号を一致させられます。
- 例:
--help: コマンドの使用ヘルプと引数の説明を表示。- 例:
./one-api-pro --help
- 例:
完全な API ドキュメントは docs/API.md に独立して管理されており、以下を網羅しています:
- 認証メカニズム:Cookie Session / Access Token / API Key(Bearer Token)の 3 つの認証方式
- 管理インターフェース:モデル価格、グループ割引、チャネル、トークン、ユーザー、ログ、利用コード、プラン、サブスクリプションなどの完全な CRUD
- OpenAI 互換インターフェース:
/v1/models、/v1/chat/completions、/v1/embeddings、画像、音声、モデレーションなど - クラスタ管理 API:ノード発見、ハートビート、データ同期などの分散型クラスタインターフェース
以下のいずれかの方法を選びます:
方法一:プリコンパイル済みバージョンをダウンロード(推奨)
GitHub Releases から対応プラットフォーム(Linux / macOS / Windows)の裸の実行可能ファイルをダウンロードします。解凍不要でそのまま実行できます。
方法二:release.sh でワンクリックパッケージング
git clone https://github.com/modelbus/one-api-pro.git
cd one-api-pro
./release.sh # マルチプラットフォームのパッケージング、成果物は dist/ に出力方法三:ソースからコンパイル
git clone https://github.com/modelbus/one-api-pro.git
cd one-api-pro
# フロントエンドをビルド(Vue 3 管理画面、web/THEMES に従って順次ビルド)
cd web
sh build.sh
# バックエンドをビルド(注意:最新のフロントエンド成果物を組み込むため、必ずフロントエンドのビルド後に実行)
cd ..
go build -ldflags "-s -w" -o one-api-prochmod u+x one-api-pro
./one-api-pro --port 3000 --log-dir ./logshttp://localhost:3000/ にアクセスしてログインします。初期アカウントのユーザー名は root、パスワードは 123456 です。
- すべてのサーバーで
SESSION_SECRETを同じ値に設定します。 SQL_DSNを必ず設定し、SQLite ではなく MySQL データベースを使用し、すべてのサーバーが同じデータベースに接続します。- すべての従属サーバーで
NODE_TYPEをslaveに設定する必要があります。設定しない場合はメインサーバーがデフォルトになります。 SYNC_FREQUENCYを設定すると、サーバーはデータベースから設定を定期的に同期します。リモートデータベースを使用する場合は、主従を問わずこの項目の設定と Redis の有効化を推奨します。- 従属サーバーは必要に応じて
FRONTEND_BASE_URLを設定し、ページリクエストをメインサーバーにリダイレクトできます。 - 従属サーバーにはそれぞれ Redis をインストールし、
REDIS_CONN_STRINGを設定します。これにより、キャッシュが未失効の間はデータベースへのアクセスをゼロにでき、遅延を削減できます(Redis クラスタまたはセンチネルモードの対応は環境変数の説明を参照)。 - メインサーバーのデータベースアクセス遅延も高い場合は、Redis の有効化と
SYNC_FREQUENCYの設定が必要です。データベースから設定を定期的に同期するためです。
環境変数の具体的な使用方法はこちらを参照してください。
クラスタモードでは、複数のノードがそれぞれ独立した One Api Pro + MySQL をデプロイし、アプリケーション層のイベント同期でデータ相互信頼を実現できます。データベース共有は不要です。
適用シナリオ:グローバルな複数地域デプロイ、最寄りアクセスによる遅延削減、高可用性・災害復旧、複数ノードの負荷分散。
┌─────────────┐
│ Nginx/LB │ (統一入口,ip_hash 負載均衡)
└──────┬──────┘
│
┌──────────────┼──────────────┐
│ │ │
┌──────┴──────┐ ┌────┴───────┐ ┌───┴────────┐
│ Node A │ │ Node B │ │ Node C │
│ (one-api-pro) │ │ (one-api-pro) │ │ (one-api-pro) │
│ + MySQL │ │ + MySQL │ │ + MySQL │
│ + Redis │ │ + Redis │ │ + Redis │
└──────┬──────┘ └─────┬──────┘ └────┬────────┘
│ │ │
└────── HTTP 推送同步事件 ──────┘
- 分散型:全ノードが対等で主従の区別なし、どのノードでもデータ変更後は全存続ノードへ能動的にプッシュ
- ゼロ侵入:GORM コールバックでデータ変更を捕捉し、既存のビジネスコードを変更しない
- 非同期プッシュ:データ同期はメインプロセスをブロックせず、バックグラウンドの goroutine で一括プッシュ
- 競合解決:
updated_atタイムスタンプの比較に基づき、より新しいデータのみ書き込む - レート制限同期:チャネル並行性と RPM レート制限カウンタをデータベーステーブル経由でクロスノード同期
- 単一ノード互換:クラスタ環境変数を設定しない場合、システムは完全に単一ノードモードで動作
| データテーブル | 同期するか | 説明 |
|---|---|---|
| users | ✅ | ユーザー情報 |
| tokens | ✅ | API トークン |
| channels | ✅ | チャネル設定 |
| abilities | ✅ | チャネル機能 |
| options | ✅ | システム設定 |
| redemptions | ✅ | 利用コード |
| plans | ✅ | サブスクリプションプラン |
| user_plans | ✅ | ユーザーサブスクリプション |
| plan_usages | ✅ | プラン使用量 |
| channel_counters | ✅ | チャネルレート制限カウンタ |
| cluster_nodes | 🔄 Discovery | クラスタノード情報(発見メカニズムで管理され、データ同期は行われない) |
| logs | ログデータ量が大きいため、CLUSTER_SYNC_LOGS で制御 |
1. MySQL 設定(各ノードは独立した MySQL インスタンスを使用する必要があります)
各ノードには独立した MySQL インスタンスが必要です(同一の MySQL インスタンス内に複数のデータベースを作成して複数のノードをデプロイすることはできません。auto_increment_offset はインスタンスレベルの変数だからです)。
# 节点 1 的 my.cnf
[mysqld]
server-id = 1
auto_increment_increment = 50
auto_increment_offset = 1
log_bin = mysql-bin
binlog_format = ROW
# 节点 2 的 my.cnf
[mysqld]
server-id = 2
auto_increment_increment = 50
auto_increment_offset = 2
log_bin = mysql-bin
binlog_format = ROW
# 节点 3 的 my.cnf
[mysqld]
server-id = 3
auto_increment_increment = 50
auto_increment_offset = 3
log_bin = mysql-bin
binlog_format = ROW
auto_increment_incrementを 50 に設定すると、最大 50 ノードをサポートできます。各ノードのoffsetはCLUSTER_NODE_IDと一致し、かつ互いに異なる必要があります。
重要:
auto_increment_incrementとauto_increment_offsetは MySQL のシステムレベル変数であり、インスタンス内のすべてのデータベースに影響します。データベースごとに異なる値を設定することも、テーブルレベルの設定もできません(MySQL のテーブルオプションはAUTO_INCREMENTの開始値のみをサポートし、増分はサポートしません)。したがって、各ノードは独立した MySQL インスタンスを使用する必要があり、同一の MySQL インスタンス内で異なるデータベースを作成して複数のノードをデプロイすることはできません。同一マシン上で複数の MySQL インスタンスを実行する必要がある場合は、異なるポートで複数の mysqld プロセスを開始するか、Docker で複数の独立した MySQL コンテナを実行してください。
server-idと binlog について:server-idは同一クラスタのすべての MySQL インスタンスで互いに異なる必要があります。log_binとbinlog_format=ROWは強く推奨します。これらは将来のマスタースレーブレプリケーション拡張と point-in-time recovery のためのものです。クラスタデータ同期自体は binlog に依存しません(GORM コールバックでアプリケーション層に実装)が、binlog は追加の信頼性保証を提供します。
2. Redis 設定(各ノードは独立した Redis インスタンスを使用する必要があります)
各ノードにも独立した Redis インスタンスが必要です(ポートが異なるか、異なるマシン上)。Redis はこのクラスタアーキテクチャではノード間通信には使用されず、本ノードのキャッシュ、レート制限などのビジネス用途のみに使用されます。
3. 新規ノードの初期化データ
新規ノードをオンラインにする際は、まず既存ノードのデータスナップショットを取得する必要があります:
# 方法一:既存ノードからエクスポートしてインポート
mysqldump -h existing-node -u root -p oneapi > backup.sql
mysql -u root -p oneapi < backup.sql
# 方法二:API でスナップショットを取得(サービスの起動が必要)
curl -H "X-Cluster-Secret: your-secret" \
"https://existing-node/api/cluster/snapshot?tables=users,tokens,channels,abilities,options,redemptions,plans,user_plans,plan_usages" \
-o snapshot.json4. 環境変数設定(完全な例)
以下は 3 ノードクラスタの完全な .env 設定例です。各ノードは独立した MySQL と Redis インスタンスを使用し、ポートとパスはそれぞれ異なります。
ノード 1 — 中国ノード(/opt/one-api-pro/node1/.env):
# ========================
# 基本設定
# ========================
PORT=3000
SYSTEM_NAME=One Api Pro Cluster
# ========================
# データベース(独立した MySQL インスタンス)
# ========================
SQL_DSN=root:password@tcp(127.0.0.1:3306)/oneapi_node1?charset=utf8mb4&parseTime=True&loc=Local
# ========================
# Redis(独立した Redis インスタンス)
# ========================
REDIS_CONN_STRING=redis://127.0.0.1:6379/0
# ========================
# クラスタ設定
# ========================
CLUSTER_ENABLED=true
CLUSTER_NODE_ID=1
CLUSTER_NODE_NAME=node-cn
CLUSTER_NODE_ADDRESS=https://cn.example.com
CLUSTER_SECRET=your-strong-shared-secret-key-change-me
# シードノード(初回起動時に他のノードを発見するためのガイド)
# 最初のノード:自分のアドレスを記入するか空のまま
# 後続のノード:稼働中の任意のノードのアドレスを記入
CLUSTER_SEEDS=https://cn.example.com,https://us.example.com,https://eu.example.com
# ========================
# クラスタ調整(オプション)
# ========================
CLUSTER_DISCOVERY_INTERVAL=30
CLUSTER_DEAD_PING_INTERVAL=120
CLUSTER_MAX_PING_FAILURES=3
CLUSTER_PUSH_INTERVAL=3
CLUSTER_SYNC_LOGS=true
CLUSTER_BATCH_SIZE=50ノード 2 — 米国ノード(/opt/one-api-pro/node2/.env):
# 基本設定
PORT=3001
SYSTEM_NAME=One Api Pro Cluster
# データベース(独立した MySQL インスタンス。ポートまたはマシンがノード 1 と異なる)
SQL_DSN=root:password@tcp(127.0.0.1:3306)/oneapi_node2?charset=utf8mb4&parseTime=True&loc=Local
# Redis(独立した Redis インスタンス)
REDIS_CONN_STRING=redis://127.0.0.1:6380/0
# クラスタ設定
CLUSTER_ENABLED=true
CLUSTER_NODE_ID=2
CLUSTER_NODE_NAME=node-us
CLUSTER_NODE_ADDRESS=https://us.example.com
CLUSTER_SECRET=your-strong-shared-secret-key-change-me # ノード 1 と完全に一致している必要があります
# 稼働中の任意のノードのアドレスを記入
CLUSTER_SEEDS=https://cn.example.comノード 3 — 欧州ノード(/opt/one-api-pro/node3/.env):
# 基本設定
PORT=3002
SYSTEM_NAME=One Api Pro Cluster
# データベース
SQL_DSN=root:password@tcp(127.0.0.1:3306)/oneapi_node3?charset=utf8mb4&parseTime=True&loc=Local
# Redis
REDIS_CONN_STRING=redis://127.0.0.1:6381/0
# クラスタ設定
CLUSTER_ENABLED=true
CLUSTER_NODE_ID=3
CLUSTER_NODE_NAME=node-eu
CLUSTER_NODE_ADDRESS=https://eu.example.com
CLUSTER_SECRET=your-strong-shared-secret-key-change-me # 全ノードで一致している必要があります
# 稼働中の任意のノードのアドレスを記入
CLUSTER_SEEDS=https://cn.example.com設定パラメータ対照表:
| 環境変数 | ノード 1 | ノード 2 | ノード 3 | 説明 |
|---|---|---|---|---|
PORT |
3000 | 3001 | 3002 | リッスンポート(同一マシンでは異なる必要がある) |
SQL_DSN |
...oneapi_node1 | ...oneapi_node2 | ...oneapi_node3 | 独立した MySQL インスタンス |
REDIS_CONN_STRING |
:6379/0 | :6380/0 | :6381/0 | 独立した Redis インスタンス |
CLUSTER_NODE_ID |
1 | 2 | 3 | ノード番号、MySQL の auto_increment_offset に対応 |
CLUSTER_NODE_NAME |
node-cn | node-us | node-eu | ノード名、識別しやすくする |
CLUSTER_NODE_ADDRESS |
https://cn.example.com | https://us.example.com | https://eu.example.com | ノードの公開アドレス(他のノードはこのアドレスでアクセス) |
CLUSTER_SECRET |
同じ値 | 同じ値 | 同じ値 | 全ノードで完全に一致させる必要がある |
CLUSTER_SEEDS |
自分のアドレスまたは空 | 任意の存続ノード | 任意の存続ノード | 初回起動時のガイド、以降は自動発見 |
5. 起動コマンド
各ノードは --env 引数で自分の設定ファイルを読み込みます:
# ノード 1
./one-api-pro --env /opt/one-api-pro/node1/.env --port 3000
# ノード 2
./one-api-pro --env /opt/one-api-pro/node2/.env --port 3001
# ノード 3
./one-api-pro --env /opt/one-api-pro/node3/.env --port 30026. 起動順序
- 最初のノード(Node A)を起動、
CLUSTER_SEEDSは空にするか自分のアドレスを入力 - Node A が完全に起動するのを待ちます(約 5-10 秒、「クラスタモジュール初期化完了」のログを確認)
- 後続ノードを起動、
CLUSTER_SEEDSに稼働中の任意のノードのアドレスを入力 - 後続ノードは起動後、シードノードに自動で ping し、推移的にすべての他のノードを発見
- 全ノード起動後、任意のノードの管理画面「設定 → ノード管理」ページでノード状態を確認
7. Nginx 負荷分散設定例(オプション)
upstream one_api_cluster {
ip_hash; # IP ハッシュに基づき、同一ユーザーのリクエストを同じノードに固定し、session/cache のヒット率を保証
server cn.example.com:3000;
server us.example.com:3000;
server eu.example.com:3000;
}
server {
listen 443 ssl;
server_name api.example.com;
location / {
proxy_pass http://one_api_cluster;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300s;
}
}
ip_hashを使うことが重要:同一ユーザーのリクエストを常に同じノードへ固定し、プランレート制限、Redis キャッシュなどの状態が異なるノード間で失われないようにします。
8. クラスタ状態の検証
デプロイ完了後、以下の方法で検証できます:
# ノード一覧を表示(任意のノード上で呼び出し)
curl -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
https://cn.example.com/api/cluster_node/
# 全ノードのリスト(status、last_heartbeat、ping_failures などのフィールド)が返されるはずですまたは管理画面:設定 → ノード管理 ページでノード一覧、状態、最終ハートビート時刻などを確認できます。
💡 クラスタ管理 API の詳細は docs/API.md 付録 E:クラスタ管理 API を参照してください
- 各ノードは独立した MySQL インスタンスと Redis インスタンスが必要で、データベースを共有しません
CLUSTER_SECRETは全ノードで一致させる必要があり、強力なパスワードを使用して適切に保管してくださいCLUSTER_NODE_IDは全ノードで互いに異なる必要があり、MySQL のauto_increment_offsetと一致させる必要がありますCLUSTER_NODE_ADDRESSは他のノードからアクセス可能な公開アドレスである必要があります(https://などのプロトコルプレフィックスを含む)- 新規ノードのオンライン前のデータ初期化は手動で行う必要があります(オンラインノードからスナップショットを取得)
- ログテーブル(logs)はデータ量が大きいため、
CLUSTER_SYNC_LOGS=falseでログ同期を無効化できます - MySQL の
auto_increment_incrementとauto_increment_offsetはCLUSTER_NODE_ID設定と一致させる必要があります - ノード発見は ping の双方向登録メカニズムを採用しており、失敗ノードは削除されず、status=2 とマークされるだけです。ネットワーク復旧後は自動的に復活します
CLUSTER_SEEDSは初回起動時のガイドにすぎません。ノードが ping で他のノードを発見した後は SEEDS に依存しません- ノードがオフラインの間に他のノードで発生した変更は自動で再送されません。オフラインノードが再オンラインした後はスナップショットを取得してデータを補完する必要があります
各ノードは起動時に自分の cluster_nodes テーブルに 1 件のローカルレコードを書き込みます(node_id は本機設定の CLUSTER_NODE_ID と等しい)。これは意図的な設計であり、理由は以下の通りです:
- 管理画面での表示:「設定 → ノード管理」ページで、管理者が本機情報(アドレス、状態、ハートビート時刻など)を確認し、問題を調査できるようにするため
- ノード発見の推移性:ノード B がノード A の ping リクエストを受けたとき、A は応答で完全なノードリスト(A 自身を含む)を返します。B はそれを受信してローカルテーブルにマージします。これにより C は B の応答を通じて A の存在も学習できます
- 存続判断の根拠:本機レコードの
last_heartbeatは本機によって 30 秒ごとに自動更新され(discoverOnce関数内)、本機が正常に稼働している状態を反映します
自己登録により循環同期データが発生することはありません。システムは 5 つのレベルで保護しています:
| 防護ポイント | 作用 |
|---|---|
① GetAllRemoteNodes SQL フィルタ |
発見時、SQL に node_id != ? を付加して本機を除外 |
② GetAliveNodesForSync SQL フィルタ |
プッシュ時、SQL に node_id != ? を付加して本機を除外 |
③ handlePing は自己 ping を拒否 |
req.NodeId == NodeID を明示的に拒否 |
④ mergeDiscoveredNodes は本機をスキップ |
発見ノードのマージ時に本機をスキップ |
⑤ ApplyEvents は本機イベントをスキップ |
イベント適用時に本機が生成したイベントをスキップ |
データフローは一方向です:本機からリモートへプッシュ、リモートから取得して本機に適用。永遠にループはありません。
管理画面は本機のノード名の横に「本機」の青いバッジを表示し、本機に対する「削除」と「手動 Ping」操作を無効化します(これらは本機にとって意味がありません)。
各ノードは自分の secret を持ち、グローバル共有 secret は使用しません。設計理由:
- セキュリティ:1 つのノードの secret が漏えいしても他のノードには影響しません
- 管理の柔軟性:各ノードは自分の secret を独立してローテートできます
- 自動発見:ノード間 ping 時、相手に保存させるため自分の secret を自動的に携行します
Secret のライフサイクル:
- ノード初回起動:
CLUSTER_SECRET環境変数を初期値として使用し、cluster_nodes.secret_keyフィールドに書き込み - 以降の起動:
cluster_nodes.secret_keyから読み取る - Admin は「ノード管理」ページで他のノードの secret を変更できます
- ping 時の
X-Cluster-Secretヘッダー = ターゲットノードの secret(ローカル DB から検索)
新規ノード追加フロー:
- ノード A で B ノードのレコードを追加し、B の
CLUSTER_SECRET値を入力 - ノード B で A ノードのレコードを追加し、A の
CLUSTER_SECRET値を入力 - A が B に ping:B の secret を使用;B が受信:B 自身の secret を検証 ✓
- B の応答に A、B 各々の secret が含まれ、A がローカル保存分を更新
Admin がノードを削除するとき、物理的に削除せず disabled = true を設定します:
- 削除されたノードが「自動的に復活する」のを防ぐ(ping メカニズムが再登録するため)
- 無効化されたノードは依然として ping に応答します(相手に本ノードがオンラインであることを知らせる)が、本ノードの情報は取得しません
- 物理削除には手動 SQL が必要:
DELETE FROM cluster_nodes WHERE node_id = ?
クラスタデータ同期は完全に GORM イベント + HTTP 能動プッシュ メカニズムに依存しています:
- 任意のビジネステーブルの INSERT/UPDATE/DELETE 操作 → GORM コールバックで捕捉 →
sync_eventsテーブルに書き込み → Pusher goroutine が全存続ノードへプッシュ - 受信側は
WithSkipHookでローカルデータベースに書き込みます(ループバックなし) - 受信側は
event.NodeId == 本機 NodeIDのイベントをスキップします(二重の保険)
アーキテクチャのトレードオフ:本設計はクロスノードの能動プルを実装しません。理由は以下の通りです:
- ビジネスへの侵入:クロスノードプルでは各テーブルのビジネス固有フィールドを知る必要があり、ビジネスコードを汚染します
- 主キー競合:クロスノードの自動増分 ID は連続しません(異なる
auto_increment_offset)、ソースノードの id を使用すると offset 設計を破壊します - 複雑さが高い:保守コストが高く、信頼性の向上は限定的
- 能動プッシュで十分:95% のシナリオ(ノードがオンライン時の通常同期)は完全にプッシュでカバーされます
既知の制限と運用要件:
- ノードがオフラインの間に他のノードで発生したデータ変更 → 恒久的に消失(プッシュはリアルタイム)
- ノードが再オンラインした後、オフライン期間のデータを自動で補完できません
- 新規ノードは参加後のデータ変更のみを受信でき、履歴データはありません
- 運用上の対策:
mysqldumpで他のノードからエクスポートしてからインポート
典型的なデプロイシナリオ対照:
| シナリオ | プルが必要か | 処理方法 |
|---|---|---|
| ノードが恒久的にオンライン | ❌ | プッシュで十分 |
| ノードが時々再起動(分単位) | 短時間のオフラインデータ消失、運用上許容可能 | |
| ノードが頻繁にメンテナンス | ❌ | プッシュ継続、再起動後すぐに復旧 |
| 新規ノードがクラスタに参加 | ❌ | DBA が手動で mysqldump 初期化 |
| ノードが長期オフライン後に復旧 | ❌ | DBA が手動で mysqldump を補完 |
デプロイ後にアクセスして空白ページが表示される場合は、#97 を参照してください。
- アーキテクチャレベルのリファクタリング:Adaptor 自己登録メカニズム、新規プロバイダー追加でフレームワーク変更ゼロ
- Vue 3 の新しい管理画面:Arco Design + ビジュアルダッシュボード + 30+ モデルプラットフォームのアイコン
- プラン・サブスクリプション体系:Token / リクエスト単位の課金、周期レート制限、モデル別のきめ細かい管理
- 分散型アクティブ・アクティブクラスタ:GORM イベント駆動 + HTTP 能動プッシュ同期、データベース共有不要
- 正確なコスト計算:Prompt / Completion / Cached の独立した価格設定、グループ割引の積み上げ
- 多段階権限システム:Guest / User / Admin / Root の 4 段階、オリジナルの API 権限の脆弱性を修正
- OpenAI 互換インターフェース:models / chat / completions / embeddings / images / audio / moderations を完全サポート
- プラン注文とアップグレードフロー:ネイティブ
POST /api/order/planでサブスクリプション注文を作成、stack(積み上げ)とprice_diff(差額アップグレード)の 2 モードをサポート、差額は残り日数の割合で自動計算、同レベル・ダウングレードの検証を含む - 注文監査と注文センター:新規
ordersテーブル(type/source/order_no/plan_info/amount/status/pay_status/pay_method/pay_time/pay_trade_no)で全決済・管理側開通のフローを永続化、フロントエンドのユーザー側/plansと/ordersページで完全に表示;注文センターテーブルに「注文タイプ」列を追加しプランとチャージを区別 - 実決済連携(gopay):ネイティブに微信支付 Native(PC スキャン)と支付宝当面付(TradePrecreate)を連携、決済コールバックは
/api/payment/{wechat,alipay}/notifyで検証 + 注文アクティブ化のループを完了;決済通知processNotifyはorder.Typeに応じてプラン有効化とチャージ入帳に振り分け - 決済 / プラン運営設定:「運営設定」の下に「プラン運営」(差額アップグレード vs 積み上げ)と「決済」(微信 / 支付宝 / 銀行 の 3 チャネル独立スイッチ + 証明書アップロード + 通知 URL 設定)を新設、必要に応じてフォームを表示
- オンライン(残高 / quota):ユーザーはコントロールパネル「マイ残高」カードからチャージ可能、同一の微信 / 支付宝チャネルを复用;バックエンドに
OrderTypeTopup=2を追加してordersテーブルを复用、注文番号プレフィックスTP、入帳は冪等;ActivateTopupByOrderでIncreaseUserQuotaを呼び出しRecordTopupLogを書き込む - チャージ設定センター:「設定 → チャージ」タブで旧
plan.allow_topupを置き換え、マスタースイッチ / プリセット金額 / カスタム金額許可 / 換算レート(デフォルト 1:1)を設定可能、既存の決済設定とsystem_settingsテーブルを复用 - 統一注文管理(管理者視点):管理端の注文センターが一覧 / 検索 / 詳細 / 更新 / 削除に対応し、ステータス・タイプ・ソース・ユーザー・プランで多次元フィルター可能;管理者は「支払い済み」(オフライン / 銀行は即時有効化)と「返金済み」(ステータスのみ)を手動でマークできる
- チャネル診断とインテリジェントルーティング(基本機能):自動クールダウン(
CooldownFilter)、フォールバック(FallbackFilter)、低成功率自動無効化(monitor)が稼働中 - 多言語国際化(i18n):管理画面・ランディングページ・法務ページを中英で全面対応、メニュー/ページ文言/Arco Design コンポーネントがリアルタイムに切り替え、言語選択は永続化され
<html lang>と同期;言語パックはページモジュール単位で分割し自動ディープマージ
- チャネル診断とインテリジェントルーティング(強化):稼働中の自動クールダウン / フォールバック / 低成功率自動無効化に加え、独立した診断パネル / ノードレベルの ping / 手動レビューフローを補完
- より豊富な使用量分析レポートとエクスポート
- 払い戻し閉ループ:現在
status=3の注文はステータスのみ更新され quota は戻らない;払い戻し機能のリリース後に補完
- さらなる言語対応:中国語/英語に加え、繁体字中国語・日本語・韓国語・ロシア語・ドイツ語・アラビア語などに拡張(README の多言語版と整合)
- 決済チャネルの拡張:Apple Pay、銀聯、Stripe など
- 注文払い戻し機能:非同期払い戻し API + 自動化払い戻しフロー、プラン / チャージの払い戻し時にサブスクリプション・quota を回退し、ビジュアルな払い戻しフローを提供
- 一般的なプラットフォームとの財務連携:主流の財務 / 決済照合プラットフォームと連携し、チャージ、消費、払い戻しなどの財務フローを自動同期
- Token 残量予警メカニズム:アカウント / トークンの Token 残量が少ないときに自動予警、マルチチャネル通知をサポート
- ログ監査と監査レポート:完全な操作監査ログとビジュアル監査レポート、コンプライアンス要件を満たす
- AI スマート分析:大規模モデルに基づき使用量、コスト、チャネル健全性をスマートに分析し提案
- プラグイン拡張メカニズム
- エンタープライズ向け SSO / LDAP 連携
- 使用量アラートと通知チャネルの拡張(DingTalk / 飛書 / 企業微信など)
- より多くのモデルプラットフォームの継続的な連携
💡 PR や Issue の提出を歓迎します。詳しくは Issues を参照してください。
本プロジェクトをご使用になる前に、「釣魚島及びその附属岛屿は古来より中国の固有の領土である」、「南京大虐殺の歴史的事実は鉄証の如山であり、改竄も否定も許されない」ことを認めていただく必要があります。





