クイックスタート
前提 —— capture-ledger のスタックが動いていること
Section titled “前提 —— capture-ledger のスタックが動いていること”Windmill は capture-ledger のスタックの 2 つを使う。OpenFGA には、下の
windmill にクロールを許可するで「windmill は acme のクロールを
始めてよい」という許可を書き込む。BrowserHive は、
クロールがページを撮りに呼ぶ。始める前に、capture-ledger の
クイックスタートの §1〜§5
(DNS ドメイン、submodule と .env、stack:up、データベース、OpenFGA の 2 つの ID)を済ませ、
スタックが動いていることを確かめる。向こうの pnpm run dev:up は §3 以降をまとめて
やるので、手で打つのは §1 と §2 だけでもよい。
§4 のスクリプトを忘れないこと。 BrowserHive は走らせるものの顔ぶれを持たないので、
scripts 表が空だと、クロールはページの中で何も走らせない —— スクロールも遅延読み込みも
起きないまま、成功したアーカイブが出る。下の doctor のスクリプトがそれを言う。
curl -s -o /dev/null -w '%{http_code}\n' -H 'authorization: Bearer dev-key' http://127.0.0.1:8090/stores# 200 なら動いている。000 なら止まっている → cd ~/projects/crawler/capture-ledger && pnpm run stack:updev-key は開発用の OpenFGA の既定の鍵。止まったままだと、下の fga:grant が
「OpenFGA (http://localhost:8090) に届きません」で止まる。
以下のコードブロックは、どれも 1 行目の cd で「どの repo で打つか」を示す(2 つの repo は
~/projects/crawler/ に並べて clone してある前提。別の場所なら読み替える)。capture-scheduler の
コマンドを capture-ledger で打つと、pnpm は Missing script としか言わない。
cd ~/projects/crawler/capture-schedulersudo container system dns create capture-scheduler # マシンごとに 1 度だけ./setup.shcontainer-compose up -dpnpm install
pnpm run windmill:bootstrap # workspace と token を作り、2 枚のファイルに書く(下)pnpm run windmill:push # script・flow・schedule を入れる**貼る行はもう出ません。**bootstrap が書くのは、この repo の中の 2 枚だけです:
| ファイル | 中身 |
|---|---|
.env.local |
WINDMILL_TOKEN。この repo の script が読む |
.dev/capture-ledger.env |
capture-ledger に渡す 4 行。読むのは向こう |
capture-ledger の設定を書き換えるのは、向こうで打つコマンドの仕事です:
cd ~/projects/crawler/capture-ledgerpnpm run connect # 上の 4 行を読み、capture-ledger の .env.local に書く渡るのはこの 4 行。どれが欠けても、クロールは最後まで走りません:
CAPTURE_LEDGER_CRAWL_WEBHOOK_URL=http://127.0.0.1:8000/api/w/crawler/jobs/run/f/f/waggle/crawl_levelCAPTURE_LEDGER_CRAWL_WEBHOOK_TOKEN=<bootstrap が作った token>CAPTURE_LEDGER_API_HOST=0.0.0.0CAPTURE_LEDGER_OIDC_ISSUER=http://127.0.0.1:9099| 行 | なぜ要るか |
|---|---|
…_CRAWL_WEBHOOK_URL・…_CRAWL_WEBHOOK_TOKEN |
クロールを Windmill に投げる先。無いと /api/crawls そのものが無い(404) |
CAPTURE_LEDGER_API_HOST=0.0.0.0 |
段の報告はコンテナから来る。127.0.0.1 で待つ API には届かない |
CAPTURE_LEDGER_OIDC_ISSUER |
flow は JWT で名乗る。無い API は開発用ヘッダの設定になり、段の報告は 401 になる |
bootstrap は打つたびに新しい token を作ります(前に作ったものも、使えるまま残ります)。
打ち直したら connect も打ち直すこと —— 引き渡しファイルは新しい token で書き換わるので、
取りに行かないと capture-ledger は古い token のままです(古いほうも生きているので、
壊れるのではなく「直したはずなのに変わらない」形になります)。
connect を打ったら、capture-ledger 側で issuer を起こし、API を起こし直します。
capture-ledger のクイックスタート §6 で起こした API を、Ctrl-C で止めてから
同じコマンドをもう一度打ちます —— 新しく 2 本目を立てるのではありません。
API が設定を読むのは起動のときの 1 度だけなので、走ったままのプロセスは
上の 4 行を知りません。並べて立てようとしても、2 本目は
EADDRINUSE: address already in use 0.0.0.0:7070 で落ちます。どこに残っているか
分からなくなったら、capture-ledger の pnpm run dev:status が pid と起動時刻を出し、
pnpm run dev:down が止めます(issuer も API もコンテナではないので、
container-compose down では消えません)。
oidc:issuer は API より先に起こします。API は起動時に issuer の鍵を取りに行くので、
居ないと JWT の設定で立ち上がれません。
cd ~/projects/crawler/capture-ledgerpnpm run oidc:issuer # 動かし続けるpnpm run api # §6 で起こしたものを止めてから、同じ口でもう一度4 行が効いたかは、API の起動ログの最後の行が言います:
Archive API listening on 0.0.0.0:7070 — identity: JWT (http://127.0.0.1:9099); crawl level reports: readyblocked なら、その上の warn が足りない行を名指しします(capture-ledger v0.44.0 から)。
http://127.0.0.1:8000 で Windmill が開く。
Windmill の flow が capture-ledger を呼ぶためのトークンと、呼ぶ先を、Windmill の変数に入れる:
cd ~/projects/crawler/capture-schedulerpnpm run windmill:capture-ledger-token # トークンと、コンテナから見た API の宛先と、ts-compile-service の宛先を入れるAPI の宛先(u/admin/waggle_api_url)は、CAPTURE_LEDGER_API_URL を書かなければ default
ネットワークの gateway から組みます(container network inspect default)。network を作り直すと
変わるので、そのときは windmill:capture-ledger-token をやり直します。issuer を起こし直したときも
同じ(トークンの経路)。
windmill にクロールを許可する
Section titled “windmill にクロールを許可する”Windmill は capture-ledger を windmill という名前で呼ぶ(トークンの sub。組織は acme)。
capture-ledger は、クロールを始める・段を報告する・索引を渡す・締める、のたびに
「windmill は acme のクロールを始めてよいか」を OpenFGA に訊き、許可が無ければ 404 を返す。
手で始めたクロールでも、段の報告は windmill の名前で来る。
pnpm run fga:grant submitter windmill acme (あなたが 1 度だけ) │ 書く ▼OpenFGA user:windmill submitter organization:acme ▲ │ 訊く: user:windmill は organization:acme で can_submit か │ (クロールを始める・段の報告・索引・締めのたび)capture-ledger API ◄── Windmill(sub=windmill, orgs=[acme] のトークン) │ └─ 行が在れば 202。無ければ 404 {"error":"not found"}その許可を 1 行書き込む(capture-ledger 側で 1 度だけ。取り消すのは fga:revoke):
cd ~/projects/crawler/capture-ledgerpnpm run fga:grant submitter windmill acme# windmill は acme のクロールを始められます (書いた: user:windmill submitter organization:acme)CAPTURE_LEDGER_SUBJECT / _ORGANIZATIONS を変えたなら、その名前で。書けたかどうかは、下の
doctor の can_submit の行が教える —— 足りなければ、capture-ledger が実際に見た
名前で、打つべきコマンドを出す。
確かめる —— 1 本撮れるまで
Section titled “確かめる —— 1 本撮れるまで”cd ~/projects/crawler/capture-schedulerpnpm run doctor # 14 本の点検。全部 ✓ なら、クロールが最後まで走る設定になっているpnpm run smoke # https://example.com/ を 1 本撮り、WACZ を取り出せたら「撮れた」doctor は、このページの見出しごとに「その手が済んでいるか」を、その手が作ったものに訊く。 立っているかだけでなく、script の中身が repo と同じか、Windmill が持っているトークンで クロールを始められるか、worker の中から API と BrowserHive に届くか、まで見る。✗ は、何を 直すかと、このページのどの節の手かを言う。✗ の点検に頼る点検は走らせず、「先に〇〇を」とだけ 出す —— 直すものが 1 つなら、✗ も 1 本。
立ち上げる ✓ windmill http://127.0.0.1:8000/api/version … ✗ capture-ledger api http://127.0.0.1:7070/healthz ✗ oidc issuer http://127.0.0.1:9099/.well-known/openid-configuration ・crawl route 先に capture-ledger api を ・jwt 先に capture-ledger api・oidc issuer を
直すもの (2): capture-ledger api —— capture-ledger の API が答えない → cd ../capture-ledger && pnpm run api 手順: https://uraitakahito.github.io/capture-scheduler/ja/quickstart/#立ち上げる …smoke は、doctor が全部 ✓ のときだけ 1 本撮る。本番と同じ道 —— capture-ledger の
POST /api/crawls に flow と同じトークンで頼み、Windmill の flow に撮らせ、段の報告を待つ ——
を通し、台帳に載った archive を署名付き URL で取り出して、先頭が PK(WACZ は zip)であることまで
見る:
点検 doctor の 14 本とも ✓始める POST /api/crawls → 202 crawl 545e912c-… https://example.com/待つ runningrun http://127.0.0.1:8000/run/01a0ba19-…?workspace=crawler終わり succeeded (max_depth) —— 撮ったページ 1・6 秒取り出す archive 928d640f-… の先頭が PK (WACZ = zip)撮れた https://example.com/撮れなかったら、smoke が落ちた段と直し方を言う(原因 と 直す の 2 行)。言われた手を直して
smoke をもう一度。自分が始めたクロールは、失敗しても時間切れでも Ctrl-C でも締めるので、次の 1 本が
409 で塞がれることはない。Windmill の画面で追うなら、smoke が出す run の URL を開く(見方は
Windmill UI の「失敗を掘る」)。
cd ~/projects/crawler/capture-schedulerpnpm run smoke https://example.org/ # 撮る URL を変えるpnpm run smoke --timeout 300 # 待つ上限(秒。既定 180)pnpm run smoke --no-doctor # 点検を飛ばす(直した直後の撮り直し)pnpm run smoke --close-running # 409 のとき、走っている 1 本を締めてから撮るsmoke は capture-ledger v0.43.0 以上を前提にする(最後の段の run と、取れなかったページの理由を 台帳が返すのは、その版から)。
症状から引く
Section titled “症状から引く”どれも実物で起こして確かめた見え方(2026-09-19)。
| 見えたもの | 意味 | 直す |
|---|---|---|
doctor のスクリプトが ✗ / smoke が 400 no scripts are registered |
台帳にスクリプトが無いか、全部が既定に入らない(無効)。何も名指さないクロールは断られる | capture-ledger で pnpm run scripts import .upstream/capture-scripts。全部が無効なら pnpm run scripts enable <id> |
| doctor の windmill が ✗ で、下の点検が「先に windmill を」 | Windmill が落ちている | container-compose up -d(この repo で) |
| doctor の push が ✗「repo と中身が違う」 | script を直したが push していない(または Windmill の UI で直した) | pnpm run windmill:push(違いを見るだけなら windmill:diff) |
doctor の worker→browserhive が ✗「名前が引けない」(止めた直後の数秒は「3 秒で答えない」)/smoke の原因が [cap] BrowserHive に届きません: … |
BrowserHive のコンテナが止まっている(止めたコンテナは名前ごと消える) | capture-ledger で pnpm run stack:up |
smoke が succeeded・撮ったページ 0 で、原因が … net::ERR_NAME_NOT_RESOLVED … |
撮る URL の名前が引けない | URL の綴り。正しければ、BrowserHive のコンテナから外の名前を引けるか |
doctor の can_submit が ✗「… のクロールの許可が無い」/smoke の原因が … /pages → 404 |
windmill にクロールの許可が無い | capture-ledger で pnpm run fga:grant submitter windmill acme |
doctor の can_submit が ✗「トークンが通らない」/smoke の原因が … /pages → 401 |
issuer を起こし直し、Windmill のトークンが古い | pnpm run windmill:capture-ledger-token |
doctor の jwt が ✗「ヘッダで名乗る設定で動いている」(起動ログの最後の行は crawl level reports: blocked) |
capture-ledger の API が JWT を受けない(CAPTURE_LEDGER_OIDC_ISSUER が効いていない) |
capture-ledger で pnpm run connect を打ち、API を起こし直す |
doctor の container→api が ✗「API が 127.0.0.1 で待っている」/smoke の原因が Unable to connect |
段の報告がコンテナから API に届かない(CAPTURE_LEDGER_API_HOST=0.0.0.0 が効いていない) |
capture-ledger で pnpm run connect を打ち、API を起こし直す |
| smoke が 409「走行中のクロールがある: …」 | 前の 1 本が running のまま | 終わるのを待つか pnpm run smoke --close-running |
トークンの経路
Section titled “トークンの経路”host │ コンテナ dev issuer 127.0.0.1:9099 │ │ POST /token │ ▼ │ windmill:capture-ledger-token ───────────────┼──► secret 変数 u/admin/waggle_token │ │ capture-api 0.0.0.0:7070 ◄───────────┼── trigger_crawl.tsdev issuer は loopback から出さないこと。 あれは頼まれれば誰の名前でもトークンを
出すので、コンテナから引ける場所に置いた瞬間、ブリッジに届く誰もが windmill を
名乗れる —— fga:grant で windmill だけに与えたクロールの許可を誰でも使えることになり、
JWT にした意味が消える。
鍵を作る力は host に残し、跨がせるのは出来上がったトークン 1 本だけ。
issuer を再起動したら pnpm run windmill:capture-ledger-token をやり直すこと。
issuer は起動のたびに鍵をメモリ上で作り直すので(意図された挙動)、古いトークンは
401 になる。report_level.ts と trigger_crawl.ts の失敗メッセージがそう書いてあるのは、
踏みやすく、かつ status だけからは辿れないため。
API は起こし直さなくてよい。鍵の名前(kid)も一緒に替わるので、API は新しいトークンを
1 本見た時点で鍵を取り直す(capture-ledger v0.42.1 から。それより前は kid が固定で、
API が古い鍵を最長 10 分覚えたまま、新しいトークンを 401 にしていた)。issuer を起こし直した
直後の 30 秒は、新しいトークンも通らないことがある —— doctor の jwt がそう言う。
picker で見る(トークンを貼る)
Section titled “picker で見る(トークンを貼る)”CAPTURE_LEDGER_OIDC_ISSUER を立てた capture-ledger は JWT だけを受け付ける。ブラウザで開く
picker(http://127.0.0.1:7070/)もそれに合わせて、名乗りの 2 欄の代わりにトークンの欄を出す
(capture-ledger v0.45.0 から)。API の設定は変えずに、トークンを貼って読む:
cd ~/projects/crawler/capture-ledgerpnpm run --silent oidc:token --subject "$(whoami)" --org acme | pbcopyopen http://127.0.0.1:7070/「トークン」の欄に貼って「読み込む」を押す。一覧の上に「(名前)(acme)として見ている」と出れば、 API はそのトークンを受けている。トークンは 1 時間で切れる。issuer を起こし直したときも、 API が新しい鍵を取り直した時点から、前のトークンは通らない —— 「401 — このトークンは通らない…」と 出たら、同じコマンドで取り直して貼る。 画面の使い方は capture-ledger のアーカイブを見る。
JWT が dev ヘッダより優先されるのは capture-ledger 側の意図された設計で、「両方設定された
環境で弱いほうへ落ちない」ため。picker のために CAPTURE_LEDGER_OIDC_ISSUER を外さないこと ——
外した API は flow の段の報告を 401 で断り、走っていたクロールは running のまま残って、
以後の起動を全部 409 で塞ぐ。戻し方は capture-ledger のクイックスタートの
「409 が続くとき」。