Discord から Hermes Agent に頼んで VPN サーバーを起動する
スマホの Discord で「VPN サーバーを起動して」と送ると、手元の Linux で動く Hermes Agent がスクリプトで Vultr に WireGuard のサーバーを作り、DDNS を更新し、サーバーの状態と DNS を確かめてから返事をくれます。使わない夜はサーバーを削除しています。仕組みと、AI に任せる範囲の決め方をまとめます。
スマホの Discord から「VPN サーバーを起動して」と送ると、VPN のサーバーが立ち上がるようにしています。
受け取るのは、手元の Linux Mint で常駐させている Hermes Agent(以下 Hermes)の Discord の Bot です。Hermes は前から使っている VPN の管理スクリプトを実行して、Vultr に WireGuard のサーバーを作ります。新しいサーバーの IP は DDNS(f5.si)に登録され、スマホの WireGuard のアプリは決まった名前で接続できます。Hermes は最後に、サーバーの状態と DNS を別々に確かめて、両方そろってから「起動しました」と返してきます。
VPN のサーバーは常に動かしてはいません。使わないときは消していて、毎晩 3 時にサーバーを削除する処理が動きます。
作ったきっかけ
出先では、セキュリティのために、なるべく公共の Wi-Fi にはつながないようにしています。ただ、携帯の電波が悪い場所にいるときや、大きなデータをやり取りしなければならないときは、ホテルやフェリーの Wi-Fi に仕方なくつなぐことがあります。そういうときに、この VPN を通すようにしています。
使うのはそういう場面だけなので、VPN のサーバーを常に動かしておく必要はありません。常に動かしておくと、使っていない間も料金がかかりますし、VPN のサーバーを常に動かしておくこと自体のセキュリティのリスクもあります。そこで、使いたいときだけ気軽に起動できる仕組みが欲しくて作りました。
全体の流れ
- Discord で Hermes に「VPN サーバーを起動して」と送る(DM なら普通のメッセージ、サーバーのチャンネルでは Bot へのメンション)
- Hermes が
start-vpn.sh nrtを 1 回だけ実行する - スクリプトが Vultr の東京リージョンにサーバーを作り、新しい IP を DDNS に登録する
- Hermes がサーバーの状態と DNS を別々に確かめる
- 両方そろっていれば、Discord に起動の完了と IP を返す
実際のやり取りはこうなります。Hermes はスキルを読み、スクリプトを実行し、確かめ終わってから返事をくれます。

Hermes に任せる範囲
Hermes には、Vultr の API を直接呼ばせていません。サーバーを作る・消す・状態を見るのは前から使っている 3 つのスクリプトで、Hermes はそれを呼ぶだけです。
どの言葉でどのスクリプトを呼ぶかは、Hermes のスキル(作業の手順書)に書いています。
| 頼み方 | 実行するもの |
|---|---|
| 「VPN を起動して」(リージョンの指定なし) | start-vpn.sh nrt |
| 「東京で VPN を起動」 | start-vpn.sh nrt |
| 「ソウルで VPN を起動」 | start-vpn.sh icn |
| 「VPN を停止して」 | stop-vpn.sh |
| 「VPN の状態」 | status-vpn.sh |
スキルには、ほかにも決まりを書いています。
- サーバーを作る・消すのは、はっきり頼まれたときだけ。 お金のかかるクラウドの資源を変えるので、会話の流れから勝手に起動したり作り直したりしない
- 状態を変えるコマンドは 1 回だけ実行する
- リージョンを指定されなければ東京にして、
nrtを明示して渡す。 スクリプトは引数が無いと設定ファイルの既定のリージョンを使うので、Hermes の既定と食い違わないようにしている - Vultr の API を直接呼ばない。 スナップショットからの復元を待つ確認を飛ばして、使えないサーバーが残るおそれがあるため
起動のスクリプトがすること
start-vpn.sh は次の順に進みます。
- リージョンに合わせたファイアウォールのグループを選ぶ
- ラベルが
wireguard-vpnのサーバーがすでにあれば、何も作らずに終わる - 無ければ、WireGuard を設定済みのスナップショットからサーバーを作る
- Vultr の
statusがactiveになり、続いてserver_statusがokになるまで待つ - 割り当てられた IP を取り、f5.si の DDNS の更新 API に送る
サーバーは作るたびに違う IP になります。スマホの WireGuard の接続先は IP ではなく <ホスト名>.f5.si という名前にしてあるので、DDNS が新しい IP を返すようになれば、アプリの設定は変えずにつながります。
「起動した」と返す条件
スクリプトの最後に VPN started と出ても、Hermes はそれだけで完了とは返しません。スキルで、次の 2 つを別々に確かめるようにしています。
- サーバーの状態:
status-vpn.shで、東京のサーバーがあり、server_statusがokであること - DNS:
verify-ddns.sh --wait 300で、DDNS の名前が今のサーバーの IP を返すこと
DNS を別に確かめるのは、DDNS の更新 API が成功を返すことと、DNS が実際に新しい IP を返すことが別の話だからです。verify-ddns.sh は、ふつうのキャッシュ DNS ではなく、f5.si の権威 DNS 4 台に直接問い合わせます。キャッシュ DNS は TTL の間は古い IP を返すことがあり、「まだ行き渡っていない」のか「更新が反映されていない」のかを見分けられないからです。4 台すべてが今の IP を返したときだけ OK にして、合わなければ 15 秒おきに最大 300 秒まで待ちます。
DNS が合わないまま時間切れになったときは、「サーバーは動いているが、名前はまだ確かめられていない」と返す決まりです。スクリプトの終了コードだけで成功と報告することもしません。
ただし、ここで確かめているのは、クラウドのサーバーと接続先の名前の準備ができたところまでです。WireGuard がサーバーで待ち受けているか、スマホとのハンドシェイクができるかまでは見ていません。スマホからつながらないときは、別に調べることになります。
使わない夜は削除する
stop-vpn.sh は、ラベルが wireguard-vpn のサーバーを削除します。電源を切って残すのではなく、消します。次に使うときは、またスナップショットから作ります。
この stop-vpn.sh を、cron で毎日 3 時に動かしています。8 か月ほどの記録で 247 回動いていて、そのうちサーバーを削除したのは 128 回、何も無かったのは 119 回でした。おおよそ 2 日に 1 回くらい、VPN を立ち上げていたことになります。
今の停止のスクリプトは、Vultr からのエラーの中身を確かめていません。削除を断られても Deleted と表示しうるので、止めたあとは status-vpn.sh で、サーバーが本当に無くなったかを確かめます。状態の確認も、Vultr の API が一時的にエラーを返すと「停止しています」と表示してしまうことがあるので、疑わしいときは問い合わせ直します。
Vultr を選んだ理由
VPN 経由で動画などを見ると、VPN のサーバーからスマホへ送る通信(サーバーから見たアウトバウンド)が増えます。
- AWS EC2 は、インターネット向けのデータ転送が、全サービス合計で月 100GB の無料枠を超えると、量に応じて課金されます(EC2 の料金)
- Vultr にも転送量の上限と超過料金はあります。ただ、アカウントごとに月 2TB の無料枠があり、動いているサーバーのプランの付属枠が稼働時間に応じて足されます。超えた分は 1GB あたり $0.01 です(転送量の上限の計算、超過料金)
無料枠と超過の単価が事前に分かっていて、通信量と料金を見ながら使いやすいと考えて、Vultr にしました。料金は 2026 年 10 月に公式の資料で確かめたもので、変わることがあります。



