追記(2022/02): 本記事の想定するユースケースでは, 長期稼働する場合 tailscale(wireguard)がよさそうです!
ただ, tailscale は sudo 権限いるようなので, sudo が使えない場合のとき(第三者のサーバやクライアント PC 使っているとか)は本記事の reverse ssh tunnel がいいかもしれません. (一応いろいろ設定すれば user 権限でもうごく. パフォーマンスも問題ないようである! https://tailscale.com/blog/throughput-improvements/)
Reverse ssh tunnel は便利な機能で, たとえばグローバル IP などで直接アクセスできない自宅 PC に外部からアクセスしたり, VPN をオフィス(仕事場環境)で使えない(が, ssh port は使える. or VPN を建てるほどの構成でない)とか, NAT 越えなどを, SSH のポートフォワーディング(の逆を使って)セキュアに接続できるという利点があります.
たとえば, 自宅の Raspberry Pi マシンへ, Reverse SSH tunneling を使い外部からアクセスするとかができます.
利用には, 何かしらグローバル IP を持つサーバ(中継サーバ)が必要になります.
+---------+ ssh -R +------------------+ ssh fw +-----------+
| home PC | ------> | global IP server | <-------- | Office PC |
+---------+ +------------------+ +-----------+
/| |
+---------------------------------------------------+ ssh login(server 経由)
このような構成になります.
Google GCP ですと, 海外拠点にはなりますが, free でインスタンスを立てることができますので, とりあえず中継サーバとして使うのも手です. 最近は Docker + コンテナ用 OS などで, サービス(ssh)だけ動かし OS は自動アップデートさせるなどで, サーバーレスっぽいのができるようになってきて便利ですね.
GCE f1-micro インスタンスを介して reverse SSH 接続する
https://qiita.com/syoyo/items/e54c2fe8525c9f68a39c
(追記 2023/02: 最近だと free で使えるのは e2-micro になってました. https://nellab.net/archives/01036/ )
海外サーバだと, レイテンシはやはりどうしてもかかってしまいますので, うまくいくのを確認したら国内の GCP リージョンなり各社の VPS サービスなど使うのがよいでしょう.
reverse ssh tunneling を実際に 3 ヶ月くらい試してみたところ, 時々繋がらなくなる現象がありました. ssh のプロセスとしては動いているようなので, どうも keep alive あたりの問題のようです.
ClientAliveInterval(サーバ側で設定, reverse ssh でログインするリモート PC)と, ServerAliveInterval(クライアント側, reverse ssh を発行する PC)はどちらかを設定すればよいようですので, sshd_config に変更を与えない ServerAliveInterval を利用してみます.
リバース SSH tunneling を発行するマシンで, ~/.ssh/conig に以下の設定をしてみました.
Host remote.com
ServerAliveInterval 60
60 秒の設定.
また, ときどき
debug1: remote port forwarding failure for listen port xxxxx
と出るので,
を参考に ExitOnForwardFailure を設定し, フォワード接続に失敗したら終了する(あとのスクリプトで再起動させるため)ように設定してみます.
Host remote.com
ServerAliveInterval 60
ExitOnForwardFailure yes
TCPKeepAlive no
TCPKeepAlive も no にしておきます.
さらに, reverse tunnel を行うスクリプトを cron 化して自動的に処理するようにします
# reverse_ssh_tunnel.sh
#!/bin/sh
COMMAND="ssh -N -f -R 2200:localhost:22 remote.com"
pgrep -f -x "$COMMAND" > /dev/null 2>&1 || $COMMAND
crontab -e で以下の行を追加します.
*/1 * * * * /bin/sh /home/username/reverse_ssh_tunnel.sh
これで, プロセスが動いていなかったら 1 分ごとに再起動されるようになります.
これにより, reverse SSH tunneling が安定して運用されます.
(まだ完全ではないが, 概ね数ヶ月は安定して動く様になりました)
TODO
-
cron ではなくて autossh や systemd(Ubuntu, CentOS client の場合)で ssh 接続を自動化・永続化する.
- CentOSでautosshをsystemd serviceとして動かす https://qiita.com/sandopan65/items/e21bdf710ac70f691e21
- バックアップとして VPN を使う(IPsec などの暗号強度の弱い VPN の利用はあまり推奨されないようなので, tailscale(wireguard)で暗号強度保ち, 最低限 ssh プロセスの再起動用の経路だけ確保にするのがよさそう) https://qiita.com/syoyo/items/f4ed1186b644dfdc8c0c