SSHポートフォワーディングのプチ魔術

# TL;DR
とりあえず下記のコマンドを覚えること(AWS EC2を例として):

```sh
# 踏み台サーバーを使う
$ ssh -fNL 2200:target.host.com:22 -i jump-host-key.pem ec2-user@jump.host.com
$ ssh -i target-host-key.pem ec2-user@localhost -p 2200

# ダイナミックフォワーディング（なんちゃってプロキシ）
$ ssh -fND 4242 -i jump-host-key.pem ec2-user@jump.host.com
## chrome://settings/?search=プロキシ にアクセスして下記設定を行う
## プロトコール: Socks または Socks5
## サーバー: localhost:4242

# リバースフォワーディング（なんちゃってNgrok）
## サーバー側設定：
## 1. 8080を開放
## 2. /etc/ssh/sshd_config に `GatewayPorts yes` を追記
## 3. sshdを再起動
$ ssh -fNR 8080:localhost:3030 -i jump-host-key.pem ec2-user@jump.host.com
```

# 解説
## 踏み台サーバーを使う場合
![無題のプレゼンテーション_-_Google_スライド.png](https://qiita-image-store.s3.amazonaws.com/0/87438/25138ffc-1f70-cad2-6fc1-518d1e10cff6.png)

まず、上の図が示したサーバー配置があるとして、ローカルPCはサーバー `jump.host.com` にのみアクセスできる、サーバー `target.host.com` に直接アクセスできない(IP制限などがかけたとして)。
こういう場合、普通`jump.host.com`を踏み台サーバーとして、まず`jump.host.com`にログインして、そして`jump.host.com`に置かれたSSHキー`target-host-key.pem`を使って`target.host.com`にログインする。
しかしこうすると、まず、対象サーバーのキーを踏み台サーバーに置いてしまったことはセキュリティホールになりうる。そして対象サーバーにファイルをアップしたい時は一旦踏み台サーバーにファイルをアップして、そして`scp`コマンドで対象サーバーにコッピーすることになる。

下記手順を踏まえば、ローカルPCの`localhost:2200`にアクセスすることで、直接サーバー`target.host.com`にログインでき、FileZillaなどFTPクライアントも自在に使える。

### SSHトンネルの開放
```sh
$ ssh -fNL 2200:target.host.com:22 -i jump-host-key.pem ec2-user@jump.host.com
# ________ ____ __________________ ___________________________________________
#     (1)  (2)        (3)                             (4)
```

上記コマンドを軽く説明する：
1. `ssh -fNL` は `バックグラウンドモード` `ssh接続を作らない` `ローカルのポートがフォワーディング先` この三つフラグをつけた。`-N`がない場合、トンネルと別に、普通のSSHアクセスも一個立ち上がれる。`-f`がない場合、セッションはずっと使い続ける。
2. `2200` これはローカルの2200ポートをポートフォワーディング先として指定している。当然、その他使われていないポートであれば、どれでもいい。また、ローカルであるため、ホスト名を省略したが、本来は`127.0.0.1:2200`と書くべきである。
3. `target.host.com:22`は、フォワーディング元は`target.host.com`の22番ポートだよ〜と指定していた。
4. この部分は踏み台サーバー`jump.host.com`にSSHでログインする時と同じ設定、Passwordやポート指定もできる。

### SSH接続
SSHトンネルが開放できたら、`localhost:2200` が `target.host.com:22` と同じ意味持つことになる。普通にSSHログインさえすれば入れる。また、FTPクライアントに該当設定をすれば、SFTP接続もできる。

```sh
$ ssh -i target-host-key.pem ec2-user@localhost -p 2200
```

## ダイナミックフォワーディング（なんちゃってプロキシ）
IP制限をかけたサイト(例えば企業内限定ページ)を一般のPCで閲覧する場合では、~~プロ棋士~~プロキシがよく使われている。世の中有料VPNサービスやOSSのプロキシソフトはたくさんあるが、インストールするのが手間で、すぐも使いたい場合、SSHで手軽にプロキシサービスができる。

### SSHトンネルの開放
```sh
$ ssh -fND 4242 -i jump-host-key.pem ec2-user@jump.host.com
# ________ ____ ___________________________________________
#     (1)  (2)                   (4)
```
上記コマンドを軽く説明する：
1. `ssh -fND` は `バックグラウンドモード` `ssh接続を作らない` `ダイナミックフォワーディングをする`の意味である。`-D`を使えば、対象サーバーのホストやポートを指定せず、あらゆるサービスを利用できる。
2. `4242` これはローカルの4242ポートをポートフォワーディング先として指定している。もちろん、ご自由に変えられる。
3. 同じく、SSHログイン用の設定

### プロキシ設定
OSのインターネット設定のところで自力で探してもいいし、Chromeの場合、[chrome://settings/?search=プロキシ](chrome://settings/?search=プロキシ)にアクセスすればすぐ辿りつく。
![設定.png](https://qiita-image-store.s3.amazonaws.com/0/87438/1399d545-2b43-2a0c-626d-e72ed150bfd4.png)

Macの場合は下記設定で十分である。プロキシクライアントやWindowsでの設定は割愛致す。
![スクリーンショット_2019_03_06_14_13.png](https://qiita-image-store.s3.amazonaws.com/0/87438/f0d42486-8bc4-9137-5b35-c34e4235f85d.png)

設定がうまく行けば、ウェブサイトに提示されたIPアドレスは`jump.host.com`のアドレスになっているはず。
![アクセス情報【使用中のIPアドレス確認】.png](https://qiita-image-store.s3.amazonaws.com/0/87438/3a6c870f-b0f7-c756-6241-4fa8ea8b0efe.png)

理論上、某大国のインターネット遮断に対抗することも期待できるが、その時はAWSじゃなくて、サクラなどレンタルサーバーがいいと思う。AWSのIPが時々遮断されるという噂があったためである。

## リバースフォワーディング（なんちゃってNgrok）
[Ngrok](https://ngrok.com/)はローカルのサイトを一時的にインターネット上に公開できるサービスである。昔からお世話になっている。しかしNgrokは有料サービスを購入しない限り、起動するたび、ランダムのURLが発行されて、しかも１アカウントは同時１サービスしか公開できない。Ngrok1はOSSであるため、時に自前のNgrokサーバーを立てる記事が見られるが、どれも面倒で失敗しそう。実はSSHを使えば同じ程度のことができる。

### サーバー側のSSH設定
デフォルトの場合、リバースフォワーディングの一部の機能は制限されていた。まずこの制限を解除しないといけない。

- `sshd_config`を編集

```sh
$ sudo vim /etc/ssh/sshd_config
```

- `GatewayPorts yes`にする

```config:/etc/ssh/sshd_config
...
GatewayPorts yes
...
```
- sshdを再起動(OSによってコマンドが変わる場合がある)

```sh
$ sudo /etc/rc.d/init.d/sshd restart
```

必要があれば、EC2のセキュリティグループにフォワーディング先のポートを開放(今回は８０８０)

### SSHトンネルの開放
```sh
$ ssh -fNR 8080:localhost:3030 -i jump-host-key.pem ec2-user@jump.host.com
# ________ ____ ______________ ___________________________________________
#     (1)  (2)      (3)                             (4)
```

上記コマンドを軽く説明する：
1. `ssh -fNR` は `バックグラウンドモード` `ssh接続を作らない` `リモートのポートがフォワーディング先`である。
2.  リモートのフォワーディング先、ホスト名はログインホストと一緒なので省略したが、本当は`jump.host.com:8080`や`*:8080`が正しい。
3.  ローカルのフォワーディング元を指定、今回は`3030`。
4.  同じく、SSHログイン用の設定

設定が完了すれば、`jump.host.com:8080`では`localhost:3030`と同じサイトが見れる。

PS: ポート80や443を使いたい場合、予めサーバーにNginxやApacheとかを入れて、8080をlistenするといい。rootユーザーじゃないと1000番以下は使えないからである。

## 余談
上記SSHトンネルコマンドは全部`-f`を入れており、バックグラウンドで動いている。それらのトンネルを終了したい場合、該当ポートを使用しているプロセスを`kill`すればいい。

```sh
$ sudo lsof -i:2200
COMMAND     PID
ssh       65924

$ kill 65924
```

## TODO
これらの手法をHerokuでも使ってみること。

# 参考
## SSHポートフォワーディング系
https://qiita.com/Ayaka14/items/449e2236af4b8c2beb81
http://www14.plala.or.jp/campus-note/vine_linux/server_ssh/ssh_portforwarding.html
[中国語]https://blog.twofei.com/528/
[中国語]https://blog.csdn.net/evandeng2009/article/details/51926797
[中国語]http://www.sohu.com/a/161797470_468694

## SSH設定系
https://qiita.com/FGtatsuro/items/e2767fa041c96a2bae1f
https://orebibou.com/2014/10/sshサーバsshd再起動の方法（os別）/

## その他
https://utano.jp/entry/2016/07/mac-and-linux-process-using-port-check-lsof/
https://devcenter.heroku.com/articles/exec