SSHポートフォワーディングしてセッションを維持しつつ多段SSHでファイル転送SSHでリモートからポートフォワーディング例えばNAT内に存在するコンピュータに対してサーバーに代理応答してもらう方法になる。この方法を使えばNAT内のコンピュータに対してサーバーを経由してアクセスすることが可能になる。このポートフォワーディングは以下のように行う。5000:host:10000-Lと比べ-Rはその意味を見失いやすい。5000はリモートホスト側のポートであり、リモートホストのこのポートにアクセスすることによりローカルホスト側にアクセスすることができるようになる。hostはローカルホストからみたポートだ。sshを実行しているコンピュータ自身に転送するのであればlocalhostだし、LANの他のコンピュータ、例えばbobにアクセスしたいのならbobになる。10000はhostのポートである。ここではSSHに対してログインさせたいので、変更していなければ22になるだろう。リモート側ポートはそのポートを開くため、1024より小さい値を指定するには特権がいる。逆にホスト側ポートは単にそのポートに転送するだけなので転送したいポートを指定する。このままだとログインしてしまうのでバックグラウンドで実行するオプション-fと、何もコマンドを実行しない-Nを組み合わせるのが一般的だ。5000:localhost:22なお、-gをつけない限りはリモートホストではループバックネットワークインターフェイスにのみバインドされるため、リモートホストに対して外部からアクセス可能になるわけではない。セキュリティを考えれば、公開はせずにSSHでサーバーにログインし、そこから転送するようにしたほうがいいだろう。接続を維持するこのままでは環境によっては入出力がないSSHセッションはすぐ切断されてしまう。そこで、このSSHセッションは維持してもらいたい。わなかったアイディア。通常のシェルスクリプトではあるプロセスに対して別のプロセスが読むことも書くこともする、ということはできない。いうことがしたい場合の方法は主にふたつ。Procfs/proc/<PID>/fd/0に対して書き込めば標準入力に入力が与えられる。このとき注意すべきは、標準入力がつながっているのが端末だと端末に書いてしまうので、標準入力はパイプにつながっている必要がある。パイプから何も入れる予定がないのであればsleepにつなぐと良いだろう。'A-Z'出力はパイプで受け取れば良い。FIFOこっちのほうが普通。FIFOを使えばそこに書かれた出力を一括して受け取れる。$fifoname複数のプロセスが書く場合はちゃんと排他制御すること。後処理を忘れないこと。リモートがぽんこんな感じでよかった。PONGdonereadの-tオプションでタイムアウトしている。30秒ごとにPINGしていて、45秒間PONGが返ってこなかったら、たぶんコネクションは死んでいる。(片方が送り続けていればいいはず)ただ、死活チェックのために返してほしい。どちらかといえば向こう側に送り続けてもらう必要がある。コネクションが切れたら確実に死んでもらおうこんな感じ。$mainpid)もしくはこんな感じ。1}Systemdでrespawnsystemdで起動させることにして、死んだら復活させてもらう。$MAINPIDRestart=alwaysenableする予定はないので、Installは省略。プロセスが死んだらRestart=alwaysなので復活する。停止するときはユニットをstopすること。ちなみに、KillModeを省略しているので、停止時にはsshもkillされる。SSHの設定SSHログインできるようにするここらへんは基本手順。~/.ssh/server_rsaこれを何らかの方法でサーバーの~/.ssh/authorized_keysに追記する。パーミッションは600であること。~/.ssh/server_rsaこれで簡単にログインできるようになった。serverこちらはログインする側の端末の設定である。コマンド専用鍵を作るまずは前項と同じように鍵を作って登録する。転送は許可しないといけないので、こんな感じ。authorized_keysのコマンド用鍵の行の先頭に以下のようなフィールドを追加する。command="/usr/local/bin/pong.sh",no-pty,no-X11-forwarding今回はno-port-forwardingしてしまうと動作しなくなる。ポートフォワーディングと、標準入出力を使ったやりとりを行うためだ。コマンドは入れなくて良い。そのコマンドしか実行できないので、勝手にそのコマンドが実行される。configファイルにはRemoteForwardの項目を入れるようにすると良いだろう。~/.ssh/server-proxy_rsaこちらはログインされる側の端末の設定。多段ログインログインする端末はサーバーにログインしたあと、SSHポートフォワーディングを利用してログインされる端末にログインする。ログインする端末から見るとSSHを二度行うことになる。このようなことはできないわけではないのだが、これだとSCPやSFTPなどは利用しづらい。できればコマンド一発で簡単にログインしたいところだ。そこで、まずはログインする側の鍵をログインされる側に登録する。これでまず、サーバーを経由せず直接に鍵認証可能な状態になる。その上で設定ファイル(~/.ssh/config)にProxyCommandとしてサーバーのSSHを経由して接続する設定を記述する。serverPortは-Rによってサーバーに開かれているポートHostNameはサーバーにログインしてから接続するものなので、localhostIdentityFileは直接のログインにも使用できるログインされる側に登録されているものProxyCommandとして先程の設定に記載したHostの値を利用するこれで外出中でもサーバーを経由して端末にログイン可能になった。複雑なので手順のまとめ本文は知識順に記述しているが、ここではミニマムな達成順で記述する。ここではログインする側の端末をlaptop、ログインされる側の端末をdesktop、サーバーをserverと呼称する。desktopで鍵を生成し、serverのauthorized_keysに登録するlaptopで鍵を生成し、serverのauthorized_keysに登録するlaptopで鍵を生成し、desktopのauthorized_keysに登録するserverで動作するPONGコマンドを作成するserver上のdesktopの鍵をPONGコマンドに結びつける。desktop上でserverに接続するためのコマンドを作成する。<READ>desktopで作成したコマンドを反復起動するためのsystemdユーザーユニットを作成するdesktopの~/.ssh/configにコマンドに結びつけられたserverにログインする設定を記述する。ポートフォワーディングも記述するlaptopの~/.ssh/configにserverへのログイン、及びdesktopに対してProxyCommandでserverを通じてログインする設定を記述するこれで準備は完了。あとはdesktopでユニットを起動し、laptopからserver経由desktopログインのsshを実行するだけ。プロセスとシグナルなど一般デスクトップユーザーは触れずにいるような基礎知識が詰まったものになり、計らずもさながら中級Linuxer認定試験のような内容になった。この記事がmagicalに見える方はぜひがんばって取り組んでいただきたいと思う。