やってみた 2026年7月22日

P2P転送CLIのcrocを使い捨てコンテナで動かしたら、go installも--codeも素直に通らなかった話

XECIN GoCLIファイル転送暗号化

GitHubのトレンドを流し見していたら、schollz/croc が上のほうに来ていました。「任意の2台のコンピュータの間で、シンプルかつ安全にファイルとフォルダを転送する」ツールだそうです。

私はバックエンドを長くやってきたので、「別のマシンにちょっとファイルを渡したい」という場面には人並み以上に遭遇してきました。たいていは scp か、それでダメなら一時的にS3のバケットを経由させるか。ただ、相手が同僚のノートPCだったり、SSHの鍵を交換していない相手だったりすると、そのたびに準備が要って地味に面倒だったりします。

crocが謳っているのは、その準備を「コードフレーズ1個」まで削るという話でした。PAKE(パスワード認証鍵共有)で端末間を暗号化し、リレー経由でNAT越えもするので、ポート開放もローカルサーバも要らない、と。うたい文句は昔からよく見かけていたのですが、実際に自分の手で動かした記憶が意外となかったので、使い捨てのコンテナに放り込んで確かめてみました。

試した環境

  • ホストはWindows + Docker Desktop、検証は使い捨ての golang:1.22-bookworm コンテナの中だけで完結させています
  • コンテナ内: Debian 12 bookworm / Go 1.22.12
  • croc は最終的に v10.5.0(2026-07-21 リリース)を使用
  • 公開リレー(croc.schollz.com)には頼らず、コンテナ内に自前のリレーを立てて、送信・受信ともにローカルで閉じています

先に断っておくと、後半で出てくる転送速度は「同一ホストのループバック越し」の数字です。インターネット越しの実力ではないので、そこは差し引いて読んでください。

最初のアプローチ:go install がそもそも通らなかった

READMEの「Build from Source」には、こう書いてありました。

requires Go 1.22+

手元のコンテナは Go 1.22.12。ならいけるだろう、と go install から入ったのですが、これがあっさり弾かれました。

$ go install github.com/schollz/croc/v10@latest
go: downloading github.com/schollz/croc/v10 v10.5.0
go: github.com/schollz/croc/v10@latest: github.com/schollz/croc/v10@v10.5.0
    requires go >= 1.25.0 (running go 1.22.12; GOTOOLCHAIN=local)

READMEは「1.22+」なのに、実際のモジュールの go ディレクティブは 1.25 を要求している。READMEの記述が追いついていないパターンですね。GOTOOLCHAIN=auto にすればGo側が1.25のツールチェインを勝手に落としてきて解決はしますが、それはそれで150MB近いダウンロードが走ります。

で、README を上から読み直したら、ソースビルドはそもそも後ろのほうの選択肢で、推奨は先頭にある公式インストーラのほうでした。こちらはビルド済みバイナリを取ってくるだけなので、Goのバージョン問題とは無関係です。

$ curl -sL https://getcroc.schollz.com | bash
== Architecture detected as x86_64
== OS detected as Linux
== Checksum of croc_v10.5.0_Linux-64bit.tar.gz verified
== Installed croc to /usr/local/bin/
== Installation complete

ダウンロードから設置まで実測2秒。チェックサムの検証まで踏んでくれるのは、curl | bash 系にしては良心的だと感じました。最初からこっちを読んでいればよかった、というだけの話ではあります。

$ croc --version
croc version v10.5.0

自前リレーを立てて、まず素直に送ってみる

crocは既定だと公開リレーを使いますが、今回は外に出さずコンテナ内で完結させたかったので、自前のリレーを立てました。

$ croc relay
[info] starting croc relay version v10.5.0
[info] starting TCP server on :9009
[info] starting TCP server on :9011
[info] starting TCP server on :9012
[info] starting TCP server on :9013
[info] starting TCP server on :9010

croc relay はデフォルトで 9009〜9013 の5ポートを開きます(最低2ポート必要とのこと)。これをバックグラウンドに回しておいて、1MBのランダムデータをbase64にした約1.4MBのファイルを、--relay でこのリレーに向けて送ってみます。

$ croc --relay localhost:9009 send payload.txt
Sending 'payload.txt' (1.4 MB)
Code is: 1373-square-fish-ford

On the other computer run:
    croc --relay localhost:9009 1373-square-fish-ford

コードフレーズが 1373-square-fish-ford ——「数字+英単語3つ」の形で自動生成されました。この語呂を口頭やチャットで相手に伝えれば転送が成立する、という設計です。別のシェルで受け取り側を動かすと、あっさり通りました。

$ CROC_SECRET=1373-square-fish-ford croc --relay localhost:9009 --yes
Receiving 'payload.txt' (1.4 MB)
payload.txt 100% |████████████████████| (1.4/1.4 MB, 127 MB/s)

受信側で1秒。同一ホストのループバック経由なので 127 MB/s と出ていますが、これは実力というより「経路がほぼゼロ距離」というだけの数字です。転送後には受信側がハッシュ検証を回していて、送信元と受信先で sha256 が一致することも確認できました。

$ sha256sum payload.txt recv/payload.txt
0775e85d568e93b173a20f8f488bfecc8ff5dd3884199b256dd5e98c8e34611b  payload.txt
0775e85d568e93b173a20f8f488bfecc8ff5dd3884199b256dd5e98c8e34611b  recv/payload.txt

ここまでは、うたい文句どおり気持ちよく動きました。

引っかかったところ:--code がUNIXで拒否される

自分でコードフレーズを決めたくなって、READMEにあった croc send --code [code-phrase] を素直に打ったら、転送が始まらずにこう返ってきました。

$ croc --relay localhost:9009 send --code mysecret-8083 payload.txt
On UNIX systems, to send with a custom code phrase,
you need to set the environmental variable CROC_SECRET:

  CROC_SECRET=**** croc send file.txt

Or you can have the code phrase automatically generated:

  croc send file.txt

最初は「オプションのタイポかな」と思ったのですが、そうではありませんでした。これは CVE-2023-43621 —— コードフレーズをコマンドライン引数に置くと、同じマシンの他ユーザーからプロセス一覧(ps の引数)で秘密が丸見えになる、という問題への対策です。その名残で、Linux/macOSでは コードフレーズを引数で渡す口が塞がれている

ポイントは、これが受信側だけの話ではなく 送信側にも効くことでした。自分は最初、受信は環境変数、送信は --code、と無意識に非対称に考えていたのですが、実際は送受信の両方で CROC_SECRET を使う必要があります。環境変数に置き直したら、指定したフレーズがそのままコードとして通りました。

$ CROC_SECRET=mysecret-8083-demo croc --relay localhost:9009 send payload.txt
Sending 'payload.txt' (1.4 MB)
Code is: mysecret-8083-demo

ひとつ細かいところで言うと、自動生成コードのときに croc が表示してくる受け取り手順は croc --relay localhost:9009 1373-square-fish-ford という引数にコードを載せた形でした。これはWindows向けの案内で、同じUNIX上で受けるならさっき弾かれたのと同じ形なんですよね。案内文の分岐までは細かく出し分けていないようで、ここは初見だと少し迷うところかもしれません。改善の余地というより、--classic を明示すれば従来どおり引数でも受けられるので、単一ユーザーのマシンなら好みで切り替えてくださいという設計思想なのだと理解しました。

ファイルだけでなく短いテキストも送れる

ついでに、URLや短い文字列を渡す --text も試しました。これはファイルを作らず、受信側の標準出力に直接出ます。

$ CROC_SECRET=txt-8083-demo croc --relay localhost:9009 --yes
Receiving text message (37 B)
hello from the croc yattemita sandbox

ちょっとした環境変数の値やワンライナーを別マシンに渡すとき、いちいちファイルにしなくていいのは地味に便利です。クリップボード連携(既定でコードをコピーする)も含めて、「人間が手で1回渡す」用途にかなり寄せて作られている印象を受けました。

scp と比べてどう位置づけるか

ベテランの癖で、つい「なぜ手持ちの scp ではなくこれを使うのか」を考えてしまいます。今回ベンチマークで殴り合わせたわけではないので、あくまで設計上の役割分担としての整理です。

観点scp / rsynccroc(今回試した範囲)
事前準備SSH到達性・鍵交換・known_hosts共有するのはコードフレーズ1個だけ
NAT越え基本は自前で穴を用意するリレー経由で越える前提の設計
秘密の扱いSSH鍵で恒久的に管理1回限りのフレーズ。UNIXでは引数渡しを封じ環境変数へ

こうして並べると、両者は競合というより住み分けだと感じます。恒常的なサーバ間の同期は今後も rsync のままでいいけれど、「鍵を交換していない相手に、いま1回だけ渡す」——この一点に関しては croc のほうが摩擦が少ない。私の現場の言い方をすると、scp は”配線済みの回線”で、croc は”その場で張る仮設の一本”、というイメージが近いです。

試してみての所感

正直なところ、動かす前は「有名だけど枯れた転送ツール」くらいの雑な認識でした。実際に触ってみると、うたい文句の「コードフレーズ1個で完結」はそのとおり気持ちよく動く一方で、READMEのGoバージョン表記のズレや、--code がUNIXで塞がれている件のように、ドキュメントを素直になぞると一度は引っかかる箇所がいくつかありました。そしてその引っかかりの多くが、CVE対策のような「安全側に倒した結果」だった、というのが今回一番の収穫だったりします。

エッジケースを気にする人間としては、--code を封じてまで引数経由の秘密漏洩を潰しにいっている設計は、むしろ信頼できると感じました。転送ツールで秘密がプロセス一覧に載る、というのは地味だけど確実に踏みうる穴なので。

自分としては、次は公開リレーではなく社内に自前リレーを常設した構成で、実ネットワーク越しの速度とresume(中断再開)まで測ってから、チームの「ちょっと渡す」用の標準にするかを判断したいところです。今回はループバックの数字しか取れていないので、そこは持ち帰りの宿題ということで。