ヘッドレスサーバーを実行
常時稼働するマシンで cc_server を実行し、デスクトップ、ブラウザー、またはスマートフォンから接続します。サーバーは純粋な Dart のネイティブバイナリで、Flutter
エンジンを必要としないため、macOS、Linux、Windows 上でヘッドレスに動作します。サーバーがデータベースを所有し、
エージェントを実行し、すべての外部 API 呼び出しを行います。クライアントは描画するだけです。
Docker で実行する(ビルド済みイメージ)
「Docker で実行する(ビルド済みイメージ)」というセクション各リリースでは、4 つの GHCR イメージからなるセルフホスト用スタック — バックエンド、
2 つの静的なシンクライアント、任意のペアリングリレー — と、公開デモホスト用の別個の
cc-server-demo イメージが公開されます。セルフホストでのインストールにソースのチェックアウトは
不要です。バージョンタグ(ghcr.io/samuelalev/<image>:v0.0.1-rc.1)を固定するか、latest を使い続けます。
| イメージ | 内容 | 公開ポート |
|---|---|---|
ghcr.io/samuelalev/cc-server |
バックエンド: データベース、エージェント、MCP、Webhook | -p 9030:9030 |
ghcr.io/samuelalev/cc-webapp |
Web クライアント(静的な nginx) | -p 8080:8080 |
ghcr.io/samuelalev/cc-remote |
スマートフォンコンパニオン PWA(静的な nginx) | -p 8081:8080 |
ghcr.io/samuelalev/cc-signaling-server |
WebRTC ペアリングリレー(任意) | -p 8788:8788 |
スタック全体を Compose ファイルにしたもの:
services: server: image: ghcr.io/samuelalev/cc-server:latest ports: ["9030:9030"] volumes: ["cc_data:/data"] restart: unless-stopped web: image: ghcr.io/samuelalev/cc-webapp:latest ports: ["8080:8080"] restart: unless-stopped remote: image: ghcr.io/samuelalev/cc-remote:latest ports: ["8081:8080"] restart: unless-stopped signaling: image: ghcr.io/samuelalev/cc-signaling-server:latest ports: ["8788:8788"] restart: unless-stopped
volumes: cc_data:これをループバックの外に公開する前に知っておくべきこと:
-
cc-serverイメージはCC_SERVER_INSECURE=1を同梱しています(公開ポートの トラフィックを受け取るには0.0.0.0にバインドする必要があるためです)。これが安全なのは、 信頼できるネットワーク上で TLS を終端するリバースプロキシ — Caddy、Traefik、nginx、Cloudflare Tunnel — の背後に置く場合だけです。代わりにプロセス内で TLS を終端するには、証明書をマウントしてCC_SERVER_TLS_CERT/CC_SERVER_TLS_KEYを設定します(そのうえでCC_SERVER_INSECUREを解除します)。すべてはdocker run -e …または Compose のenvironment:ブロックで上書きできます。 -
/dataが唯一の状態です。 SQLite データベース、ペアリング済みデバイスのシークレット、 ダウンロードしたモデル、ミーティングの音声はすべてこのボリュームにあります — これを バックアップしておけば、コンテナは使い捨てにできます。 -
最初の接続の前に、イメージの内部からクライアントをペアリングします — ステップ 3 の コンテナ版です:
ターミナルウィンドウ docker run --rm -it -v cc_data:/data \--entrypoint /app/bin/cc_server ghcr.io/samuelalev/cc-server:latest pair -
2 つのクライアントイメージは静的な nginx ホストです — 実行時に設定するものは 何もありません。各クライアントの接続フォームに、サーバー URL、デバイス ID、 ペアリングキーを入力します。シグナリングリレーも同様に、必要なのはポートだけです (
SIGNALING_HOST/SIGNALING_PORTは上書き可能)。リレーはステートレスでシークレットを 保持せず、あくまでフォールバックです — スマートフォンは到達可能な経路(ループバック、LAN、 tailnet、直接のwss://)があればそれを使い、どれも使えないときにだけリレーに フォールバックします。クライアントが常にサーバーに直接到達できるなら、リレーは省略してください。
このガイドの残りでは、サーバーをソースからビルドします。ここで扱うフラグと挙動は、 イメージの環境変数が渡すものと同じです。
前提条件
「前提条件」というセクション- Dart SDK。このリポジトリは SDK を fvm で固定しているため、すべてのコマンドの先頭に
fvmを付けます。 - このリポジトリをチェックアウト済みであること。
- ステージングスクリプトが必要とするネイティブツールチェーン — Rust/
cargo、およびmeson、ninja、pkg-config、gitと C++ コンパイラー。各ビルドスクリプトは、見つからないものとそのインストール方法を明示します。 - 到達可能なホスト: ローカルで使うならループバック、リモートクライアントから使うなら TLS 付きの LAN/公開アドレス。
ステップ 1: ネイティブライブラリをステージングする
「ステップ 1: ネイティブライブラリをステージングする」というセクションネイティブは必須です — 劣化モードはありません。何よりも先に、リポジトリの ルートからビルドします:
scripts/natives/build_natives.shこれにより rift、fff、tree-sitter とその文法、aec、lame、
ccpty、cc_watcher、cc_inference、および SAML ネイティブが
build/natives/ にビルドされます。cc_server のビルド
フックは、そこでステージングされたものをそのままバンドルに再出力するため、このステップを飛ばすと
ビルドがそのまま失敗するか、後述の回避手段を使った場合は、起動前チェックで不足している
ライブラリ名が示されて起動が拒否されるバイナリができあがります。
ステップ 2: バイナリをビルドする
「ステップ 2: バイナリをビルドする」というセクションcd apps/cc_serverfvm dart build cliバンドルには libsqlite3 とステージング済みのネイティブがバイナリと一緒に含まれます —
システムの SQLite も Flutter エンジンも不要です。実行ファイルは
./build/cli/<os_arch>/bundle/bin/cc_server に生成されます。
ステップ 3: 初回起動の前にクライアントをペアリングする
「ステップ 3: 初回起動の前にクライアントをペアリングする」というセクション新しいデータディレクトリにはペアリング済みデバイスも事前共有キーもないため、クライアントの
ペアリングキーの入力をまだ満たすことができません。pair サブコマンドで発行します。
これは global.db と secrets.json を直接書き込みます。すでにそのデータディレクトリを
提供しているサーバーは、再起動なしで新しいデバイスを認識します:
./build/cli/<os_arch>/bundle/bin/cc_server pair --data-dir ./data --port 9030クライアントの接続フォームに貼り付ける 3 つの値が出力されます:
Connect a thin client (paste into its connect form): Server ws://localhost:9030/rpc Device id web-client Pairing key <a freshly generated key>便利なフラグ: --device(既定は web-client。この id はデバイス
階層も決めます — desktop、ios、android、それ以外はすべて Web クライアント)、--label
(既定はプラットフォーム名とこのマシンのホスト名)、--host(URL に出力する
ホスト。ループバックは別のマシンから到達できないためです)、--client-url。pair を
再実行すると、そのデバイスのキーがローテーションされ、ライブセッションが切断されます。ペアリングで
ワークスペースが作成されることはありません。接続したクライアントのオンボーディングで最初の
ワークスペースに名前を付けて作成します。
--client-url を付けると、入力済みの Web
クライアントを開く、ターミナルでスキャン可能な QR も出力されます:
./build/cli/<os_arch>/bundle/bin/cc_server pair --data-dir ./data --port 9030 \ --bind any --host 192.168.1.42 --client-url https://app.usectrl.devcc_server pair で発行された資格情報には有効期限がありません。アプリで発行されたものは
常に 30 日で失効します。CLI で発行したデバイスは、使い終わったら
設定 → 自分 → 自分のデバイスから取り消してください。
ステップ 4: サーバーを起動する
「ステップ 4: サーバーを起動する」というセクションループバックの場合 — 既定であり、同じマシン上のクライアントにはこれだけで十分です:
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030別のマシンから到達させたい場合は、すべてのインターフェースにバインドします。TLS なしの
非ループバックバインドは起動時に拒否されるため(Refusing to bind non-loopback address … without TLS)、証明書を指定します:
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030 \ --bind any --tls-cert /path/fullchain.pem --tls-key /path/privkey.pem \ --public-url wss://server.example:9030/rpcまたは、信頼できるプライベートネットワーク上のリバースプロキシで TLS を終端し、 その背後で平文バインドを有効にします:
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030 \ --bind any --insecure --public-url wss://server.example/rpc--tls-cert と --tls-key の両方が設定されている場合、--insecure は無視されます — TLS
が常に優先されます。サーバーは平文状態を GET /healthz で insecure: true として通知し、
クライアントはそのような接続に安全でないことを示すバッジを付けます。
サーバーは SIGINT/SIGTERM まで動作し続け、その後クリーンにシャットダウンします。
ステップ 5: クライアントを接続する
「ステップ 5: クライアントを接続する」というセクションクライアントを、ステップ 3 のサーバー URL とペアリングキーに向けます:
- デスクトップアプリ: 初回起動画面(Control Centerをどのように実行しますか?)で、このアプリで実行ではなく接続用のフィールドに入力します。あるいは後から設定 → サーバー → 接続とステータスでサーバーを追加します。リモートサーバーに接続を参照してください。
- Web クライアント: app.usectrl.dev(または自分でホストしている Web ビルドのコピー)を開き、サーバー URL、デバイス ID、ペアリングキーを入力します。
- スマートフォン: 稼働中のクライアントから Remote アプリをペアリングします — デバイスをペアリングを参照してください。
ステップ 6: Google Calendar を接続する(任意)
「ステップ 6: Google Calendar を接続する(任意)」というセクションGUI を伴わずにワークスペースのカレンダーを同期するには、デバイスコードフローを使います:
GOOGLE_OAUTH_CLIENT_ID=<id> GOOGLE_OAUTH_CLIENT_SECRET=<secret> \ ./build/cli/<os_arch>/bundle/bin/cc_server calendar connect \ --data-dir ./data --workspace <workspace-id>別のデバイスで承認するためのコードと URL が出力され、リフレッシュトークンはサーバー側に
保存されて終了します。ソースからのビルドには Google クライアントが同梱されないため、id と
secret の環境変数が必須です — --google-client-id
というフラグはありません。Google Calendar を接続を参照してください。
これまでに使ったフラグは、最初のセットアップに必要なものです。完全なサーフェス — 23
組のフラグと環境変数、4 つのサブコマンド、データディレクトリの
レイアウト — は cc_server CLI リファレンスにあります。
もっとも必要になる可能性が高い 4 つ:
| フラグ | 既定値 | 意味 |
|---|---|---|
--data-dir |
OS のユーザーごとのアプリケーションデータディレクトリ | データベース、シークレット、モデル、キャッシュされたメディア |
--port |
9030 |
TCP ポート(0 = エフェメラル) |
--bind |
loopback |
loopback、または全インターフェースなら any(TLS または --insecure が必要) |
--public-url |
バインドから導出 | ペアリング済みクライアントに通知される RPC URL。プロキシ、NAT、トンネルの背後では明示的に設定してください |
既定のデータディレクトリは、macOS では ~/Library/Application Support/control-center、
Windows では %APPDATA%\control-center、それ以外では $XDG_DATA_HOME/control-center(なければ
~/.local/share/control-center)です。カレントディレクトリ相対の .cc_server が使われるのは、
ホームディレクトリもアプリデータディレクトリも解決できない場合だけです。
サーバーが提供するもの
「サーバーが提供するもの」というセクションcc_server は製品サーフェスの一部ではなく、その全体です。リポジトリ RPC のデータ経路
とサブスクリプション、同じポート上の POST /mcp と GET /sse にある MCP ツール
エンドポイント、受信 Webhook、メディアとフォントのプロキシ、シングルサインオン
のコールバック、フリートリースプロトコル、30 分間隔のサーバー側 RSS 取得、そして
ベクター検索(sqlite_vector 拡張は
プロセス全体の自動拡張として登録され、拡張が利用できない場合にのみ
全文検索にフォールバックします)です。
ディスパッチャーはステートレスです。セッションごとのワークスペースの紐づけは
ありません。ワークスペースを対象とするすべての呼び出しが自身の workspace_id を持ち、アクセスは
呼び出し元のワークスペースのメンバーシップとロールによって決まります — ペアリングキーを
保持しているかどうかでは決まりません。
ポートをループバックの外に公開する前に知っておくべき 2 つのこと:
- MCP はホスト外でフェイルクローズします。 トークンのない MCP サーフェスはループバックにしか応答しません。
anyにバインドしてもこの範囲は広がりません — トークンを設定するまで(mcp.setToken、または 設定 → サーバー → MCP サーバー)、ホスト外のリクエストは “MCP requires a bearer token to answer non-loopback clients” で拒否されます。 GET /healthzは設計上認証を必要としません。 ワイルドカード CORS を備え、サーバーの ID、名前、アイデンティティフィンガープリント、ビルドバージョンを公開します。クライアントはサーバーをピン留めするためにフィンガープリントを必要とするため、これは意図的なものです — ただし、到達可能なcc_serverは誰に対してもそれだけの情報を開示するという意味でもあります。