毎度、ググっても出てこない小ネタを取り扱っております。
本記事は個人的な見解であり、筆者の所属するいかなる団体にも関係ございません。
今回は「こんな方法があるの?」と本当に驚いたSSHポートフォワーディングの活用方法です。
ググっても他にこの方法を書いている人はいませんでした。
1. はじめに
1-1. この記事の対象読者
- LXC コンテナや headless サーバー上で CLI ツールの OAuth2 認証に詰まっている方
-
gio: Operation not supportedやError: cannot open displayに遭遇した方 - SSH ポートフォワーディングを活用したトラブルシューティングに興味がある方
1-2. 問題の背景
LXC コンテナや headless 環境で CLI ツールを使っていると、OAuth2 認証が必要な場面に遭遇することがあります。
例えば claude /login コマンドを実行すると、以下のように OAuth2 認証用の URL が表示され、ブラウザで開くよう求められます:
Visit:
https://claude.ai/oauth/authorize?code=true&client_id=...
Opening browser...
gio: https://claude.ai/oauth/authorize?...: Operation not supported
しかし、LXCコンテナにはブラウザが存在しないため gioによるブラウザの自動起動が失敗します。
最初はX11フォワーディングでGUIブラウザを起動しようとしましたが、xeyesは動くのにFirefoxだけが失敗しました。straceで調査したところ、FirefoxがWaylandソケットを探して失敗していることが判明しました。(動かしていたのはUbuntu 24.04のLXCコンテナでした)
テキストブラウザ(w3m、lynx)も試しましたが、OAuth2の認証フローにはJavaScriptが必要なため動作しませんでした。
最終的にSSH のリモートポートフォワーディングで解決しました。本記事ではその仕組みと手順を解説します。
2. OAuth2の仕組み
2-1. OAuth2とは
OAuth2は、外部サービスへの認可を安全に委譲するためのプロトコルです。
例えば「Googleアカウントでログイン」のような機能がこれにあたります。パスワードをアプリケーションに直接渡すことなく、認可サーバー(Googleなど)が発行するアクセストークンを通じてリソースにアクセスできます。
2-2. 認可コードフロー(Authorization Code Flow)
CLIツールで使われるOAuth2の認証方式は「認可コードフロー(Authorization Code Flow)」が一般的です。フローは以下のようになります:
1. クライアント(CLIツール)がローカルでHTTPサーバーを起動(例: localhost:54545)
2. クライアント → 認可サーバー:
認可リクエスト(URLをブラウザで開くよう促す)
3. ユーザー → 認可サーバー:
ブラウザでログイン・認可画面を操作
4. 認可サーバー → クライアント:
コールバック(localhost:54545?code=xxx)にリダイレクト
5. クライアント → 認可サーバー:
認可コードをアクセストークンに交換
6. 認証完了
2-3. なぜブラウザが必要なのか
OAuth2の認証フローでブラウザが必要な理由は2つあります:
-
認可画面の表示にJavaScriptが必要
認可サーバーのログイン画面や認可画面はJavaScript を多用しており、テキストブラウザでは正常に動作しません。 -
コールバックをローカルのポートで受け取る
認証後、認可サーバーはブラウザをlocalhost:54545にリダイレクトします。このリクエストをCLIツールが受け取ることで認証が完了します。
2-4. headless環境での問題点
headless環境や LXCコンテナでは以下の問題が発生します:
| 方法 | 問題点 |
|---|---|
| ブラウザの自動起動 |
gio: Operation not supported でブラウザが見つからない |
| X11フォワーディング | Wayland/X11問題でブラウザが起動しない場合がある |
| テキストブラウザ | JavaScriptが動かず認証フローが完結しない |
3. SSH ポートフォワーディングによる解決
3-1. SSH ポートフォワーディングとは
SSH ポートフォワーディングとは、SSH のトンネルを通じてポートを転送する機能です。主に以下の2種類があります:
| オプション | 名称 | 方向 |
|---|---|---|
-L |
ローカルポートフォワーディング | ローカルのポート → リモートに転送 |
-R |
リモートポートフォワーディング | リモートのポート → ローカルに転送 |
今回使うのは リモートポートフォワーディング(-R) です。
3-2. 解決策の仕組み
OAuth2のコールバックは localhost:54545に届きます。これをリモートポートフォワーディングでリモートサーバー側に転送することで、ローカルのブラウザで認証しつつ、コールバックをリモートのCLIツールに届けることができます。
【ローカルマシン】 【リモートサーバー(LXCコンテナ)】
ブラウザで OAuth URL を開く
↓
認可サーバーで認証
↓
コールバック localhost:54545 ──SSH -R──→ localhost:54545
↓
CLIツールがコードを受け取る
↓
認証完了
3-3. 手順
ステップ1: -R オプション付きで SSH 接続する
ssh -R 54545:localhost:54545 user@remotehost
-R 54545:localhost:54545の意味:
- リモートの
54545ポートへのアクセスを - ローカルの
localhost:54545に転送する
私はXShellを使っているので以下のような設定にしました。

ステップ2: リモートで認証コマンドを実行しOAuth URLを取得する
claude # または認証が必要なCLIツール
表示されたOAuth URLをコピーします。
ステップ3: ローカルのブラウザでOAuth URLを開く
コピーした URLをローカルマシンのブラウザのアドレスバーに貼り付けて開きます。
ステップ4: 認証する
ブラウザ上でログインと認可を行うと、コールバックがSSHトンネル経由でリモートのCLI ツールに届き、認証が完了します。
4. 実践例:claude コマンドの認証
4-1. 環境
| 項目 | 内容 |
|---|---|
| リモート | LXCコンテナ(Ubuntu 24.04) |
| ローカル | SSHクライアント(X11フォワーディング設定済み) |
| 対象ツール |
claude(Claude.aiのCLIツール) |
4-2. 発生したエラー
エラー1: gioによるブラウザ起動失敗
gio: https://claude.ai/oauth/authorize?...: Operation not supported
コンテナ内にブラウザが存在しないため自動起動が失敗。
エラー2: X11フォワーディングでFirefoxが起動しない
Error: cannot open display: localhost:10.0
xeyesは動作するがFirefoxは失敗。straceで調査したところ:
connect(14, {sa_family=AF_UNIX, sun_path="/run/user/1000/localhost:10.0"}, 32)
= -1 ENOENT
FirefoxがX11ではなくWaylandソケットを探して失敗していることが判明。
エラー3: テキストブラウザでは認証フローが完結しない
sudo apt install w3m
w3m "https://claude.ai/oauth/authorize?..."
# → JavaScript が動かず認証できない
4-3. 解決手順
ローカルマシンから -Rオプション付きでSSH接続し直す:
ssh -X -R 54545:localhost:54545 t-yano@HermesAgent
リモートでclaudeコマンドを再実行:
claude
表示されたOAuth URLをローカルのブラウザで開く:
Visit:
https://claude.ai/oauth/authorize?code=true&client_id=...
ローカルブラウザで上記URLを開き認証すると、コールバックがSSHトンネル経由でリモートに届き認証が完了しました。
5. 注意点
5-1. ポート番号の確認
OAuth2のコールバックポートはツールによって異なります。事前にURLのredirect_uriパラメータを確認してポート番号を把握しておいてください。
redirect_uri=http%3A%2F%2Flocalhost%3A54545%2Fcallback
↑ ポート番号(54545)
5-2. sshd の設定
通常はデフォルト設定で動作しますが、リモートサーバーの/etc/ssh/sshd_configでGatewayPortsが no になっている場合、外部からのアクセスが制限されます。ループバック(localhost)への転送は通常デフォルトで許可されています。
# /etc/ssh/sshd_config
GatewayPorts no # デフォルト(localhostへの転送は可能)
5-3. セキュリティ
- OAuth URLには
stateやcode_challengeなどの認証トークンが含まれています。第三者に共有しないでください。 - 認証フローは一度しか使えないため、URLが漏れた場合は再認証してください。
- 認証完了後は不要なポートフォワーディングを閉じることを推奨します。
6. まとめ
6-1. まとめ
headless環境やLXCコンテナでOAuth2認証が必要な場合、SSHのリモートポートフォワーディング(-R) を使うことでローカルのブラウザを利用しつつ、コールバックをリモートのCLIツールに届けることができます。
ssh -R <コールバックポート>:localhost:<コールバックポート> user@remotehost
X11フォワーディングやテキストブラウザで詰まった際の有効な解決策として覚えておくと便利です。