Ubuntu 26でキーボードをカスタマイズ(Caps Lock⇔Ctrl入れ替えとCtrl+SpaceでIME切替)

メモ

Ubuntu 26.04 LTS (Resolute Raccoon) でキーボードを2点カスタマイズするメモ。

  1. Caps LockキーとCtrlキーを入れ替える
  2. Ctrl + Space で日本語入力(Mozc)と直接入力を切り替える

Ubuntu 26.04 LTSはGNOME 50を採用しており、GNOME-on-X11セッションが廃止され、デスクトップはWaylandのみで動作する点に注意(XWaylandは引き続き利用可能)。これに伴い、xmodmapsetxkbmap といったX11時代の小技は使えない(XWaylandアプリにしか効かない)ため、GNOME本体の設定や低レイヤなツールを使う必要がある。

環境

  • Ubuntu 26.04 LTS (Resolute Raccoon)
  • GNOME 50 / Wayland セッション
  • USキーボード(JISでも考え方は同じ)

Caps LockとCtrlの入れ替え

方法1: GNOME Tweaks(GUI)

一番手軽なGUI手順。Tweaksを入れていない場合は先にインストールする。

1
$ sudo apt install gnome-tweaks

Tweaksを起動して以下を辿る。

  1. 左メニューの「Keyboard」(キーボードとマウス)を開く
  2. 「Additional Layout Options」をクリック
  3. 「Ctrl position」を展開
  4. 「Swap Ctrl and Caps Lock」を選択

設定は即時反映され、再ログインしても保持される。

方法2: gsettingsコマンド(CLI / Wayland対応)

Tweaksを入れたくない場合や、dotfilesで管理したい場合は gsettings を直接叩く。Waylandでもそのまま効く。

現状確認:

1
$ gsettings get org.gnome.desktop.input-sources xkb-options

入れ替え:

1
$ gsettings set org.gnome.desktop.input-sources xkb-options "['ctrl:swapcaps']"

代表的なオプション:

オプション 動作
ctrl:swapcaps Caps LockとCtrlを入れ替え
ctrl:nocaps Caps LockをCtrlに置き換え(Caps Lockは使えなくなる)
caps:ctrl_modifier Caps Lockを「もう一つのCtrl」として扱う(Caps Lockも残る)

元に戻す:

1
$ gsettings reset org.gnome.desktop.input-sources xkb-options

なお、gsettings の値はGNOMEセッションに対する設定なので、コンソール(TTY)には効かない。コンソールでも入れ替えたい場合は /etc/default/keyboardXKBOPTIONSctrl:swapcaps を追加し、sudo dpkg-reconfigure keyboard-configuration を実行する。

方法3(補足): keyd によるカーネルレベルの入れ替え

GNOMEに依存せず、ログイン画面・コンソール・任意のWaylandコンポジタで一様に動かしたい場合は keyd を使う。evdev / uinput を経由してカーネルレベルでリマップするため、X11/Waylandを問わず動作する。

1
2
$ sudo apt install keyd
$ sudo systemctl enable --now keyd

/etc/keyd/default.conf を以下のように作成する。

1
2
3
4
5
6
[ids]
*

[main]
capslock = control
control = capslock

設定を反映:

1
$ sudo keyd reload

「Caps Lockをホールド時はCtrl、タップ時はEsc」のような複合動作が欲しい場合もkeydで書ける(Vim使いには定番)。

Ctrl + Space で日本語/英語切り替え

Ubuntu 26.04 では IME フレームワークとして IBus(従来のデフォルト)と fcitx5(近年推奨されつつある)の二択になる。WaylandやAnki等のElectronアプリとの相性ではfcitx5の方が安定しているケースが多い。

どちらを使うかで設定箇所が変わるので、それぞれ書く。

注意: Super + Space との競合

GNOME 50のシステム既定は Super + Space で入力ソースを切り替える挙動。Ctrl + Space を IME 側に割り当てる場合、システム側のショートカットを変更する必要はないが、Ctrl + Space を別アプリ(Emacs の set-mark-command、tmuxのprefix等)で使っている場合は競合するため要注意。

パターンA: IBus + Mozc の場合

Ubuntu の伝統的な構成。IBus の「入力ソースの切り替え」ではなく、Mozc側のキー設定でトグルを定義するのが素直。理由は、IBusのレイヤだと「直接入力 → Mozc」の片方向しか拾わないことがあり、トグルとして機能させるには Mozc 内のモード遷移を直接書く必要があるため。

  1. 画面右上の入力ソースアイコンをクリック → 「ツール」 → 「プロパティ」を開く
  2. 「キー設定」の項目で「キー設定の選択」を「カスタム」にし、「編集」をクリック
  3. キーマップエディタで「編集」 → 「エントリーを追加」を選び、以下の2エントリを追加する
モード キー コマンド
直接入力 Ctrl + Space IMEを有効化
入力文字なし Ctrl + Space IMEを無効化

ポイントは、IMEを有効化する側のモードを「入力なし」ではなく「直接入力」にすること(先に紹介した UbuntuでJISとUSの両キーボードを使う の記事と同じパターン)。

合わせて、デフォルトで Ctrl + Space に「全角スペースを挿入」が割り当てられているエントリがある場合は削除しておく。重複していると意図しない挙動になる。

設定後はログアウト/ログインで反映。反映が怪しい時は以下で再起動できる。

1
$ ibus-daemon -drx

パターンB: fcitx5 + Mozc の場合

fcitx5 はそもそも デフォルトのトリガキーが Ctrl + Space だが、Ubuntu 26 + GNOME 50(Wayland)の組み合わせでは「インストールしただけでは動かない」要素が複数ある。順に潰す必要がある。

B-1. パッケージのインストール(フロントエンド込み)

1
2
3
4
5
$ sudo apt install fcitx5 fcitx5-mozc fcitx5-config-qt \
fcitx5-frontend-gtk3 fcitx5-frontend-gtk4 \
fcitx5-frontend-qt5 fcitx5-frontend-qt6 \
mozc-utils-gui
$ im-config -n fcitx5

フロントエンドパッケージ(gtk3/4, qt5/6)を入れ忘れると、fcitx5は起動するけれど対象アプリで Ctrl + Space を押しても無反応、という症状になる。最初は環境変数だけ確認しがちだが、フロントエンドが無いとそもそもアプリ側にIMモジュールが注入されない。

B-2. ~/.config/fcitx5/profilekeyboard-usmozc を並べる

これが特に分かりにくい。fcitx5のトリガキーは「IMをon/off」ではなく「グループ内の入力メソッドをトグル」。グループに mozc しか居ないと、Ctrl + Space を押しても見かけ上の挙動が「mozc ⇄ inactive」となり、英語直接入力には戻らないか、fcitx5自体がオフになって入力レイアウト依存になる。

profile の最小例(USキーボード):

1
2
3
4
5
6
7
8
9
10
11
12
13
[Groups/0]
Name=Default
Default Layout=us
DefaultIM=mozc

[Groups/0/Items/0]
Name=keyboard-us

[Groups/0/Items/1]
Name=mozc

[GroupOrder]
0=Default

JISキーボードなら keyboard-uskeyboard-jpDefault Layout=usDefault Layout=jp に変える。

GUIで入れたい場合は fcitx5-configtool を起動 → 左の「Input Method」タブで Keyboard - English (US)Mozcこの順で リストに登録する。

B-3. ~/.config/fcitx5/config の TriggerKeys は サブセクション形式 で書く

地味だが重大なハマり所。以下は動かない書き方:

1
2
3
4
# NG: TriggerKeys と 0= が同じ [Hotkey] セクション内
[Hotkey]
TriggerKeys=
0=Control+space

正しい書き方は、Hotkey/TriggerKeys という独立したサブセクション:

1
2
3
4
5
[Hotkey/TriggerKeys]
0=Control+space

[Hotkey/AltTriggerKeys]
0=Shift_L

前者はfcitx5に「TriggerKeysが空のリスト」と解釈され、Ctrl + Space を押しても沈黙する。設定後は fcitx5 -r で再起動。

B-4. fcitx5の自動起動を仕込む

Ubuntu 26 + GNOME 50 では、im-config -n fcitx5 だけでは fcitx5 デーモンはログイン時に起動しない。/etc/xdg/autostart/ にfcitx5のdesktopファイルが配られるパッケージ構成にもなっていないので、自分で入れる:

1
2
3
4
5
6
7
8
9
$ mkdir -p ~/.config/autostart
$ cat > ~/.config/autostart/fcitx5.desktop <<'EOF'
[Desktop Entry]
Type=Application
Name=Fcitx 5
Exec=fcitx5 -d
X-GNOME-Autostart-enabled=true
NoDisplay=false
EOF

B-5. 既存の ibus 系 autostart をユーザ側でマスクする

これも踏みやすい罠。apt purge ibus-mozc をしていない場合、/etc/xdg/autostart/ には ibus-mozc-gnome-initial-setup.desktopibus-mozc-launch-xwayland.desktop などが残り、毎回ログイン時に ibus-daemon が起動する。fcitx5と並走して、フォーカスや起動順次第でキー入力を奪い合う。

ユーザ側の ~/.config/autostart/ に同名ファイルを置けば、システム側はシャドウされる。

1
2
3
4
5
$ for f in /etc/xdg/autostart/ibus-*.desktop; do
name=$(basename "$f")
cp "$f" ~/.config/autostart/"$name"
echo 'Hidden=true' >> ~/.config/autostart/"$name"
done

B-6. GNOME側の入力ソース切替ショートカットを潰す

Ubuntu 26のGNOMEは入力ソースをデフォルトで Super + Space に割り当てているが、設定経路によっては Ctrl + Space も拾うことがある。さらに org.gnome.desktop.input-sources sources に複数登録があると、GNOME自体がキー入力を横取りしてfcitx5に届かなくなる。

1
2
3
4
5
6
# 入力ソースを単一に固定(fcitx5に任せる)
$ gsettings set org.gnome.desktop.input-sources sources "[('xkb', 'us')]"

# WMキーバインドの切替系を空に
$ gsettings set org.gnome.desktop.wm.keybindings switch-input-source "[]"
$ gsettings set org.gnome.desktop.wm.keybindings switch-input-source-backward "[]"

B-7. 反映と確認

ここまでやってログアウト/再ログイン(または再起動)。確認:

1
2
3
4
$ env | grep -E 'IM_MODULE|XMODIFIERS'   # fcitx を指しているか
$ pgrep -a fcitx5 # fcitx5 が起動しているか
$ pgrep -x ibus-daemon # 何も出ないことを確認(出るならB-5を見直し)
$ fcitx5-remote -t && fcitx5-remote -n # CLIでトグル → mozc / keyboard-us

もし端末で env に出ないが gnome-shell 本体には入っている、というケースもある。これはGUIアプリには効いている状態なので、入力テスト本体(テキストエディタで Ctrl + Space)が成功するならOK。

動作確認

テキストエディタや端末で Ctrl + Space を叩き、画面右上のIMEインジケータが「あ」と「A」(または相当の表示)で切り替わるかを確認する。切り替わらない場合は、以下を順に確認する。

  • システムショートカット(Settings → Keyboard → View and Customize Shortcuts)でCtrl+Spaceに別の機能が割り当たっていないか(B-6)
  • Mozc側のキー設定が 直接入力入力文字なし の両方に入っているか(IBusの場合)
  • fcitx5の場合は fcitx5-diagnose を実行して環境変数(GTK_IM_MODULEQT_IM_MODULEXMODIFIERS)が fcitx を指しているか
  • fcitx5の ~/.config/fcitx5/config の TriggerKeys がサブセクション形式で書かれているか(B-3)
  • fcitx5の ~/.config/fcitx5/profilekeyboard-*mozc両方が登録されているか(B-2)

Ansibleで自動化する

複数台に同じ設定を繰り返し入れる場合は、手元のAnsibleコレクション [ansible-miscs] に2つのroleと1つのplaybookを追加した。

追加したrole

roles/keyboard_swapcaps_gnome

CapsとCtrlの入れ替えをUbuntu desktop(GNOME 50 / Wayland)と仮想コンソールの両方に適用する。系統が2層あるため両方を面倒見るのが要点。

  • GUIセッション側: /etc/dconf/db/local.d/00-keyboard-swapcaps をテンプレートで配置し、dconf update でシステム全体のGNOMEデフォルトとして反映。ユーザは次回ログイン時から有効
  • コンソール側: /etc/default/keyboardXKBOPTIONSctrl:swapcaps を入れ、setupcon --force を発火

keyboard_swapcaps_xkb_optionctrl:nocapscaps:ctrl_modifier に切り替えれば挙動を変えられる。

gsettings set ... をユーザDBus越しに叩く方式は、SSH越しのAnsible実行ではセッションが取れないので意図的に避けた(dconfシステムoverrideなら無人で確実に効く)。

roles/fcitx5_mozc

fcitx5 + fcitx5-mozc 一式を入れて、~/.config/fcitx5/config をテンプレートで上書きし Control+space をトリガキーに固定する。im-config -n fcitx5 をユーザコンテキストで実行し、/etc/environmentGTK_IM_MODULE=fcitx などを書き込む。

既存IM環境との競合に対する安全弁

Ubuntu標準は伝統的にIBus + ibus-mozcで、ユーザがすでに辞書登録やキーマップカスタマイズをしている可能性が高い。雑にfcitx5に上書きすると ユーザのIBus側Mozcデータが孤児になる ため、role冒頭で以下を検出する。

  • im-config -m(現在の選択)
  • dpkg -l で既存IMフレームワークの一覧
  • pgrep -x ibus-daemon

別系統のIMが検出されたら assert失敗させる。明示的に -e fcitx5_mozc_force_switch=true を渡したときだけ進む。-e fcitx5_mozc_purge_ibus_mozc=true を併用するとibus側Mozcもpurgeされる(データ喪失を伴うので別フラグに分離)。

追加したplaybook

playbooks/conf/linux/ubu26_desktop.yml

1
2
3
4
5
6
7
8
9
- hosts: "{{ server | default('localhost') }}"
become: yes
vars:
fcitx5_mozc_user: "{{ lookup('env', 'SUDO_USER') | default(lookup('env', 'USER'), true) }}"
fcitx5_mozc_user_home: "/home/{{ fcitx5_mozc_user }}"
roles:
- register_home
- keyboard_swapcaps_gnome
- fcitx5_mozc

実行例:

1
2
3
4
$ cd ~/Sources/ansible-miscs
$ ansible-playbook -i hosts playbooks/conf/linux/ubu26_desktop.yml \
-e server=localhost \
-K

事前検出だけ走らせたい場合(実機を変更しない):

1
2
$ ansible-playbook -i hosts playbooks/conf/linux/ubu26_desktop.yml \
-e server=localhost --tags fcitx5_mozc_check -K

既存roleとの整理

Role 用途 採用すべきケース
keyboard_nocaps(既存) /usr/share/X11/xkb/symbols/{jp,us} を直接編集してCaps→Ctrl片方向 Raspberry Pi OSなどX11時代の構成。dist-upgradeで戻る点は注意
keyboard_swapcaps_gnome(新規) dconf override + /etc/default/keyboard でCaps↔︎Ctrl入れ替え Ubuntu 26.04などGNOME/Wayland desktop
japanese(既存) locale設定 + fcitx4 + fcitx-mozc + WSL用GTKスケール WSL上で日本語が要るケース
fcitx5_mozc(新規) fcitx5 + fcitx5-mozc + Ctrl+Spaceトリガ + 既存IM検出 Ubuntu 26.04 desktopのIME

ロールバック

うまく動かなかった場合や、元の構成に戻したい場合の手順。手で当てた設定とAnsibleで当てた設定で復旧の経路が違うので、それぞれ書く。

Caps↔︎Ctrl入れ替えを戻す

方法1(GNOME Tweaks)で当てた場合

GNOME Tweaks の Keyboard → Additional Layout Options → Ctrl positionDefault に戻す。

方法2(gsettings)で当てた場合

1
$ gsettings reset org.gnome.desktop.input-sources xkb-options

方法3(keyd)で当てた場合

1
2
$ sudo systemctl disable --now keyd
$ sudo rm /etc/keyd/default.conf # 設定ごと消す場合

サービスを残したまま個別マシンで一時無効化したいだけなら disable --now のみで十分。

Ansibleで当てた場合(keyboard_swapcaps_gnome role)

dconfシステムoverrideと /etc/default/keyboard の両方を戻す必要がある。

1
2
3
4
5
6
7
# GUIセッション側(dconfシステムoverride)
$ sudo rm /etc/dconf/db/local.d/00-keyboard-swapcaps
$ sudo dconf update

# コンソール側(/etc/default/keyboard)
$ sudo sed -i 's/^XKBOPTIONS=.*/XKBOPTIONS=""/' /etc/default/keyboard
$ sudo setupcon --force

各ユーザがログイン中の場合、GNOMEセッションには即時反映されない。一度ログアウト/ログインする。なお、ユーザ側で個別に gsettings set ... xkb-options "['ctrl:swapcaps']" を後から叩いている場合はそちらが優先されるので、gsettings reset も併せて実行する。

IME(Ctrl+Space切替)を戻す

IBus + Mozc を変更した場合

Mozcのプロパティ → キー設定 → 「カスタム」のエントリから、追加した Ctrl + Space の2エントリ(直接入力時:IMEを有効化/入力文字なし時:IMEを無効化)を削除する。デフォルトの「全角スペース挿入」を消していた場合は元に戻す。

設定後:

1
$ ibus-daemon -drx

fcitx5 を変更した場合

~/.config/fcitx5/config[Hotkey/TriggerKeys] を編集して元に戻すか、ファイル自体を消して再起動するとfcitx5デフォルト(Ctrl+Space)に戻る。

1
2
$ rm ~/.config/fcitx5/config
$ fcitx5 -r & # restart

IBusに完全に戻したい(fcitx5を入れた後)

1
2
$ im-config -n ibus
$ sudo systemctl reboot # 環境変数の再読込のため再ログイン or 再起動

Ansibleで当てた場合(fcitx5_mozc role)

/etc/environment への追記をブロックマーカーで囲んでいるので、マーカーごと削除する。

1
2
3
4
5
6
7
8
9
10
11
12
# /etc/environment に追記したIM環境変数を削除
$ sudo sed -i '/# BEGIN ANSIBLE MANAGED: fcitx5/,/# END ANSIBLE MANAGED: fcitx5/d' /etc/environment

# fcitx5パッケージを完全に外す場合
$ sudo apt purge fcitx5 fcitx5-mozc fcitx5-config-qt mozc-utils-gui
$ sudo apt autoremove

# IBusに戻す
$ im-config -n ibus

# 再ログイン or 再起動
$ systemctl reboot

fcitx5_mozc_purge_ibus_mozc=trueibus-mozc をpurgeしていた場合、ユーザの個人辞書(~/.config/mozc/ 以下)はパッケージ削除では消えていないので、再インストール後にそのまま使える。ただしibus-mozcとfcitx5-mozcで個人辞書のパスは共有なので、移行時にデータ重複や上書きが起きていないかは要確認。

まとめてロールバックしたい場合

Ansibleでまとめて当てた構成を一気に戻すワンライナー的な手順は用意していない(破壊的すぎるため)。上記の「Caps↔︎Ctrl」と「IME」を順に手で実行する。安全に戻したい場合は、playbook適用前に該当設定ファイルのバックアップを取っておくのが確実。

1
2
3
4
5
6
7
$ sudo tar czf ~/keyboard_backup_$(date +%F).tgz \
/etc/default/keyboard \
/etc/dconf/db/local.d/ \
/etc/environment \
~/.config/fcitx5/ \
~/.config/mozc/ \
~/.xinputrc 2>/dev/null

参考

共有

Headscale を自宅サーバまたは AWS EC2 で運用する

はじめに

Tailscale は WireGuard をベースとしたメッシュ型 VPN サービスで、複数のデバイスを安全に相互接続できます。 普段はマネージドサービスとして利用すれば十分ですが、

  • 制御サーバ(コーディネーションサーバ)を自分の管理下に置きたい
  • ベンダーロックインを避け、構成情報を自身で持ちたい
  • WireGuard と Tailscale の仕組みを学びたい

といった動機がある場合、Headscale を使ってセルフホスト構成を組むという選択肢があります。 本稿では、個人利用を想定して、Headscale を AWS EC2 単体 または 自宅 Linux サーバ で運用する手順を整理します。 あわせて、設定の自動化のための Terraform と Ansible の構成例も紹介します。

Headscale の概要

Headscale は Tailscale 制御サーバの OSS 互換実装です。 データプレーン(実際のトラフィック)は Tailscale 公式と同じく WireGuard で構成され、 クライアントは公式の Tailscale クライアント(macOS / Windows / Linux / iOS / Android)をそのまま利用します。 Headscale が代替するのは、ノード登録、鍵管理、ACL 配布、DNS、DERP リレーの調整といった「制御プレーン」の部分のみです。

Headscale 制御プレーンとデータプレーン

公式によれば「単一 tailnet を対象とした、個人や小規模 OSS 組織向けの実装」とされています 1。 本稿の執筆時点における最新版は v0.28.0(2025-02-04 リリース)です 2

構成パターンの選択

ホストする場所は、大きく次の 2 通りがあります。

構成 長所 短所
AWS EC2 単体 公衆 IP・DNS・帯域が安定。ポート開放を気にしなくてよい。 月額のランニングコストが発生する。
自宅 Linux サーバ 既存サーバを活用できる。電気代以外の月額コストはほぼゼロ。 グローバル IP の確保や、ISP の制約(CGNAT 等)に応じた工夫が必要。

リバースプロキシは Caddy を推奨します。Tailscale プロトコルは WebSocket POST を必要とするため、 Cloudflare(および Cloudflare Tunnel)は使えない 点に注意してください。 公式のリバースプロキシリファレンス 3 でも明記されています。

事前準備(AWS アカウントとローカル環境)

実際に試す前に整えておくと、以降の手順がスムーズになります。 AWS で構築する場合と、自宅サーバ構成のどちらでも共通する項目を先に列挙します。

AWS を使う場合

1. AWS アカウントと IAM ユーザー

ルートアカウントは使わず、Terraform 用の IAM ユーザーを作成します。

  1. AWS マネジメントコンソール → IAM → 「ユーザーの作成」
  2. 必要な権限ポリシー(個人利用なら以下のマネージドポリシーで十分):
    • AmazonEC2FullAccess(VPC・EIP も含む)
    • AmazonRoute53FullAccess(Route 53 を使う場合のみ)
  3. 作成後、対象ユーザー → 「セキュリティ認証情報」 → 「アクセスキーを作成」 → 用途「コマンドラインインターフェイス(CLI)」
  4. アクセスキー ID とシークレットアクセスキーを控えておきます(一度しか表示されない

2. AWS CLI のプロファイル設定

ローカル PC(WSL2 や Linux)に AWS CLI をインストールして、プロファイルを設定します。

1
2
3
4
5
6
7
sudo apt install -y awscli   # 未インストールなら

aws configure --profile headscale
# AWS Access Key ID: <控えたアクセスキー>
# AWS Secret Access Key: <控えたシークレット>
# Default region name: ap-northeast-1
# Default output format: json

以降のコマンドではプロファイルを環境変数で固定すると楽です。

1
2
3
4
5
export AWS_PROFILE=headscale
export AWS_REGION=ap-northeast-1

# 認証確認
aws sts get-caller-identity

3. SSH 鍵と EC2 キーペア

EC2 にログインするための鍵です(IAM のアクセスキーとは別物)。

1
2
3
4
5
6
7
# ローカルの SSH 鍵が無ければ生成
[ -f ~/.ssh/id_ed25519.pub ] || ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""

# AWS にキーペアを import
aws ec2 import-key-pair \
--key-name headscale-key \
--public-key-material fileb://~/.ssh/id_ed25519.pub

ここで指定した --key-name の値(例: headscale-key)を、後で Terraform の key_name 変数に渡します。両者の名前が一致していないと EC2 起動時に InvalidKeyPair.NotFound で失敗するので注意してください。

4. 利用可能な AZ の確認

新規 AWS アカウントには 特定の AZ(例: ap-northeast-1a)が割り当てられないことがあります。 事前に利用可能な AZ を確認してください。

1
2
3
aws ec2 describe-availability-zones \
--query "AvailabilityZones[?State=='available'].[ZoneName,ZoneId]" \
--output table

返ってきた中から 1 つを Terraform の availability_zone に指定します。 割り当てられていない AZ を指定すると、サブネット作成時に unexpected state 'unavailable' エラーが出ます。

5. ドメイン

hs.example.com のように、Headscale サーバを公開するドメイン(あるいはサブドメイン)が必要です。 お名前.com、Cloudflare、Route 53 など好みの DNS で構いません(後述の「DNS レコードの設定」で具体例を示します)。

自宅サーバを使う場合

  • Ubuntu 24.04 LTS(ARM64 / AMD64 どちらでも)が動作するマシン
  • ローカルから SSH 接続できる状態
  • 以降の DNS / グローバル IP 関連は「案B: 自宅 Linux サーバでの構成」で扱います

ローカル PC のツール

ツール 用途 備考
Terraform >= 1.6 AWS リソース構築 自宅サーバ構成の場合は不要
Ansible >= 2.16(ansible-core) サーバへのソフトウェアインストール 後述の通り apt 版は古い場合があるので注意
AWS CLI v2 AWS との対話 AWS 構成の場合のみ
ssh / dig / curl 動作確認 通常入っている

想定コスト(AWS 構成、東京リージョン)

項目 月額目安
EC2 t4g.micro(24h 稼働) $7.78
EBS gp3 16 GiB $1.54
Public IPv4(EIP)※ $3.60
合計 約 $13 / 月(≒ ¥2,000)

※ 2024 年 2 月以降、AWS は接続中・未接続を問わずすべての Public IPv4 アドレスに対して $0.005/h の課金を行います。 試用後はすみやかに terraform destroy で削除すれば、それ以降の課金は止まります。

案A: AWS EC2 単体構成

先に前提条件が単純な EC2 構成から扱います。 本稿では Ubuntu 24.04 LTS(ARM64、t4g.small)を 1 台立ち上げ、Caddy で TLS 終端し、Headscale 本体はバックエンドに置く構成とします。

1. インスタンスの準備

  • インスタンスタイプ: t4g.micro(2 vCPU / 1 GiB、ARM64)で個人利用には十分(クライアント数が増える / ACL を凝るなら t4g.small 推奨)
  • AMI: 最新の Ubuntu 24.04(Canonical 公式)
  • ストレージ: gp3 16 GiB(暗号化)
  • パブリック IP: Elastic IP を付与(再起動でも IP を維持するため)
  • AZ と キーペアは「事前準備」で確認した値を使用

セキュリティグループの受信ルールは次の通りです。

  • 22/tcp: 管理用、自宅 IP の /32 のみ許可
  • 80/tcp443/tcp: Caddy(自動 TLS 取得と HTTPS 公開)
  • 3478/udp: 組み込み DERP を使う場合のみ。本稿の構成では Tailscale 公式 DERP を利用するので 不要

EIP を確保したら、後述の「DNS レコードの設定」に従って、利用するドメイン(例: hs.example.com)の A レコードを EIP に向けます。

2. Headscale のインストール

DEB パッケージでのインストールが公式推奨です 4HEADSCALE_VERSION は最新リリースに合わせて更新してください。

1
2
3
4
5
6
HEADSCALE_VERSION="0.28.0"
HEADSCALE_ARCH="arm64" # x86_64 の場合は amd64

wget --output-document=headscale.deb \
"https://github.com/juanfont/headscale/releases/download/v${HEADSCALE_VERSION}/headscale_${HEADSCALE_VERSION}_linux_${HEADSCALE_ARCH}.deb"
sudo apt install ./headscale.deb

DEB パッケージなら、headscale ユーザー、systemd サービス、/etc/headscale/ 以下のディレクトリ、/var/lib/headscale/ のデータ領域などが一式整備されます。

3. 設定ファイル

/etc/headscale/config.yaml を編集します。最小構成は次のようなものです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
server_url: https://hs.example.com
listen_addr: 127.0.0.1:8080 # Caddy 経由なのでローカル限定
metrics_listen_addr: 127.0.0.1:9090
grpc_listen_addr: 127.0.0.1:50443
grpc_allow_insecure: false

tls_cert_path: "" # TLS は Caddy で終端
tls_key_path: ""

noise:
private_key_path: /var/lib/headscale/noise_private.key

prefixes:
v4: 100.64.0.0/10
v6: fd7a:115c:a1e0::/48
allocation: sequential

derp:
server:
enabled: false
urls:
- https://controlplane.tailscale.com/derpmap/default

database:
type: sqlite
sqlite:
path: /var/lib/headscale/db.sqlite
write_ahead_log: true

dns:
magic_dns: true
base_domain: hs-net.example.com # server_url のドメインとは別にする
nameservers:
global:
- 1.1.1.1
- 9.9.9.9

policy:
mode: file
path: /etc/headscale/acl.hujson

unix_socket: /var/run/headscale/headscale.sock
unix_socket_permission: "0770"

要点は次の通りです。

  • server_url はクライアントが接続する URL。後述の Caddy が公開するドメインに合わせます。
  • tls_cert_path / tls_key_path を空にして、TLS 終端は Caddy に任せます。
  • dns.base_domainserver_url のドメインと 別の ドメインを指定する必要があります(重複していると起動に失敗します)。
  • 個人利用ではデータベースは SQLite で十分です。Postgres はレガシー扱いとされています 5
  • 設定の検証は sudo headscale configtest で行えます。

4. Caddy で自動 HTTPS

Caddy は自動 HTTPS と WebSocket 対応をデフォルトで備えており、Headscale との相性が良いです。

1
2
3
4
5
6
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -fsSL https://dl.cloudsmith.io/public/caddy/stable/gpg.key \
| sudo tee /usr/share/keyrings/caddy-stable.asc > /dev/null
echo "deb [signed-by=/usr/share/keyrings/caddy-stable.asc] https://dl.cloudsmith.io/public/caddy/stable/deb/debian any-version main" \
| sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update && sudo apt install -y caddy

/etc/caddy/Caddyfile を以下のように書き換えます。

1
2
3
4
5
6
7
{
email you@example.com
}

hs.example.com {
reverse_proxy 127.0.0.1:8080
}

設定を反映します。

1
2
sudo systemctl reload caddy
sudo systemctl enable --now headscale

https://hs.example.com/health にアクセスして pass が返ってくれば疎通できています。

案B: 自宅 Linux サーバでの構成

自宅サーバで運用する場合、最大の論点は インターネットからの到達性 です。 ISP の契約によって状況が異なるため、まずは前提を整理します。

1. グローバル IP まわりの整理

確認すべき項目は次の 3 点です。

  1. 公衆 IPv4 アドレスを持っているか
    • 固定 IP か、動的 IP か
    • ルータの WAN 側 IP と、curl ifconfig.me で取得できる IP が一致していれば公衆 IP を直接持っています
    • 一致しない場合は ISP 側で NAT されており、おそらく CGNAT 環境です
  2. ポート 80 / 443 を外向けに開けられるか
    • ルータでポートフォワードができるか
    • ISP が 80 / 443 をブロックしていないか
  3. IPv6 が利用できるか
    • 利用できる場合でも、接続するクライアント側で必ず IPv6 が使えるとは限らないため、IPv6 単独は実用上の冗長系として捉えるのが無難です

これらの結果に応じて、以下のパターンに分かれます。

パターンA: 公衆 IP + ポート開放可

最も素直な構成です。

  • 動的 IP の場合は DDNS で名前を固定します。 Cloudflare の DNS(普通の DNS のみ。Cloudflare Tunnel ではない)を使う場合、API トークンと簡単なスクリプト(ddclient や自前の cron スクリプト)でレコードを更新できます。
  • 自宅ルータで 80/tcp443/tcp をサーバへフォワードします。
  • サーバ側のセットアップは前述の AWS EC2 構成と同じです。Caddy が Let's Encrypt から自動で証明書を取得します。

パターンB: CGNAT / ポート開放不可

外側からの着信が物理的に通せないため、外部に「踏み台」が必要になります。

  • 解1: 安価な VPS に Headscale を直接置く 実質的に AWS EC2 と同じ構成になります。Hetzner や Vultr、Oracle Cloud の Always Free 枠などが選択肢です。
  • 解2: VPS をリバースプロキシにし、自宅サーバへ WireGuard 等で逆トンネル Headscale 本体は自宅サーバに置きつつ、外部に対する HTTPS エンドポイントは VPS が担う構成です。 自宅サーバから VPS に向けて WireGuard を張り、VPS の Caddy が自宅側へ reverse_proxy します。 自宅サーバの計算資源を活用したい場合に有用ですが、構成要素が増えるため 解1 のほうがおすすめです。
CGNAT 配下の自宅サーバを VPS 経由で公開する構成

Cloudflare Tunnel が使えない理由(補足)

外部公開の手段として人気のある Cloudflare Tunnel ですが、Headscale では使えません。 公式リバースプロキシリファレンス 6 にも明記されている通り、Tailscale プロトコルは WebSocket の POST を必要とし、これを Cloudflare はサポートしていないためです。 Cloudflare 経由の HTTPS 化には魅力がありますが、Headscale に関しては別の方法を検討してください。

2. ソフトウェアのセットアップ

ここから先(Headscale + Caddy のインストール、config.yamlCaddyfile の内容)は AWS EC2 構成と共通です。

DNS レコードの設定

Headscale サーバには、server_url で指定したドメイン(例: hs.example.com)の A レコード を、サーバの公開 IP に向ける設定が必須です。 EC2 構成の場合は Elastic IP、自宅サーバ構成の場合は自宅ルータの公衆 IP(または踏み台 VPS の IP)が対象になります。 ドメインを管理している DNS 提供元ごとに、設定の入り口が異なります。

お名前.com で運用する場合

お名前.com には紛らわしい点があり、初期状態ではドメインのネームサーバが「お名前.com DNS(実際にレコード管理ができるサービス)」に向いていない ことが多いです。 ドメイン購入直後は dns1.onamae.com / dns2.onamae.com(パーキング用 NS)が設定されており、A レコードを追加しようとしても画面が出てきません。

切り替えの最短手順は次の通りです。

1. 「DNS レコード設定を利用する」を選んでネームサーバごと切替

  1. お名前.com Navi にログイン
  2. 上部メニューの「ドメイン」 → 対象ドメインの行で「DNS」または「ドメインの DNS 関連機能の設定」をクリック
  3. 表示された選択肢から 「DNS レコード設定を利用する」 → 「設定する」
    • この操作で、ネームサーバが自動的に 01.dnsv.jp04.dnsv.jp に切り替わります
  4. レコード追加フォームで以下を設定して「追加」:
    • ホスト名: hs(フルで hs.example.com の場合)
    • TYPE: A
    • TTL: 3600(初期検証中は 300 でも可)
    • VALUE: サーバの公開 IP(EIP など)
    • 状態: 有効
  5. 画面下の「確認画面へ進む」 → 「設定する」で確定

2. NS 切替の反映を確認

ネームサーバの変更は反映に時間がかかります(最長 24 時間、通常は数分〜1 時間)。

1
2
3
4
5
6
7
8
9
# 権威 NS が切り替わったか
dig +short NS example.com
# 期待値: 01.dnsv.jp. 〜 04.dnsv.jp.

# A レコードが返るか(権威 DNS に直接問い合わせ)
dig +short hs.example.com @01.dnsv.jp

# 通常解決でも見えるか
dig +short hs.example.com

NS が dns1.onamae.com のままだと、A レコードを設定しても応答に反映されない、あるいは パーキング用の IP(150.95.x.x 等)が返ってきてしまう ので、まず NS の切替を完了させてください。

動的 IP の自宅サーバの場合(補足)

お名前.com DNS は API 経由の自動更新(DDNS)に対応していません。 公衆 IP が動的に変わる環境では、ドメインはお名前.com で管理したまま、ネームサーバを Cloudflare DNS(無料プラン)に変更 する構成がよく使われます。 Cloudflare の API トークンと ddclient などのスクリプトがあれば、IP 変更時に A レコードを自動更新できます。 本稿で除外している「Cloudflare Tunnel」は WebSocket 制約により使えませんが、DNS としての Cloudflare 利用は問題ありません。

Route 53 で運用する場合

DNS を AWS Route 53 でホスティングしているなら、Terraform で A レコードまで一括管理できます。 本稿の Terraform に次のリソースを追加するだけです。

1
2
3
4
5
6
7
8
9
10
11
data "aws_route53_zone" "this" {
name = "example.com."
}

resource "aws_route53_record" "headscale" {
zone_id = data.aws_route53_zone.this.zone_id
name = "hs.example.com"
type = "A"
ttl = 300
records = [aws_eip.headscale.public_ip]
}

クライアントの接続

クライアントを Tailnet に参加させる手順は、大きく次の流れになります。

  1. サーバ側でユーザーと(必要なら)事前認証鍵を発行する
  2. クライアント側で公式 Tailscale を起動し、--login-server で Headscale を指定する
  3. 必要に応じてサーバ側でノードを承認する

サーバ側: ユーザーと事前認証鍵の発行

v0.28.0 から preauthkeys コマンドはユーザー名ではなく ユーザー ID を引数に取る仕様に変わっているため、先に users list で ID を確認します。

1
2
3
4
5
6
sudo headscale users create alice
sudo headscale users list
# 表示された ID(例: 1)を控える

sudo headscale preauthkeys create --user 1 --reusable --expiration 24h
# 出力された tskey-auth-xxxxxxxxxxxxxxxxxxxxx を控える

preauthkeys create の主なフラグは次の通りです。

  • --reusable: 同じ鍵を複数台に使い回す(IaC との併用で便利)
  • --ephemeral: 切断時にノード登録を自動削除(CI ランナーや一時的なサーバ向け)
  • --expiration <duration>: 有効期限(例: 24h30d

方法 A: 事前認証鍵で自動登録(推奨)

クライアント側で --login-server--authkey を渡すだけで完了します。スクリプトや cloud-init から無人で投入できるため、複数台を一気に追加する場合や、サーバ系のノードを登録する場面に向いています。

1
2
3
4
# Linux クライアント
sudo tailscale up \
--login-server https://hs.example.com \
--authkey tskey-auth-xxxxxxxxxxxxxxxxxxxxx

実行後、サーバ側で sudo headscale nodes list を打つと、登録済みノードとして表示されます。

方法 B: インタラクティブ登録(事前認証鍵を使わない)

--authkey を渡さずに tailscale up を実行すると、クライアント側に登録用 URL が表示されます。Headscale ではその URL を踏むだけでは登録が完了せず、URL に含まれる ノードキー(nodekey:...)をサーバ側で承認 する流れになります。

1
2
3
4
5
# クライアント側
sudo tailscale up --login-server https://hs.example.com
# 出力例:
# To authenticate, visit:
# https://hs.example.com/register/nodekey:abcdef0123...

URL の末尾にあるノードキーをサーバ側に渡して承認します。

1
2
3
4
5
# サーバ側(Headscale)
sudo headscale users list # 対象ユーザー ID を確認
sudo headscale nodes register \
--user 1 \
--key nodekey:abcdef0123...

事前認証鍵の発行・配布が不要な代わりに、サーバ側で 1 台ずつ手動承認する手間が増えます。少数のノードを慎重に管理したいケースや、認証鍵をクライアント側に置きたくない運用ポリシーで有効です。

公式アプリ(macOS / iOS / Windows / Android)

GUI クライアントでも Headscale に接続できます。共通する流れは次の通りです 7

  1. アプリの設定で「カスタムコーディネーションサーバ(Custom coordination server / Alternate server URL)」に https://hs.example.com を指定
  2. ログイン操作を行うと、ブラウザで Headscale の登録ページが開く
  3. 表示されたコマンド(headscale nodes register --user <id> --key <nodekey>)をサーバ側で実行して承認

事前認証鍵を使わせたい場合は、各アプリの「authkey でサインイン」相当のメニューに鍵を貼り付けます。 UI の文言や設定階層は OS とアプリ版によって変わりやすいため、本稿では公式ドキュメントへのリンクに留めます。

起動時に指定できる代表的なフラグ

tailscale up には接続時に指定できる便利なフラグがあります。よく使うものを用途別にまとめます。

フラグ 用途
--hostname=<name> Tailnet 上での表示名・MagicDNS 名を上書き
--reset 過去のフラグを破棄して指定したフラグだけで再構成
--ssh Tailscale SSH を有効化(ACL で ssh ルール定義が必要)
--accept-routes 他ノードが広告したサブネット経路を取り込む
--accept-dns=false MagicDNS を使わず既存の DNS 設定を保つ
--advertise-routes=<cidr> 自ノードをサブネットルータとして広告(要 ip_forward
--advertise-exit-node Exit Node として広告
--exit-node=<peer> 通信を peer 経由でインターネットに出す

サブネットルータや Exit Node として広告する場合は、サーバ側でも経路の承認が必要です(headscale nodes list-routes で一覧、headscale nodes approve-routes で承認)。 ACL や経路まわりの細かい挙動は公式リファレンス 8 に委ね、本稿では「クライアントを Tailnet に参加させる」ところまでをカバーします。

接続後の動作確認(クライアント側)

Headscale 構成でも、クライアント側のサブコマンド体系は公式 Tailscale と同一です 9。 接続が完了したら、まず以下の順で状態を確認します。

1. ノードの状態とピア一覧

1
2
3
tailscale ip          # 自ノードの Tailnet IP(既定では 100.64.0.0/10 から払い出し)
tailscale status # ピア一覧と各ノードの状態(idle / active / offline 等)
tailscale version

tailscale status の各行末に idleoffline が並んだ状態のままになる場合、クライアント自身がコーディネーションサーバへ到達できていない可能性が高いため、次の netcheck とログで切り分けます。

2. 接続性とリレー判定

1
2
tailscale netcheck            # NAT 種別と各 DERP リレーまでの遅延を計測
tailscale ping <peer> # 特定ピアまでの経路を確認(DERP 経由 / 直接 P2P を判別)

tailscale ping は ICMP ではなく Tailscale プロトコル上での到達性を測るため、経路途中で ICMP がブロックされていても結果が得られます。 出力に via DERP と表示されればリレー経由、via direct であれば P2P で接続できています。

3. デーモンの状態とログ

Linux クライアントでは tailscaled の状態と journald のログから原因を絞り込めます。

1
2
systemctl status tailscaled
sudo journalctl -u tailscaled -n 100 --no-pager

Unable to connect to the Tailscale coordination server のような出力がある場合は、

  • server_url(例: hs.example.com)の DNS が公開 IP を指しているか
  • Caddy が稼働しており https://hs.example.com/healthpass を返すか
  • クライアントの --login-serverserver_url と完全一致しているか(末尾スラッシュやスキームの差にも注意)

の順で見直すとスムーズです。

4. 再ログインと切断

ログインサーバを変更したり、状態をリセットしたい場合は次のコマンドを使います。

1
2
3
sudo tailscale up --login-server https://hs.example.com --reset
sudo tailscale down # トンネルだけ切断(設定は維持)
sudo tailscale logout # ノード登録を破棄

--reset を付けると過去に渡したフラグを引き継がず、指定したフラグのみで再構成できるため、設定変更時の事故を避けられます。

複数ノード間で SSH するまで

ここまでで 1 台のクライアントを Tailnet に参加させる手順を整理しました。 実用上は 複数のノード(ノート PC、サーバ、自宅マシンなど)を相互につなぎ、Tailnet 経由で SSH や各種サービスへ到達できる ところまでを確認したいはずです。 本節では、2 台のクライアント(仮に client-aclient-b と呼びます)を登録した直後から、SSH 接続が通るまでの流れを順に追います。

1. ノードがサーバに登録されているかを確認

サーバ側で headscale nodes list を打ち、両ノードが並んで表示されることを確認します。

1
sudo headscale nodes list
列の見方 意味
ID Headscale 内部のノード ID
Hostname クライアント側の OS ホスト名(変更したい場合は tailscale up --hostname で上書き可能)
IP addresses 払い出された Tailnet IP(既定では 100.64.0.0/10 内)
Online コーディネーションサーバとの接続状態
Expired ノードキーの有効期限切れ

Online: true で両方が並べば、登録は完了です。クライアント側でも同様に状態を確認します。

1
2
3
# client-a で
tailscale status
# 自ノードの行に続いて、ピアとして client-b が表示される想定

2. ピア間の疎通確認

Tailscale プロトコル経由で相手ノードに到達できるかを tailscale ping で確認します。 このコマンドは ICMP ではなく Tailscale 内部の到達性を測るため、経路上で ICMP がブロックされていても結果が出ます。

1
2
3
4
5
# client-a から client-b へ
tailscale ping client-b

# IP 指定でも可
tailscale ping 100.64.0.x

出力に注目するのは経路の種別です。

  • pong from client-b ... via DERP(tok) in 12ms → DERP リレー経由(NAT 越えに失敗した場合の自動フォールバック)
  • pong from client-b ... via 198.51.100.20:41641 in 5ms → 直接 P2P 接続

最初は DERP 経由でも、しばらくすると P2P に切り替わることがあります。 NAT が厳しい環境では DERP のままになることもありますが、通信は成立します。

通常の ping も合わせて確認しておくと、ICMP まで通るかを把握できます。

1
ping -c 3 100.64.0.x

3. MagicDNS による名前解決

config.yamldns.magic_dns: true にしている場合、<hostname>.<base_domain> 形式でノード名を引けます。 たとえば base_domainhs-net.example.com に設定していれば、client-b.hs-net.example.comclient-b の Tailnet IP に解決されます。

1
2
3
4
5
6
7
# 名前解決を確認
tailscale status # 各ノードの完全名(FQDN)を表示
ping -c 1 client-b.hs-net.example.com

# どうしても解決できない場合の切り分け
tailscale debug prefs | grep -i corpdns # MagicDNS が有効か
resolvectl status # systemd-resolved 環境

tailscale up 時に --accept-dns=false を付けていると MagicDNS は無効になります。 その場合は IP 直打ち、または OS の /etc/hosts などで明示的に名前解決の経路を作る必要があります。

4. 通常の SSH で接続する

ここまで来れば、Tailnet 内であれば通常の OpenSSH で接続できます。 クライアント側に tailscaled が動いていて IP が振られていれば、SSH デーモン側は特別な設定なしで Tailnet からの接続を受け付けます。

1
2
3
4
5
# Tailnet IP で接続
ssh user@100.64.0.x

# MagicDNS 名で接続(推奨。IP が変わっても影響しない)
ssh user@client-b.hs-net.example.com

接続できない場合のチェック順は次の通りです。

  1. ピア側で sshd が稼働しているか(systemctl status ssh
  2. ピア側のファイアウォール(ufw status など)が tailscale0 インターフェイスからの 22/tcp を許可しているか
  3. ACL(/etc/headscale/acl.hujson)で dst 側の 22/tcp が許可されているか
  4. Tailnet IP / MagicDNS 名のどちらでも tailscale ping で疎通できているか

ACL を初期状態(全許可)から絞り込んだ場合、SSH のために次のような最小ルールを残しておくと運用しやすいです。

1
2
3
4
5
6
7
8
9
{
"acls": [
{
"action": "accept",
"src": ["alice"],
"dst": ["alice:22"]
}
]
}

alice の部分は、Headscale 上で users create したユーザー名に置き換えます。 ユーザー単位で許可することで、後から別ユーザーを追加しても影響範囲を分離できます。

5. (任意)Tailscale SSH を有効化する

各ノードに OpenSSH を立てて鍵を配るのが面倒な場合、tailscaled 経由で SSH を提供する Tailscale SSH が便利です 10。 鍵管理が不要になり、ACL でアクセス可否を一元的に制御できます。

クライアント側で SSH サーバ機能を有効化します。

1
2
3
4
sudo tailscale up \
--login-server https://hs.example.com \
--ssh \
--reset

ACL には ssh ルールを追加します。

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"acls": [
{ "action": "accept", "src": ["*"], "dst": ["*:*"] }
],
"ssh": [
{
"action": "accept",
"src": ["alice"],
"dst": ["alice"],
"users": ["autogroup:nonroot"]
}
]
}

利用側からは通常の ssh コマンドで接続できます。

1
2
ssh alice@client-b.hs-net.example.com
# OpenSSH の鍵ではなく、Tailscale ACL で認可される

autogroup:nonroot は root 以外のすべてのユーザーを意味します。 特定ユーザーだけに絞りたい場合は ["alice", "bob"] のように列挙します。 ポリシー編集後は sudo headscale policy check --file /etc/headscale/acl.hujson で構文を確認してから反映してください。

構築の自動化(Terraform / Ansible)

ここまでの手順を自動化するための Terraform と Ansible の最小構成を用意しています。 記事と対応するソースは GitHub の dobachi/headscale-iac-sample リポジトリに置いてあるので、git clone してそのまま試せます。

Terraform: AWS 側のリソース構築

新規 VPC、パブリックサブネット、セキュリティグループ、Ubuntu 24.04 ARM64 の EC2、Elastic IP を一括で作成します。

1
2
3
4
5
cd iac/terraform
cp terraform.tfvars.example terraform.tfvars
# key_name と allowed_ssh_cidr を編集
terraform init
terraform apply

主な変数(variables.tf)は次の通りです。

  • region / availability_zone: デフォルトは東京リージョン
  • vpc_cidr / public_subnet_cidr: VPC とサブネットの CIDR
  • instance_type: 既定 t4g.small(個人利用なら t4g.micro でも十分。コストを優先したいときに切り替え)
  • key_name: 事前に作成済みの EC2 キーペア名
  • allowed_ssh_cidr: 自宅の /32 を指定
  • enable_stun: 組み込み DERP を使う場合に true

apply 後、terraform output public_ip で Elastic IP を確認し、DNS の A レコード(例: hs.example.com)をその IP へ向けます。

Ansible: Headscale + Caddy のセットアップ

EC2 でも自宅サーバでも同じ Playbook が使えます。Ubuntu 24.04 を前提とし、

  • Headscale の DEB をダウンロード・インストール
  • /etc/headscale/config.yaml をテンプレートから配置
  • 初期 ACL ファイル(全許可、後で絞り込み)を配置
  • headscale configtest で構文検証
  • Caddy をインストールし、Caddyfile を配置
  • 初期ユーザーを作成

までを行います。

Ansible のインストール

Ubuntu の apt で入る ansible 2.10 系は古く、Python 3.12 が動くターゲット(Ubuntu 24.04)では No module named 'ansible.module_utils.six.moves' のような互換性エラーが出ます。 pipx で最新の ansible-core を入れる のが確実です。

1
2
3
4
5
6
7
8
9
sudo apt remove --purge -y ansible ansible-core 2>/dev/null || true
sudo apt install -y pipx python3-venv
pipx ensurepath
source ~/.bashrc

pipx install --include-deps ansible

ansible --version
# ansible [core 2.16.x] 以上 が表示されることを確認

実行

1
2
3
4
5
6
7
8
9
cd iac/ansible
cp inventory.example.ini inventory.ini
cp group_vars/all.yml.example group_vars/all.yml
# inventory.ini と group_vars/all.yml を編集

# 接続テスト(pong が返ればOK)
ansible -i inventory.ini headscale -m ping

ansible-playbook -i inventory.ini playbook.yml

group_vars/all.yml で設定する主な変数は次の通りです。

  • headscale_server_url: クライアントが接続する URL(例: https://hs.example.com
  • headscale_base_domain: MagicDNS のベースドメイン(server_url のドメインとは別にする)
  • caddy_admin_email: Let's Encrypt の連絡先
  • headscale_users: 初期作成するユーザー名のリスト
  • headscale_arch: arm64(AWS t4g.* や Raspberry Pi)または amd64

運用

ACL ポリシー

policy.mode: file の場合、/etc/headscale/acl.hujson を編集することでアクセス制御を行います。 最小構成として「同一ユーザーのデバイス間のみ通信可」とする例です。

1
2
3
4
5
{
"acls": [
{ "action": "accept", "src": ["alice"], "dst": ["alice:*"] }
]
}

ACL 構文は Tailscale の ACL とほぼ互換で、グループ・タグ・ユーザー単位で細かく制御できます 11。 編集後は sudo headscale policy check --file /etc/headscale/acl.hujson で検証してから、サービスを再読み込みします。

バックアップ

最低限バックアップすべき対象は次の 3 つです。

  • /var/lib/headscale/db.sqlite: ノード・ユーザー・鍵などの実体
  • /var/lib/headscale/noise_private.key: ノイズプロトコルの秘密鍵(紛失すると全クライアントの再登録が必要
  • /etc/headscale/: 設定一式と ACL

cron で日次に固める例です。

1
2
sudo tar czf /var/backups/headscale-$(date +%F).tgz \
/etc/headscale /var/lib/headscale

S3 や別ホストへ rsync する仕組みと併用するとより安全です。

アップデート

DEB パッケージを上書きインストールするだけで完了します。

1
2
3
4
sudo systemctl stop headscale
sudo apt install ./headscale_<NEW_VERSION>_linux_arm64.deb
sudo headscale configtest
sudo systemctl start headscale

マイナーバージョンを跨ぐ場合は、必ず CHANGELOG を確認してください。 v0.28.0 のように、PreAuthKey の保存形式変更(bcrypt 化)など破壊的変更が入ることがあります 12

ログとトラブルシュート

サーバ側のログは journald で確認します。

1
2
sudo journalctl -u headscale -f
sudo journalctl -u caddy -f

つながらないときの典型的なチェックリストは次の通りです。

  • DNS が EIP / 自宅の IP を正しく指しているか
  • セキュリティグループ(あるいはルータ)で 443/tcp が開いているか
  • Caddy が証明書を取得できているか(80/tcp が空いているかどうかが ACME 取得に効きます)
  • headscale nodes list でノードが登録されているか
  • クライアント側の tailscale status でコントロールプレーンへの接続状況を確認

つまずきポイント集

実際に手順をなぞる過程で発生しやすいエラーをまとめておきます。

Terraform: unexpected state 'unavailable'(サブネット作成)

1
2
Error: waiting for EC2 Subnet (subnet-xxxx) create:
unexpected state 'unavailable', wanted target 'available'.

原因: terraform.tfvarsavailability_zone が、AWS アカウントに割り当てられていない AZ を指している。 新規 AWS アカウントは ap-northeast-1a などが使えないことがあります。

対応: 「事前準備」の AZ 確認コマンドで使える AZ に書き換えて terraform apply。 すでに失敗したサブネットが残っている場合は terraform state rm aws_subnet.public で状態をクリアしてから再実行します。

Terraform: InvalidKeyPair.NotFound

1
Error: ... api error InvalidKeyPair.NotFound: The key pair 'xxx' does not exist

原因: key_name の値が AWS に登録済みのキーペア名と一致していない。

対応: aws ec2 describe-key-pairs --query "KeyPairs[].KeyName" で確認し、terraform.tfvarskey_name を実在する名前に修正。

DNS: パーキング用 IP(150.95.x.x)が返る

原因: お名前.com の場合、NS が dns1/dns2.onamae.com(パーキング用)のままになっている。

対応: 上述の「お名前.com で運用する場合」の手順で、NS を 01.dnsv.jp04.dnsv.jp に切り替え、A レコードを再設定。

Ansible: No module named 'ansible.module_utils.six.moves'

原因: ローカル Ansible のバージョンが古く(2.10 系等)、ターゲット側の Python 3.12 と互換性がない。

対応: 上述の「Ansible のインストール」に従って pipx で最新版を入れ替え。

Ansible: headscale configtestacl.hujson 不在で失敗

原因: 設定で policy.mode: file を有効にしているが、ACL ファイル本体を配置していない。

対応: 本稿の Ansible ロールには ACL テンプレート(templates/acl.hujson.j2)を含めてあるので、ロールを最新化してから再実行してください。手動セットアップの場合は次のようなファイルを /etc/headscale/acl.hujson に置きます。

1
2
3
4
5
{
"acls": [
{ "action": "accept", "src": ["*"], "dst": ["*:*"] }
]
}

v0.28.0 以降: preauthkeys create -u <ユーザー名> が失敗

1
2
Error: invalid argument "alice" for "-u, --user" flag:
strconv.ParseUint: parsing "alice": invalid syntax

原因: v0.28.0 で preauthkeys コマンドの --user がユーザー名から ユーザー ID 指定 に変わった。

対応: headscale users list で ID を確認してから渡す。

1
2
sudo headscale users list           # ID を確認
sudo headscale preauthkeys create --user 1 --reusable --expiration 24h

おわりに

本稿では、個人利用を想定して Headscale を AWS EC2 と自宅 Linux サーバの 2 通りで運用するための具体的な手順をまとめ、Terraform と Ansible による自動化の足場も用意しました。 EC2 構成は前提が単純で t4g.small でも快適に動きます。 自宅サーバ構成は ISP 環境次第で構成が分かれますが、CGNAT 配下でも安価な VPS を踏み台として使えば現実的に運用できます。 セルフホスト Tailscale を起点に、自宅とクラウド、外出先の端末をひとつの仮想ネットワークでつなぐ運用は、個人の学習用途としても実用上もよい題材だと感じます。

参考


  1. Headscale 公式ドキュメント, Headscale↩︎

  2. Headscale v0.28.0 リリースノート, https://github.com/juanfont/headscale/releases↩︎

  3. 公式リバースプロキシリファレンス, https://headscale.net/stable/ref/integration/reverse-proxy/↩︎

  4. 公式インストールガイド, https://headscale.net/stable/setup/install/official/↩︎

  5. 公式設定リファレンス, https://headscale.net/stable/ref/configuration/↩︎

  6. 公式リバースプロキシリファレンス, https://headscale.net/stable/ref/integration/reverse-proxy/↩︎

  7. クライアント接続ガイド, https://headscale.net/stable/usage/↩︎

  8. ACL 構文の解説, https://tailscale.com/kb/1018/acls↩︎

  9. Tailscale CLI リファレンス, https://tailscale.com/kb/1080/cli↩︎

  10. ACL 構文の解説, https://tailscale.com/kb/1018/acls↩︎

  11. ACL 構文の解説, https://tailscale.com/kb/1018/acls↩︎

  12. Headscale v0.28.0 リリースノート, https://github.com/juanfont/headscale/releases↩︎

共有

論文解説:Data-centric Artificial Intelligence: A Survey

論文解説:Data-centric Artificial Intelligence: A Survey

論文情報

  • タイトル:Data-centric Artificial Intelligence: A Survey
  • 著者:Daochen Zha, Zaid Pervaiz Bhat, Kwei-Herng Lai, Fan Yang, Zhimeng Jiang, Shaochen Zhong, Xia Hu
  • 所属:Rice University / Texas A&M University(DATA Lab)
  • 掲載誌:ACM Computing Surveys, Vol. 57, No. 5
  • DOI:10.1145/3711118
  • arXiv:2303.10158 (初版 2023年3月、ACM掲載 2025年1月)
  • 付随リソース:data-centric-AI GitHub

動機と位置づけ

従来のAI研究は「model-centric」なパラダイム、すなわち固定されたデータセットを前提にモデル設計・ハイパーパラメータ最適化を繰り返すアプローチを中心としてきた。しかしこのアプローチにはいくつかの本質的な限界がある。

  • 固定データセットへの過度な依存は、実世界応用における汎化性能の低下を招く
  • モデルが特定の問題・データに高度に特化するため、転移が困難
  • データに潜む質的問題(欠損値・不正確なラベル・異常値)を看過しがちであり、データカスケード(上流の品質問題が下流に連鎖的に波及する現象)を引き起こす

Andrew Ng が提唱した Data-centric AI(DCAI) の概念は、この状況への応答として登場した。本論文はその概念を体系的に整理し、156本以上の文献を横断的に調査・分類した初の包括的サーベイである。

なお、「data-centric」と「data-driven」は根本的に異なる概念である。data-drivenはデータをAI開発の指針として使うことを強調するだけで、依然としてモデル開発が主体となる。これに対してdata-centricはデータそのものをエンジニアリングの主対象と置く。

著者について

全著者がRice大学とTexas A&M大学に所属し、Xia Hu 教授(Rice大)が率いる DATA Lab を中心とするグループである。筆頭著者のDaochen Zhaは本サーベイのリードを担い、NeurIPS・ICMLなどのトップ会議への掲載多数。グループはサーベイだけでなく、KDD 2023でのチュートリアル開催、関連ベンチマーク整備、GitHubでのリソースリスト継続更新など、コミュニティ形成にも積極的に関与している。

リサーチクエスチョン

本論文が明示的に設定した4つの問いは以下の通り。

  • RQ1:AIをdata-centricにするために必要なタスクは何か?
  • RQ2:データの開発・維持においてなぜ自動化が重要か?
  • RQ3:どの場面でなぜ人間の参加が不可欠か?
  • RQ4:Data-centric AIの現在の進捗はどこまで来ているか?

フレームワーク:3つの目標(Goal-driven Taxonomy)

論文の中核は、データライフサイクル全体を3つの目標で整理したgoal-driven taxonomyである。

Goal-driven Taxonomy
  • Training Data Development:学習データの収集から前処理・拡張までのパイプライン
  • Inference Data Development:モデルに入力するデータの設計・評価
  • Data Maintenance:データの継続的なメンテナンス

以下、それぞれの目標について詳述する。

Training Data Development

学習データの収集から前処理・拡張までのパイプラインを扱う。モデルの性能はデータの質と量に強く依存するため、このフェーズへの投資がAIシステム全体の基盤となる。

Data Collection

学習に必要な生データを様々なソースから収集・統合する。収集戦略がデータ品質・量の出発点を決定づける。論文は「データ収集プロセスは重要なインフラとツールのサポートを必要とする」と指摘する。

代表的なタスク・手法:Dataset discovery、Data integration、Raw data synthesis

Data Labeling

収集した生データに教師信号(ラベル)を付与し、教師あり学習を可能にする。「ラベリングはモデルが意図した予測を行えるようにするうえで不可欠であり、適切なラベルなしにはモデルは与えられたデータ以上の性能を発揮できない」と論文は述べる。従来は人手に依存していたが、近年は効率化手法が多数提案されている。

代表的なタスク・手法:Crowdsourced labeling、Semi-supervised labeling、Active learning、Data programming(Snorkel)、Distant supervision

Data Preparation

収集・ラベリング済みデータを学習に適した形式に変換・整備する。欠損値処理・外れ値除去・特徴量抽出・変換など、モデルへの入力品質を直接左右する工程である。

代表的なタスク・手法:Data cleaning、Feature extraction、Feature transformation

Data Reduction

データの次元や量を削減しつつ、モデル性能を維持または向上させる。不要な特徴量を除去することで計算コストを下げ、過学習を抑制する。「特徴選択は数十年前から研究されてきた古典的テーマ」と論文は位置づけている。

代表的なタスク・手法:Feature selection、Dimensionality reduction、Instance selection

Data Augmentation

手元のデータセットに対して変換・合成を施し、データの多様性と量を拡大する。追加収集なしにデータ分布を豊かにし、モデルの汎化性能を高める。クラス不均衡への対応(SMOTE・ADASYN)も含む。

代表的なタスク・手法:Basic manipulation(回転・フリップ等)、GAN・拡散モデルによる合成、Upsampling

Pipeline Search

前処理・削減・拡張など複数工程を横断的に統合し、エンドツーエンドで最適な構成を探索する。個別工程の局所最適ではなく全体最適を目指す。AutoSklearnを先駆けとし、DARPAのD3Mプログラムがインフラ整備を牽引してきた。

代表的なタスク・手法:AutoSklearn、DARPA D3M、End-to-end AutoML

Inference Data Development

モデルに入力するデータの設計・評価を扱う。model-centricパラダイムではほぼ看過されていた領域だが、大規模言語モデルの台頭によりその重要性が急上昇している。

In-distribution Evaluation

学習データ分布の範囲内で、モデルの挙動を細粒度に把握・診断する。特定のデータスライス(属性の組み合わせ等)でモデルが弱い箇所を特定したり、モデル判断の「反事実的な境界」(Algorithmic recourse)を可視化する。潜在的なバイアスの検出にも有効である。

代表的なタスク・手法:Data slicing(Slice Finder)、Algorithmic recourse(反事実的説明)

Out-of-distribution Evaluation

学習分布から外れた入力に対するモデルの脆弱性・頑健性を評価する。敵対的サンプルを用いたAIセキュリティ研究の基盤であり、実世界展開時のリスク把握に直結する。

代表的なタスク・手法:Adversarial samples生成、Distribution shiftのシミュレーション

Prompt Engineering

学習済みの大規模モデルをパラメータ更新なしに活用するため、入力データ(プロンプト)を最適化する。「モデルが十分に強力な場合、推論データ(プロンプト)を調整するだけで目的を達成できる」と論文は示す。手動設計から自動探索(Automated Prompt Search)まで幅広い手法が対象である。

代表的なタスク・手法:Manual prompt design、Automated prompt search

Data Maintenance

実世界ではデータは一度作成して終わりではなく、継続的なメンテナンスが必要である。このフェーズはトレーニング・推論データの正確性と信頼性を動的環境の中で保証するための役割を担う。

Data Understanding

複雑なデータセットを人間が洞察を得やすい形に可視化・要約する。また Data valuation(各データポイントがモデルに対してどれだけ貢献しているかの定量評価)により、取捨選択や改善優先度の判断を支援する。

代表的なタスク・手法:Visual summarization、Clustering for visualization、Visualization recommendation、Data valuation

Data Quality Assurance

データの品質を定量的に評価し、問題箇所を検出・修復する。動的環境でのデータドリフト検知や継続的な品質モニタリングを含む。データカスケード(品質問題の連鎖的伝播)を防ぐ最重要プロセスである。

代表的なタスク・手法:Quality assessment、Quality improvement

Data Storage & Retrieval

必要なデータを効率的に供給するためのインフラ最適化。クエリ性能の向上・インデックス自動選択・DBの自律チューニングなど、大規模データを実用速度で扱うための基盤技術である。機械学習を用いてDB管理システム自体を自律化する方向性(Self-driving DB)も含まれる。

代表的なタスク・手法:Query index selection、Query rewriting、Resource allocation、DB自律チューニング

なお、各サブゴールのうち、Data Preparation・Data Reduction・Data Storage & Retrieval の説明については、論文のフレームワーク定義とTable 1の分類を根拠として補足している。論文ではこれらの項目は手法列挙が主であり、目的の散文的説明は省略されているため、論文のコンテキストから解釈・補完した部分がある。

横断的な分析視点:自動化 vs. 人間協働

各タスクを「自動化の程度」と「人間の関与度」という2軸でさらに分類している点が本論文の独自性の一つである。2軸はそれぞれ独立したスペクトラムであり、論文内の各手法はいずれかに分類される。

自動化 vs. 人間協働の2軸

自動化の3レベル

自動化軸はコスト・複雑さが低い方から高い方に向かって以下の3レベルに分かれる。

  • Programmatic(人間コスト:低):ヒューリスティクスや統計的ルールでデータを自動処理する。設計が単純で高速だが、柔軟性は低い。
  • Learning-based(人間コスト:中):目的関数を最適化することで自動化戦略自体を学習する。より柔軟・適応的だが、学習コストが発生する。
  • Pipeline(人間コスト:高):前処理〜拡張など複数工程を横断して最適構成を一括探索する。全体最適を狙えるが、探索コストが大幅に増大する。

人間協働の3段階

人間協働軸は人間の関与度が低い方から高い方に向かって以下の3段階に分かれる。

  • Minimum participation(人間コスト:低):手法がプロセス全体を制御し、必要なときのみ人間に判断を求める。
  • Partial participation(人間コスト:中):手法が主導しつつ、人間が継続的にフィードバックを提供し続ける。
  • Full participation(人間コスト:高):人間がプロセスを完全制御し、手法は補助ツールに徹する。

自動化・人間協働のどちらのレベルも「高い方が優れている」わけではない。効率(人間労力の削減)と有効性(人間の意図との整合)はトレードオフであり、ドメイン・ステークホルダーのニーズに応じた使い分けが前提となる。たとえば Pipeline automation はシナリオによっては過複雑となり、単純な Programmatic 手法の方が実用的なケースも多い。

調査対象論文の範囲と時代的分布

本サーベイが対象とする文献は、古典的な研究から最新の動向まで幅広い時代にわたる。

  • 古典的・確立領域:Feature selection、Data augmentation(基本的手法)、Active learning
  • 2010年代後半:Crowdsourcing(MTurk系)、AutoML(AutoSklearn等)、GAN系データ拡張
  • 2020年代前半:Data programming(Snorkel)、Prompt engineering、RLHF、Adversarial robustness
  • 最新動向(2023年時点):Foundation models活用、Automated prompt search、Algorithmic recourse

個別テーマに絞った既存サーベイ(データ拡張、ラベリング、特徴選択等)はすでに存在していたが、データライフサイクル全体を横断するgoal-driven taxonomyによる統合的整理は本論文が初である。

主要な考察結果

Data-centric と Model-centric は対立しない

model-centricの価値を否定するのではなく、相互補完的なパラダイムとして捉える。GANや拡散モデル等のモデル技術がデータ拡張を支援し、逆に拡充されたデータがモデル設計の進化を促す。本番環境ではデータとモデルは絶えず変化する環境の中で交互に進化していく。

データカスケード問題の深刻さ

データ品質を軽視すると、上流の問題が下流に連鎖的に波及し、精度低下・持続的バイアスなどを引き起こす。高リスク領域(医療・金融等)ではこの影響が特に甚大である。

大規模言語モデルの成功はData-centric AIの証左

GPT-2からGPT-3への進化はアーキテクチャの変更ではなく、高品質・大規模なデータの収集によって達成された。ChatGPTもGPT-3と同等アーキテクチャのまま、RLHFによる高品質ラベルデータの活用が成功の鍵となっている。

評価フェーズの再定義

Data-centric AIパラダイムにおける評価は、精度指標だけでなく、データの動的な性質・攻撃者の存在・説明可能性(right of explanation)など多面的な側面を考慮すべきである。

将来の研究課題(Future Directions)

  • Foundation Models との統合:大規模事前学習モデルがラベリング・拡張・品質保証などのData-centric AIタスクをどう変革するか
  • プライバシー保護との両立:連合学習・差分プライバシー等を組み合わせた、データ品質向上とプライバシー保護の共立
  • 統一ベンチマーク整備:個別タスクに偏った既存ベンチマーク(DataPerf等)を超える、データライフサイクル全体を評価できる指標の構築
  • 高リスクドメインへの展開:医療・金融・法律等における体系的なデータエンジニアリングの適用と検証
  • データカスケードの予防:上流品質管理の自動化・定量化手法の確立

総評

本論文の最大の貢献は、従来は独立して議論されていた多数のデータ関連タスクを、データライフサイクルという統一的な視座のもとに再配置し、自動化と人間協働という実践的な軸を加えて整理した点にある。単なるサーベイにとどまらず、コミュニティへの方向付けを意図した「教科書的」な役割を担う論文として位置づけられる。

ただし、本論文が主に扱うのはアルゴリズム・手法レベルの分類であり、システムアーキテクチャ(データスペース設計・分散インフラ等)については対象外である点は留意が必要である。データエコシステムや主権保護的なデータ流通の文脈でこの論文を読む際は、Data Maintenanceのサブゴール(品質保証・データ理解)との接続点を中心に参照するのが実用的である。

参考情報

共有

Claude CodeからOpenAI Codexを使う方法 - MCPで実現するマルチAI開発環境

Claude CodeとOpenAI Codexは、それぞれ異なる特性を持つ優れたコーディング支援AIである。 両者を組み合わせることで、各モデルの得意分野を活かしたマルチAI開発環境を構築できる。 本記事では、Model Context Protocol(MCP)を使用してClaude CodeからOpenAI Codexを呼び出す方法を解説する。

자세히 보기

共有

Gemini with Claude Code

メモ

Claude CodeからGeminiを利用する方法についてのメモ。 MCPサーバーを使うことで、Claude CodeのセッションからGeminiの機能を呼び出すことができる。

主な選択肢として以下がある。

  1. gemini-mcp-tool: Gemini CLIラッパー(大規模ファイル分析向け)
  2. mcp-gemini-cli: シンプルなGemini CLIラッパー
  3. @rlabs-inc/gemini-mcp: 多機能なGemini統合サーバー
  4. gemini-mcp-server: 多機能なGemini CLIラッパー

MCPサーバーのスコープ設定

Claude CodeでMCPサーバーを追加する際、-s オプションでスコープを指定できる。

スコープ オプション 設定ファイル 用途
ユーザー -s user ~/.claude.json どのプロジェクトでも使いたい場合
プロジェクト -s project .mcp.json(リポジトリ内) 特定プロジェクトのみで使う場合

Gemini連携は汎用的なツールなので、ユーザースコープ(-s user)での設定が便利。 以下の各ツールのインストール例では、用途に応じてスコープを調整すること。

gemini-mcp-tool

gemini-mcp-tool はGemini CLIのMCPサーバーラッパー。 Geminiの大規模トークンウィンドウを活用し、大規模ファイル分析やコードベース理解に適している。

特徴

  • Gemini CLIの大規模トークンウィンドウを活用
  • サンドボックスでのコード実行に対応
  • @構文によるファイル/ディレクトリ参照

提供機能

ツール名 説明
ask-gemini ファイル解析や一般的な質問への回答
sandbox-test Geminiのサンドボックスでコード/コマンドを安全に実行

スラッシュコマンドとして /analyze/sandbox/help/ping も提供。

インストール

前提として、Gemini CLIのインストールと認証を完了しておく必要がある。

Claude Codeでのセットアップ:

1
$ claude mcp add gemini-cli -s user -- npx -y gemini-mcp-tool

または、設定ファイル(~/.claude.json など)に直接記述:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"mcpServers": {
"gemini-cli": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"gemini-mcp-tool"
],
"env": {}
}
}
}

ユースケース

  • 大規模なコードベースの分析
  • @largefile.js のような構文でファイルを指定して解析
  • サンドボックス環境でのコードテスト

mcp-gemini-cli

mcp-gemini-cli はGemini CLIのシンプルなMCPサーバーラッパー。 MCP Gemini CLI入門:Claude CodeとGeminiの連携でAIコーディングを強化する に詳しい解説がある。

特徴

  • シンプルな設計で3つの機能を提供
  • Gemini CLIの認証を利用

提供機能

ツール名 説明
googleSearch Gemini経由でGoogle検索を実行
chat Geminiとの直接会話
analyzeFile 画像、PDF、テキストファイルの分析

インストール

前提として、Gemini CLIの認証を完了しておく必要がある。

1
$ claude mcp add -s user gemini-cli -- npx @choplin/mcp-gemini-cli --allow-npx

ユースケース

  • 「Geminiに最新のNext.js 15の新機能を検索してもらって」
  • 「Geminiにこのエラーメッセージの解決方法を聞いて」

@rlabs-inc/gemini-mcp

RLabs-Inc/gemini-mcp はGemini 3モデルとの統合を提供する多機能なMCPサーバー。 30以上のツールを提供し、画像生成、動画生成、コード実行など幅広い機能が利用可能。

特徴

  • 30以上のツールを提供
  • Gemini API Keyを使用(無料で取得可能)
  • 画像生成(最大4K)、動画生成(Veo 2.0)、TTSなど

主な機能

カテゴリ 機能
コンテンツ生成 画像生成、動画生成、TTS(30種類の音声)
Web統合 リアルタイム検索、YouTube動画分析
ドキュメント処理 PDF/DOCX分析、テーブル抽出、要約
コード実行 Python実行(numpy, pandas, matplotlib対応)
AI推論 Geminiへの直接クエリ、思考レベル調整

インストール

Google AI Studio からGemini API Keyを取得し、以下のコマンドでインストール。

1
$ claude mcp add gemini -s user -- env GEMINI_API_KEY=YOUR_KEY npx -y @rlabs-inc/gemini-mcp

グローバルインストールの場合:

1
$ npm install -g @rlabs-inc/gemini-mcp

設定オプション

環境変数 説明
GEMINI_API_KEY 必須。Google AI Studioで取得
GEMINI_OUTPUT_DIR 生成ファイルの保存先(デフォルト: ./gemini-output)
VERBOSE 詳細ログの有効化

gemini-mcp-server

gemini-mcp-server はGemini CLIをラップした多機能なMCPサーバー。 「ClaudeにGeminiの巨大コンテキストウィンドウのスーパーパワーを与える」というコンセプトで開発されている。

特徴

  • Geminiの100万トークン超のコンテキストウィンドウを活用
  • 5つのツールによる多機能性
  • VS Code、Cursorなど複数のIDE対応

提供機能

ツール名 説明
gemini ファイルやコードベースをGeminiの大規模コンテキストで分析
web-search Google検索グラウンディング対応のWeb検索
analyze-media 画像、PDF、スクリーンショットの処理
shell シェルコマンドの生成・実行
brainstorm 構造化手法による創造的なアイデア出し

インストール

前提として、Gemini CLIのインストールと認証を完了しておく必要がある。

1
$ npm install -g @google/gemini-cli

Claude Codeでのセットアップ:

1
$ claude mcp add gemini-cli -s user -- npx -y @tuannvm/gemini-mcp-server

ユースケース

  • 大規模なコードベースの分析
  • Web検索を組み合わせた調査
  • 画像やPDFの分析
  • アイデアのブレインストーミング

どれを選ぶか

観点 gemini-mcp-tool mcp-gemini-cli @rlabs-inc/gemini-mcp gemini-mcp-server
導入の手軽さ ○ API Key取得が必要
機能数 ○ 2機能+コマンド △ 3機能 ◎ 30+機能 ○ 5機能
用途 大規模ファイル分析、サンドボックス 検索・対話・ファイル分析 画像/動画生成、コード実行など多目的 コードベース分析、Web検索、メディア分析
依存関係 Gemini CLI Gemini CLI なし(API直接利用) Gemini CLI
特徴 大規模トークンウィンドウ活用 シンプル 多機能 バランス型、IDE対応
  • 大規模コードベースの分析には gemini-mcp-tool
  • シンプルに検索や対話を追加したい場合は mcp-gemini-cli
  • 多機能な統合が必要な場合は @rlabs-inc/gemini-mcp
  • バランスの良い機能とIDE対応が欲しい場合は gemini-mcp-server

筆者は現在 gemini-mcp-server を使用している。

参考

共有

Claude Code Setup

メモ

Claude CodeのCLI版をセットアップするメモ。 以前はnpmでインストールしていたが、ネイティブインストールに切り替えた。

システム要件

Set up Claude Code によると、以下の要件がある。

  • OS: macOS 13.0+、Ubuntu 20.04+/Debian 10+、Windows 10+ (WSL 1、WSL 2、またはGit for Windows)
  • ハードウェア: 4 GB以上のRAM
  • ネットワーク: インターネット接続が必要
  • シェル: BashまたはZshが推奨

なお、ネイティブインストールの場合はNode.jsは不要。npmインストール(非推奨)の場合のみNode.js 18以上が必要。

ネイティブインストール(推奨)

現在はネイティブインストールが推奨されている。 Ubuntu/Linux/WSLの場合、以下のコマンドでインストールする。

1
$ curl -fsSL https://claude.ai/install.sh | bash

ネイティブインストールの場合、バックグラウンドで自動更新されるため、常に最新バージョンが利用可能。

既存のnpmインストールからの移行

既存のnpmインストールからネイティブインストールへ移行するには、以下のコマンドを実行する。

1
$ claude install

npmインストール(非推奨)

npmインストールは非推奨となっている。 可能な限りネイティブインストールを使用すること。

1
$ npm install -g @anthropic-ai/claude-code

注意: sudo npm install -g は使用しないこと。パーミッションの問題やセキュリティリスクにつながる可能性がある。

インストール後の確認

インストール後、以下のコマンドでインストールの種類とバージョンを確認できる。

1
$ claude doctor

PATHの問題

command not found: claude というエラーが出る場合は、PATHに追加する。

1
2
$ echo 'export PATH="$HOME/.claude/bin:$HOME/.local/bin:$PATH"' >> ~/.bashrc
$ source ~/.bashrc

認証

個人利用の場合

  1. Claude ProまたはMaxプラン(推奨): Claude's Pro or Max plan でサブスクライブし、Claude.aiアカウントでログイン
  2. Claude Console: Claude Console からOAuthプロセスを完了。Anthropic Consoleでのアクティブな請求が必要

チーム・組織での利用

  1. Claude for Teams または Enterprise(推奨): 一元化された請求とチーム管理
  2. Claude Console with team billing: 共有組織を設定
  3. クラウドプロバイダ: Amazon Bedrock、Google Vertex AI、Microsoft Foundryを使用

アンインストール

ネイティブインストールの場合

1
2
$ rm -f ~/.local/bin/claude
$ rm -rf ~/.local/share/claude

npmインストールの場合

1
$ npm uninstall -g @anthropic-ai/claude-code

設定ファイルのクリーンアップ(オプション)

1
2
$ rm -rf ~/.claude
$ rm ~/.claude.json

注意: これにより全ての設定、許可されたツール、MCPサーバー設定、セッション履歴が削除される。

参考

[@anthropic-ai/claude-code - npm]: https://www.npmjs.com/package/@anthropic-ai/claude-code

共有

Claude Code with Claude Code Web

メモ

Claude Code(CLI版)とClaude Code Web(クラウド版)を連携して使う方法。

認証

Max Plan / Pro Planあれば、claude loginでブラウザ認証すればAPIキー不要で両方使える。

1
claude login

モデル設定

環境変数で統一:

1
export ANTHROPIC_MODEL=opus

起動時に指定:

1
claude --model opus

セッション中に切り替え:

1
/model sonnet

モデルエイリアス:

エイリアス 用途
default アカウント種別に応じた推奨
sonnet 普段のコーディング
opus 複雑な推論
haiku 軽いタスク
opusplan 計画時Opus、実行時Sonnet

&でWebにタスク送信

先頭に&付けると新規Webセッション作ってバックグラウンドで動く。

1
& Fix the authentication bug in src/auth/login.ts

コマンドラインからも:

1
claude --remote "Fix the authentication bug"

流れ

1
2
3
4
5
6
7
ローカルCLI会話

[& タスク指示] → 新規Webセッション作成

Webで自律実行(バックグラウンド)

/tasks で監視 → 必要ならteleportでローカルに戻す

向いてるタスク

  • バグ修正、テスト作成など明確なタスク
  • 複数タスク同時進行
  • 時間かかる処理

並列実行

1
2
3
& Fix the flaky test in auth.spec.ts
& Update the API documentation
& Refactor the logger module

それぞれ別のWebセッションで同時に動く。

タスク確認

1
/tasks

一覧出て、tキーでテレポートできる。 claude.ai/codeでも確認できる。

&とteleportの違い

機能 方向 用途
& CLI → Web タスクをWebに送る
/teleport Web → CLI Webセッションをローカルに持ってくる

ワークフロー例

1
2
3
4
5
# 1. ローカルで計画
claude --permission-mode plan

# 2. Webで実行
& Execute the migration plan we discussed

計画はローカルでやって、実行はクラウドに任せる。

制限

  • GitHubのみ(GitLab未対応)
  • 既存セッション丸ごとWebに移すのは無理(新規作成のみ)
  • 同じClaude.aiアカウントでログイン必要

参考

共有

Claude Code クラウド環境のネットワーク制限と対処法

概要

Claude Code on the web(クラウド環境)では、セキュリティのためネットワークアクセスに制限がある。 本記事では、スマホアプリ版のClaude Codeで作業しようとした際に遭遇した問題とその解決策を解説する。

環境構成

Claude Codeクラウド環境は以下の構成で動作している。

項目 設定
ネットワーク HTTPプロキシ経由(JWT認証付き)
DNS /etc/resolv.conf が空(DNSサーバー未設定)
許可ホスト ホワイトリスト方式(開発ツール関連サイト)

問題1: apt updateが失敗する

症状

1
2
W: Failed to fetch http://archive.ubuntu.com/ubuntu/dists/noble/InRelease
Temporary failure resolving 'archive.ubuntu.com'

原因

  • /etc/resolv.conf が空でDNSサーバーが設定されていない
  • aptがプロキシを使用する設定になっていない

診断コマンド

1
2
3
4
5
6
7
8
# DNS設定確認
cat /etc/resolv.conf

# プロキシ環境変数確認
env | grep -i proxy

# curlの接続先確認(プロキシ経由か直接か)
curl -v http://archive.ubuntu.com 2>&1 | grep -E "Connected|Trying"

解決策

プロキシ環境変数からaptの設定を作成する。

1
2
3
4
5
6
7
8
9
10
11
# プロキシURLを取得
printenv http_proxy > /tmp/proxy_url.txt

# apt用プロキシ設定を作成
sudo bash -c 'cat > /etc/apt/apt.conf.d/proxy.conf << EOF
Acquire::http::Proxy "$(cat /tmp/proxy_url.txt)";
Acquire::https::Proxy "$(cat /tmp/proxy_url.txt)";
EOF'

# 動作確認
sudo apt update

ポイント: プロキシURLにはJWT認証トークンが含まれているため、完全なURLを使用する必要がある。

問題2: GitHubリリースのダウンロードが403エラー

症状

1
2
$ curl -L "https://github.com/quarto-dev/quarto-cli/releases/download/v1.4.549/quarto-1.4.549-linux-amd64.deb"
curl: (56) CONNECT tunnel failed, response 403

原因

GitHubリリースはCDN(objects.githubusercontent.com等)にリダイレクトされるが、 リダイレクト先がホワイトリストに含まれていない場合がある。

解決策: conda-forge経由でインストール

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Minicondaをダウンロード(repo.anaconda.comは許可されている)
curl -sL "https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh" \
-o /tmp/miniconda.sh

# インストール
bash /tmp/miniconda.sh -b -p $HOME/miniconda3

# 利用規約に同意
$HOME/miniconda3/bin/conda tos accept --override-channels \
--channel https://repo.anaconda.com/pkgs/main
$HOME/miniconda3/bin/conda tos accept --override-channels \
--channel https://repo.anaconda.com/pkgs/r

# conda-forgeからQuartoをインストール
$HOME/miniconda3/bin/conda install -y -c conda-forge quarto

問題3: 外部サイト(zotero.org等)へのアクセスがブロック

症状

1
2
Could not fetch https://www.zotero.org/styles/ieee
ProxyConnectException "www.zotero.org" 443 (Status {statusCode = 403})

原因

ホワイトリストに含まれていないホストへのアクセスは403 Forbiddenで拒否される。

解決策: ローカルファイルを使用

1
2
3
4
5
6
7
8
# GitHubのraw.githubusercontent.comは許可されている
curl -sL "https://raw.githubusercontent.com/citation-style-language/styles/master/ieee.csl" \
-o sources/references/ieee.csl

# 設定ファイルをローカル参照に変更
# csl: https://www.zotero.org/styles/ieee
# ↓
# csl: ../sources/references/ieee.csl

許可されている主要ホスト

プロキシのJWTトークンに含まれるallowed_hostsから抜粋。

カテゴリ ホスト
パッケージ管理 pypi.org, registry.npmjs.org, repo.anaconda.com, conda.anaconda.org
GitHub github.com, api.github.com, raw.githubusercontent.com, gist.github.com
Ubuntu *.ubuntu.com, archive.ubuntu.com, security.ubuntu.com
その他開発ツール crates.io, rubygems.org, golang.org, hub.docker.com

conda-forge版Quartoの追加設定

conda-forgeからインストールしたQuartoは、パス設定に追加作業が必要な場合がある。

1
2
3
4
5
# QUARTO_SHARE_PATHを設定
export QUARTO_SHARE_PATH=$HOME/miniconda3/share/quarto

# ビルド実行
$HOME/miniconda3/bin/quarto render report.qmd --to html

まとめ

問題 解決策
apt失敗 プロキシ設定を/etc/apt/apt.conf.d/proxy.confに追加
GitHubリリースのブロック conda-forge経由でインストール
外部サイトのブロック GitHubのraw URLからダウンロードしてローカル参照

推奨ワークフロー

  1. 開発・プレビュー: ローカル環境で実施(ネットワーク制限なし)
  2. ビルド・品質チェック: クラウド環境で実施(上記対策を適用)
  3. 外部依存ファイル: 事前にローカルにダウンロードしてリポジトリに含める

参考

共有

仕事の基礎ガイド「Work Fundamentals」を公開しました

概要

「何をすればいいか分からない」「何をどう報告すればいいか分からない」という悩みを解消し、 自律的に動けるようになることを目指した実践的な仕事ガイド「Work Fundamentals」を公開した。

Work Fundamentals は主に新人・若手社員を対象としているが、 仕事の進め方を改めて見直したい方にも参考になる内容となっている。

対象読者

以下のような方を想定している。

  • 仕事の進め方に悩む方
  • 指示がないと動けない感覚を持つ方
  • 報告・相談に苦手意識のある方
  • タスク管理や時間管理を改善したい方

ガイドの構成

ガイドは以下の3部構成となっている。

Part 1: 日常業務編

日々の業務を効率的に進めるための基本を解説している。

  • 朝のルーティン
  • タスク管理ルール
  • 報告方法
  • 時間管理テクニック

Part 2: プロジェクト遂行編

プロジェクトに参加する際の実践的なノウハウを提供している。

  • プロジェクト参加時の心構え
  • タスク遂行フロー
  • 会議参加方法
  • 成果物作成ポイント

Part 3: 困ったときの対処法

よくある課題への解決策を示している。

  • よくある課題への対処法
  • 1on1の活用方法

技術情報

このガイドは Quarto を使用して構築されており、GitHub Pagesでホストされている。 Apache-2.0ライセンスの下で公開されているため、自由に利用・改変が可能である。

参考

共有

欧州健康データ空間(EHDS)分析レポートをGitHub Pagesで公開

欧州健康データ空間(EHDS)に関する包括的な分析レポートを作成し、GitHub Pagesで公開しました。本レポートは、EHDSの技術仕様、実装要件、そして日本の医療機関・企業への影響について詳細に分析したものです。

免責事項

本レポートは、個人的な興味・関心に基づいて作成したものであり、特定の組織や企業の見解を代表するものではありません。内容は執筆時点での公開情報に基づく個人的な分析・考察であり、実際の政策実装や事業判断にあたっては、必ず最新の公式情報をご確認ください。

注記: 本レポートは現在執筆途中です。内容は随時更新・改訂される予定です。

レポートの概要

本レポートは、2025年より段階的に施行される欧州健康データ空間(European Health Data Space, EHDS)規則について、技術的・政策的観点から包括的に分析した専門家向けの資料です。

主な内容

  • EHDS規則の詳細分析: 一次利用・二次利用の要件、技術仕様、実装タイムライン
  • 技術要件の解説: HL7 FHIR準拠、相互運用性要件、セキュリティ基準
  • 日本への影響評価: 医療機器メーカー、医療ITベンダー、医療機関への具体的影響
  • 実装ガイダンス: 段階的対応戦略、必要な準備、投資機会の分析

公開情報

レポートは以下のリンクからアクセス可能です:

技術スタック

本レポートの作成には、以下の技術を活用しています:

  • Quarto: 学術文書作成システム(Markdown + Pandoc)
  • GitHub Actions: 自動ビルド・デプロイメント
  • GitHub Pages: 静的サイトホスティング
  • Pandoc: 多様な出力形式(HTML、PDF)の生成

想定読者

  • 医療機器メーカーの戦略企画・規制対応部門
  • 医療ITベンダーの製品開発・事業開発部門
  • 医療機関の情報システム部門
  • 政策立案者・規制当局
  • 医療データ利活用に関わる研究者

今後の更新予定

本レポートは継続的に更新される予定です。特に以下の点について拡充を計画しています:

  1. EHDS実装ガイドラインの最新動向の反映
  2. 日本国内での対応事例の収集と分析
  3. アジア太平洋地域への展開戦略の追加
  4. 米国市場との比較分析

コントリビューション

本レポートはオープンソースプロジェクトとして公開しています。以下の方法でコントリビューションを歓迎します:

  • Issue報告: 誤りの指摘、改善提案、質問など
  • Pull Request: 内容の追加・修正の提案
  • ディスカッション: GitHubディスカッションでの意見交換

ライセンス

本レポートは知識共有を目的として公開されています。詳細なライセンス情報はリポジトリをご確認ください。

参考

共有