特に自宅にサーバーを立てているときに外部回線経由でSSHアクセスしたいのだけれども…というときはたまにあります。ただ、その回線によっては特定のポートへの通信しか許可しない、といった設定となっている環境も多いようで、格安SIM経由の通信でもそういうことが起こりうるようです。そうなると何らかの理由で自宅サーバーの環境を変更したい、といったことや自宅サーバー経由で内部にあるメインマシンにリモートデスクトップでアクセスしてごにょごにょ、なんていうことも生まれてくるでしょう。そういうときに効果を発揮する対策です。
先に書いておきますとこのsslhを使った方法は自宅サーバーなどプライベートなサーバーに設定するにはかなり有用なのですがある問題点のためにHTTPSでWebページを公開しているようなサーバーには設定すべきではないと考えています。その点については後ほど。(なのでこのblogがあるWebサーバーのwww.timbreofprogram.infoには設定されていません)
sslhとは
適当に検索していると出てきたとあるプログラムです。基本的には軽量のプロキシサーバーと考えればOKです。ただし、対応している通信の種類として暗号通信系が入っているので今回の用途には最適ということが特徴となっています。プロキシとして使うことができる通信が(私がインストールした環境で有効になっているものとして
- ssh
- openvpn
- tinc
- xmpp
- http
- ssl
- tls
- adb
- anyprot
となっていました。今回はこの中のsshとsslが対象になります。使い方によってはそのほか(openvpnなど)も設定するといろいろと使えるかもしれません。
sslhのインストール
パッケージが用意されているようなLinuxのディストリビューション(今回試したのはFedora系)であればパッケージのインストール作業でOKです。私の場合はインストール作業
$ sudo dnf install sslh
だけでした。パッケージがない場合はソースコードをダウンロードしてコンパイルします。基本的には単一のプログラム(設定ファイルを作るor起動時にオプションとして与える)だけですのでコンパイル後は/usr/local/以下にプログラムを置くように設定すればOKです。パッケージからインストールした場合は大体設定ファイルが別の場所におかれます。Fedora系では/etc/sysconfig/sslhに起動時のオプションを設定するファイル(単に設定ファイルを参照するように書かれている)があり、/etc/sslh.cfgに実際の設定ファイルが置かれます。
sslhの設定
まずはsslhの設定から。sslh.cfgを編集して自サーバーに来たPort443への通信を受け付けられるようにしてsslが来た場合はlocalhostのPort443へ、sshが来た場合はlocalhostのPort22へ流すようにします。設定ファイルはこんな感じ。中にあるIPは自サーバーのIPもしくは自サーバー内でDNS処理を行ったとき自サーバーのIPとなるような名前を設定します。例では192.168.0.2としておきます。
listen: ( { host: "192.168.0.2"; port: "443"; } ); protocols: ( { name: "ssh"; service: "ssh"; host: "localhost"; port: "22"; }, { name: "ssl"; host: "localhost"; port: "443"; log_level: 0; } );
設定ファイルの場合は括弧の種類やカンマ、セミコロンを間違えるとSyntax Errorで起動できません。
また、パッケージインストールの場合は丁寧なファイルがついてくるので編集は簡単ですがプログラムを直接起動する場合は引数として与える必要があります。その場合のコマンドラインは
--user sslh --listen 192.168.0.2:443 --ssh localhost:22 --ssl localhost:443
のようになります。これを設定してdaemonを起動…だけでは無理ですよ。
httpd(Apache)からhttps側のlistenをlocalhostのみに変更
たいていの場合Port443は自宅サーバーとして起動している場合だとApacheがListenしているはずです。その場合はApacheのListenを変更しないとsslhがPort443をListenできなくなってしまいますので注意です。設定変更はApacheのsslを設定している場所(Fedora系の場合は/etc/httpd/conf.d/ssl.conf)に対して
# # When we also provide SSL we have to listen to the # the HTTPS port in addition. # #Listen 443 https Listen localhost:443 https
とした上で再起動をします。これをしておかないとlocalhost以外のListenがされたままになるのでsslhがPort443をListenできない、ということになってしまいます。またsslhからApacheにhttpsの接続を流すこともできなくなるので注意です。もちろん、ApacheのListenするポートを443から別のポートに変えてsslhから接続するポートの設定を変える、というのもありかもしれません。プライベートサーバーならそういったことも考えてみるとよいかもしれません。
sslhをsystemctlから起動
Fedora系でパッケージインストールした場合は
$ sudo systemctl start sslh
で起動できます。サービスとしてサーバー起動時に自動起動させるときは
$ sudo systemctl enable sslh
も実行しておきましょう。また、サービスがちゃんと起動できたかどうかステータスの確認をしておきましょう。失敗しているときは設定ファイルやPort443で競合していないかどうかを調べるとよいと思います。
各サービスへの接続チェック
Port443に外部から接続してそれぞれに接続できているかをチェックします。これは設定したサーバー内だとうまくいきませんので注意しましょう。sshはTeraTermなどから、sslはブラウザでアクセスしてみればわかりますね。
sshとssl(https)以外にもいろいろと設定してみると使えるかも
見た感じでは使えそうなのはopenvpnですね。vpn接続を行うことができればサーバーのイントラネットへアクセスできるのでスマートフォンからでもいろいろとできることはあると思います。まあ同等の機能としてsshのポート転送を組み合わせてなんとかするのありだとおもいます。Androidのアプリでもポート転送を行うことができるものはありますのでそれを使うとssh単体以外にもリモートデスクトップでWindowsを操作する、といった活用も考えられると思います。
ちなみにこれを設定した後で直接sshのポートに接続できないとある外部のネットワークからssh接続をかけてみるとなんとうまくいきました。格安SIMでもVPN接続を行わずに接続できた(というより格安SIM経由だと接続ができなかったことが今回のテストで初めてわかった、ということでもあります)のでこのシステムはかなり有用そうだな~というところです。
接続ログがちょっと微妙
少し問題なのがこのsslhが基本的にはproxyである、ということです。つまり接続先の各サービス(この場合はsshとhttpd)には接続ログとして「自ローカルIPからアクセスがあった」というログだけが残ってしまい、元々どのIPからアクセスがあったか(サーバーに何らかの攻撃があったか)という情報がつかみづらくなる、ということになるからです。設定ファイルのオプションを見る限りhttpsに関してはなんとかなる可能性はありそうですがssh側はそうはいかないようです。これがプライベートなサーバー以外で設定をしない方がよい、という理由となります。
プライベートサーバーに設定しておくと外出時などで使える
まあ、これが結論ですね。Port443はhttpsのポートなのでプライベートサーバーであればダミーを用意しておいてそれを公開する「ふり」をしておいてもう一方でsshを有効にしておけば自宅にデータを忘れてきた、というときやメインマシンで何かやる指示を外部から出せるというのはありがたいと思います。