FreeBind と After= の違い:systemd ソケットを VPN アドレスに束縛する
FreeBind は VPN アドレスが存在する前に systemd にリスナーを所有させますが、After= はジョブを並べるだけです。両者を比較し、順序と準備状態を検証してください。
起動時、固定の VPN アドレスに束縛するソケットユニットは、トンネルがそのアドレスを割り当てる前に失敗し、その背後のサービスは決して起動しないことがあります。二つのスイッチは修正に見えますが、その問題の別々の半分を解きます。FreeBind はアドレスがまだ無い間に systemd がリスナーを作れるようにします。After= はジョブを並べるだけなので、物事がいつ始まるかを変えるものの、アドレスを早く届けることはしません。
二つの異なる問題、二つの異なるスイッチ
第一の問題は束縛の失敗です。カーネルはホストが所有しないアドレスでの待ち受けを拒否するため、ソケットユニットは即座に失敗し、サービスは決して有効になりません。第二の問題は準備状態の失敗です。アドレスは最終的に存在しますが、トンネルが通信を運ぶ前に何かがそれを使おうとします。FreeBind は前者に対処し、後者には何もしません。順序の指示はどちらにも直接対処しません。なぜなら、それらは何がどの順序で始まるかを決めるだけだからです。実際にある失敗を名指しすることが、決定のすべてです。
どちらなのかは、サービスの説明ではなくジャーナルで確認してください。束縛の失敗はアドレスを挙げ、割り当てられないと報告します。準備状態の失敗は通常もっと後に現れ、タイムアウトや相手側から見た接続拒否として現れ、ログにはまったく健全なソケットユニットが残ります。
FreeBind:リスナーはアドレスより先に存在する
FreeBind はカーネルに非ローカルなアドレスへの束縛を許可させ、systemd が起動時に待ち受けソケットを作成し、アプリケーションが起動するたびにそれを渡せるようにします。これがソケットアクティベーションの狙いであり、ソケットが背後のサービスより長く生きられる理由です。
[Socket]
ListenStream=
ListenStream=10.8.0.1:8443
FreeBind=yes
空の代入は、新しい項目を追加する前にベンダーユニットから継承した待ち受け項目を消去し、残ったワイルドカードのリスナーがすべてのインターフェースで応答するのを防ぎます。アドレスとポートは自分のものに置き換え、drop-in ファイルだけでなく実効ユニットを確認してください。パッケージファイルをその場で編集するのではなく、ユニット名で drop-in を使ってください。次のパッケージ更新が編集を上書きし、意図の痕跡が残らなくなるからです。その後、ソケットユニットが期待する再読み込みと再起動の手順で適用します。
systemd のソケットのリファレンスは、このオプション背後の IPv4 と IPv6 の挙動を記述しており、重要な点はこれが経路制御ではなく束縛に適用されることです。その中にはアドレスを割り当てたり VPN を開始したりするものはありません。FreeBind はリスナーに与えられた許可であり、インターフェースの代わりではありません。
After= と Wants=:順序は準備状態ではない
順序と要件は別の軸であり、混同すると正しい順序で起動しながら失敗するユニットができます。After=vpn-client.serviceは、両方のジョブが起動した場合に、こちらがもう一方の起動を待つ、という意味だけです。VPN を引き込むことはなく、VPN の接続完了も待ちません。
Wants=やRequires=のような要件の指示は有効化を扱い、依存関係が失敗したときの挙動が異なります。一方は続行し、他方は停止します。どちらも接続済みのトンネルが何を意味するかを知りません。VPN プロセスは、アドレスが割り当てられていない状態でも、アドレスはあるがピアへの経路がない状態でも有効になり得て、どちらも依存関係を満たします。アプリケーションがアドレスの存在を必要とするなら、プロセスの起動を準備完了の証拠とみなすのではなく、その条件を明示的にモデル化してください。
systemctl catとsystemctl show -p After -p Wants -p Requiresで、ユニットが実際に何を宣言しているかを確認してください。三つの異なるディレクトリの drop-in が、書いたことのない指示を追加していることがあり、systemd は実効ユニットだけを読みます。
network-online.target がしないこと
network-online.targetの後に並べられたユニットは、ネットワークマネージャがネットワークを利用可能と宣言するのを待ちます。これは起動時の同期点であり、継続的な条件ではありません。特定のトンネルが上がっているかは何も語らず、午後に VPN が再接続しても再び発火することはありません。これを再接続の監視とみなすのが、このターゲットの最もよくある誤読です。
systemd プロジェクトはこの区別を直接文書化しており、実務上の帰結は、トンネルのアドレスを必要とするものは依存関係を自分で持たなければならないということです。network-online を待ってからトンネルのアドレスを束縛するユニットは、トンネルが偶然先に上がるときだけ正しく、それは設計ではなく偶然です。
実際に選んだライフサイクルを検証する
クリーンな起動、アドレスが現れた後の要求、VPN が落ちて戻った後の挙動を検証してください。この三つのケースが、動くリスナーと動くサービスを分けます。
systemd-analyze verify myapp.socket
systemctl cat myapp.socket
ss -ltn "sport = :8443"
最初のコマンドは再起動前にユニットファイルの誤りを捕まえ、二番目は統合されたユニットを示し、三番目はリスナーが存在するか、どのアドレスかを証明します。トンネルのアドレスを期待した場所でワイルドカードのアドレスにリスナーがあるのは、空の ListenStream が取り除くはずだった残骸そのものです。VPN の再接続後に三番目のコマンドを繰り返し、アドレスが移動したかを見てください。
ライフサイクルは意図して選んでください。安定したアドレスの復帰を待つ自由束縛のリスナーか、トンネルとともに停止し復旧時に再起動するサービスかです。これらは異なる設計であり、異なる形で失敗します。そのうえで、アクセス方針は意図した送信元と経路に結び付けたままにしてください。宛先アドレスを束縛しても、受け入れたパケットが信頼できるインターフェースから来たことにはならないからです。