2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Cloudflare OSを触ってみる

2
Last updated at Posted at 2026-08-09

Cloudflare OSを触ってみる

投稿者はCloudflareについてさえも全く知りません。
個人で作ったプロダクトをCloudflareを通すと比較的安全に公開できるって程度の理解です。
備忘録程度

調査

まずは下記の観点でCloudflare OSについて調べてみます。

  • サービス概要
  • 何ができる?
  • どんな感じに動作するの?
  • どんな場面で活用できそう?
  • ローカルLLMで動かせそう?

参照ソース

github
Cloudflare OS公式


サービス概要

githubに記載されている内容から、全てに対して使えるAI開発環境っぽい(意訳)

Cloudflare OS is an "operating system" for AI productivity originally developed for use inside Cloudflare. A large portion of Cloudflare's workforce -- from engineering to sales and everything in between -- uses Cloudflare OS every day to help them do their jobs.

コンピュータ環境の一般的なOSではなくセキュアにAIを活用し、AIワークロードに対してのOSって話みたい

Cloudflare OSを使ってできることは

  • Agentとのチャット(アプリ作るための?)
  • サンドボックスを使いgadgetsと呼ばれる個人アプリを作って他者に共有できる
  • Gatekeepersと呼ばれるセキュリティフレームワークを使って、技術者じゃなくても熱中して使える

とりあえずgithubのreadme冒頭に記載されている内容を書いてみた

感覚的にはCopilot Studio + Copilot chatみたいな感じ?
 → google AI Studioに近い気がする

わからない単語が出てきたので、それについてもreadmeに載っていた

gadgets

Cloudflare OS上のユーザ専用のアプリのこと

  • サンドボックス上なのでセキュア
  • バグがあってもAIがよしなにやってくれる

が特徴らしい

Gatekeepers

能力ベースのセキュリティ層のこと
 → 能力ベースってなんだ。

強化版MCPサーバ(?)

gadgetsやagentが外部リソースにアクセスする際の接続を管理する

  • どんなWebAPIでも扱いやすいAPI形式に変換
  • 権限の管理(OAuthとか)
  • アクセス先を制限
  • gadgetやagentのパフォーマンスやログを取得
  • human in loopをさせる(ユーザ側に動作の許可をもらう)

human in loopについてはどうやらこだわりがあるよう
大体、動作許可の依頼が来たときに毎回、動作の度に出るので自動承認にしがち(投稿者も)。
Gatekeeperはagentに対して結果のダミー送信をさせて、agentに動作完了させたと認識させる。
それにより次の動作をagentにさせて、ユーザは後から結果を確認させて、本実行させる感じ。
だからagentとユーザ承認が非同期に進む感じかな?


何ができるのか?

公式のホームページの動画を見る感じだと

  • チャット
  • ドキュメントとかワークシートの作成
  • アプリ作成
  • ワークフローの作成と実行
  • アプリの共有

この辺りは実際に触ってみる時に確かめてみようかな


どんな感じに動作するの?

チャット欄からエージェントに対してアプリの要件を話して、外部データとの連携もしてもらう感じ。
ここでスクリーンショットとかも貼ったのでこっちを確認してもらった方がいいかも


どんな場面で活用できそう?

他のアプリケーション(slack, github)と連携してローカルでアプリを作る感じ?
アクセス数とかBIとかなのかなぁ...
githubのskillsとしてgatekeeperを作成するものを公開している。
これを使って独自のgatekeeperを作って、自分のサービスのAPIをたたかせたりできそうな雰囲気がしている。


ローカルLLMで動かせそう?

自分の環境にはollamaがあるので、それで動かせるかを確認する


APIは叩ける?

packages/workshop-backend/src/ai-models.ts
にプロバイダとしてollamaが入ってるから使えそう...?
ollamaはローカルだからAPI費用がかからないようにundefined?

// Consult pi's builtin catalog for cost/compat metadata of a known model id. Unknown models are
// fine (synthesized with zero cost). Import per-provider, not providers/all.
function catalogModel(provider: AiModelConfig["provider"], modelId: string): Model<Api> | undefined {
  switch (provider) {
    case "anthropic": return (ANTHROPIC_MODELS as Record<string, Model<Api>>)[modelId];
    case "openai": return (OPENAI_MODELS as Record<string, Model<Api>>)[modelId];
    case "google": return (GOOGLE_MODELS as Record<string, Model<Api>>)[modelId];
    case "cloudflare": return (CLOUDFLARE_WORKERS_AI_MODELS as Record<string, Model<Api>>)[modelId];
    case "ollama": return undefined;
    default: return undefined;
  }
}
function getModelDirect(config: AiModelConfig, sessionAffinity?: string): ModelHandle {
...
    case "ollama":
      // `apiUrl` is the Ollama server base; its OpenAI-compat endpoint lives under /v1. Accept
      // (and strip) a trailing `/api` or `/v1` path: configs saved before the pi migration store
      // the native-API base `http://host:11434/api` (the old ollama provider's convention), and
      // users may paste the /v1 endpoint directly. When no API key was configured we assume
      // local auth and send no Authorization header at all (as before the pi migration; a strict
      // local proxy may reject an unexpected bearer token): the OpenAI SDK requires *some* key,
      // so give it a placeholder while a null default header deletes the Authorization header
      // the SDK derives from it.
      return makeHandle({
        model: {
          id: config.model,
          name: config.model,
          api: "openai-completions",
          provider: "ollama",
          baseUrl: `${stripTrailingSlashes(config.apiUrl ?? "http://localhost:11434")
              .replace(/\/(api|v1)$/, "")}/v1`,
          reasoning: true,
          input: ["text", "image"],
          cost: ZERO_COST,
          ...window,
        },

config.apiUrlが空ならhttp://localhost:11434なので、ここをUIとかで設定できれば良さそう

実際にやってみた

前提として投稿者は

端末 - リバースプロキシ(ホストA) - gpu搭載PC - cloudflare osコンテナ

の経路で端末から操作しようとしています。

2026/08/09現在、他のアプリとの連携がうまく行ってないです。
githubの連携をしようとしたらlocalhostにリダイレクトされたりしているので
 → ほんとは今接続しているIPとportにリダイレクトしてほしい
この辺りは今後の改善に期待かなと...(早期公開みたいな立ち位置みたいだし)

git clone https://github.com/cloudflare/cloudflare-os.git

dockerfile

FROM node:22-slim

# pnpmの有効化
RUN corepack enable

WORKDIR /app

# ソースコードのコピー
COPY . .

# パッケージインストール
RUN pnpm install

EXPOSE 8787
# ↓--ip 0.0.0.0の設定が効かない...
# relay用のコンテナを作って外部との橋渡しをする
CMD ["pnpm", "run-local", "--", "--ip", "0.0.0.0"]

docker compose

services:
  cloudflare-os:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: cloudflare-os
    # ollamaが同じホスト上のコンテナとしてあるため繋げる
    extra_hosts:
      - "host.docker.internal:host-gateway"
    ports:
      - "9009:9009" # ホスト側ポート:コンテナ側ポート
    environment:
      - NODE_ENV=development
      # 応答まちで止まらないように
      - CI=true
      # アプリが自身のアクセス用URLを認識するための設定
      # - VITE_BACKEND_HOST=localhost:8787
    volumes:
      - .:/app
      # コンテナ内の node_modules をローカル側で上書きしないように保護
      - /app/node_modules
    # ターミナルでの入力受け取り・対話モード維持用
    tty: true
    stdin_open: true
    restart: always

# 別ホスト上にあるリバースプロキシと接続させるため
  relay:
    image: alpine/socat
    container_name: cloudflare-os-relay
    network_mode: "service:cloudflare-os"
    depends_on:
      - cloudflare-os
    command: ["tcp-listen:9009,fork,reuseaddr", "tcp-connect:127.0.0.1:8787"]
    restart: always

リバースプロキシ

server {
    listen 9009;
    server_name localhost;

    access_log /var/log/nginx/cloudflare-os-direct-access.log;
    error_log  /var/log/nginx/cloudflare-os-direct-error.log;

    location / {
        proxy_pass http://<cloudflare-osが置いているホストのIP>:9009;

        # 基本ヘッダー
        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;

        # WebSocket対応(Cap'n Web RPCやライブ更新系の通信で必要になる可能性が高い)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # エージェントの応答はストリーミング(SSE)になりうるので、タイムアウトを長めに
        proxy_read_timeout 300s;
        proxy_send_timeout 300s;

        # バッファリングを切っておく(ストリーミング応答が遅延なく届くように)
        proxy_buffering off;
    }

    # ファイルアップロード(ナレッジベースへのドキュメント添付など)を見越して緩めに
    client_max_body_size 50m;
}

http://<リバースプロキシIP>:9009にログインしたら、アカウント作成からやる

model設定ができるのでここから
ollamaを選択して、モデルID、画面に表示するモデル名、OllamaのURLを記入
OllamaのURLはhttp://host.docker.internal:11434

image.png

その後の色々の連携はスキップして、とりあえずチャットまで

image.png

とりあえずチャットまではできた。

多分ここからこういうアプリがほしいとか言ったらできるんだろうなぁと想定

とりあえずAgents-A1-4B-Q8_0を使ってやってみた。

gemma4:e4bとqwen3.5:9bを使ってみたけど、なんかうまくファイルを作成してくれない。
たまたまの可能性はあるが

個人用ダッシュボードを作ってほしいとふわっとしたお願いをしてみた
やっぱ4Bの性能だからか、めっちゃ時間かかる
あと、エラー吐いてうまくいかない。
このエラーについてもLLMにぶん投げることができる
image.png

途中から35Bの方に切り替えたAgent-A1:35B

image.png
...まぁ、画面には出力されるようになった。
ちなみにここまでになるのに30分程度かかった

google AI Studioやってる感じだ。
ローカルモデルで30B程度だと結構苦戦する。
ここでagentモデルが活躍するのかと、改めて思った。
qwen-agentworldあたりとかどうなるか気になる。

あと、チャット欄から入力しているけど、英語用なのか変換するためにエンター押下するとチャットに出される。この辺り調整したいなぁ(自分がmac使ってるから?)

終わり

実際に触ってみたけど、ローカルLLMを使う場合、結構いいやつを使わないと厳しい気がした。
 → これは自分がagent方面のLLMに明るくないからかもしれないけど
difyと違って全部LLMに投げることができるってのは面白い。(保守には目を背けて)

qwen3-coder-nextとかqwen-agentworldを使ってどんな感じか確かめてみるか〜。

追記

qwen-agentworldでやってみた。
思った以上にエラーなくできたので、結構いいかも。

image.png

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?