sshのリバースポートフォワーディングを使うと、
- NATの内側(家庭や企業のLAN内など)に置いたRaspberryPi
- CGNのSIMでインターネットにつながっているRaspberryPi
- グローバルアドレスを持っているが固定IPではないしDynamicDNSなども使いたくないRaspberryPi
などにも任意の場所からリモートログインできるようになり非常に便利ですが、sshのオプションとsystemdのオプションをそれぞれ適切に設定しないとコネクションが切れたときにうまく復帰してくれない。
いまのところうまくいっている設定をメモしておく。
RaspberryPiの設定
- sshのコマンドラインオプションはReverse ssh tunnel を安定運用するを参考にした
-
Restart=always
でsshのプロセスがどのような終了ステータスの場合も再起動を試みる -
RestartSec
はサービス再起動までの待ち時間(秒) -
StartLimitBurst
は、サービスの再起動を停止するまでの試行回数。0に設定すると無限にサービスの起動を試みるようになる
/etc/systemd/system/ssh-rpfw.service
[Unit]
Description=ssh reverse port forwarding service
After=network.target auditd.service
[Service]
User=pi
Group=pi
WorkingDirectory=/home/pi
ExecStart=/usr/bin/ssh -oServerAliveInterval=10 -oExitOnForwardFailure=yes -oTCPKeepAlive=no -N -R 3022:127.0.0.1:22 user@example.com
Restart=always
RestartSec=1
StartLimitBurst=0
[Install]
WantedBy=multi-user.target
sshサーバの設定
- ここで言うsshサーバとは、リバースポートフォワーディングの踏み台(中継)に使うサーバのこと
- このサーバは当然RaspberryPi(前述)とsshクライアント(後述)の両方から接続ができる
- 自分はさくらVPSを使っている
アカウントの作成と公開鍵の配置
- RaspberryPiからは自動でsshが実行されるので、鍵認証が必須
sshdの設定
- なくてもいいけど、ないとTCPのタイムアウトまで次の接続ができなくなる
- 以下の設定だとRaspberryPiを停止してから2分弱くらいでTCPソケットが消えて再度接続できるようになる
/etc/ssh/sshd_config
~~~~ 前略
ClientAliveInterval 30
ClientAliveCountMax 3
~~~~ 後略
TCPの設定
前述の例では3022でLISTENしているが、3022は Registered Port なので、別の(本来このポートをLISTENするはずの)サービスがLISTENする可能性がある。
そのため、 Ephemeral Port の範囲を絞って、あいた範囲をリバースポートフォワーディングの待ち受け用ポートにしようかと思ったが、だるかったのでやめた。
(というのも、FreeBSD handbookの当該の箇所が日本語訳されていなかったので、先にドキュメントの修正をやらないといけない気持ちになってしまった)
sshクライアントの設定
- ここでいうsshクライアントとは、上記の設定をしたRaspberryPiに対してリモートログインしたいワークステーションなどのこと
- リバースポートフォワーディングのソケットは
localhost
にバインドされているので、多段sshを実行する
~/.ssh/config
Host exmaple.com
User user
Host example.com
Host raspberrypi
HostName localhost
Port 2201
User pi
ProxyCommand ssh -W %h:%p example.com
上記のraspberrypi
の設定があれば、
$ ssh raspberrypi
のみで、RaspberryPiにリモートログインできる。