sslhでポート443を共有しOpenVPN・SSH・Webを1つに集約
はじめに
自宅サーバーで Web サイト以外に SSH や VPN など、複数のサービスを外部から利用したいと考えたことはありませんか? しかし、サービスごとにポートを分けると管理が煩雑になり、セキュリティの観点からも公開ポートは最小限に抑えたいものです。さらに、外出先のフリー Wi-Fi 環境では 443 番ポート(HTTPS) 以外の通信が許可されていないケースも少なくありません。
このような課題を解決するのが、今回紹介する「sslh」です。sslh は、単一のポート(ここでは 443 番)で受け取ったトラフィックを、そのプロトコルに応じて適切なバックエンドサービスに振り分けてくれる、非常に便利なプロトコルマルチプレクサです。
この記事では、sslh を活用し、OpenVPN、SSH、Web サービス(nginx)をすべて 443 番ポートに集約する方法を、Docker Compose を用いてスマートに実現する手順を解説します。
全体構成図
今回構築するシステムの全体像は以下の通りです。外部からのすべてのアクセスはまず sslh に届き、そこから各サービスへとインテリジェントに転送されます。
(インターネット)
|
| <--- TCP 443番ポートへのアクセス
|
+-----------------------------+
| ルーター / ファイアウォール |
| (ポートフォワーディング: 443) |
+-----------------------------+
|
|
+-----------------------------+
| Docker ホスト |
| |
| +-----------------------+ |
| | sslh コンテナ | | <--- すべてのトラフィックを最初に受け取る
| | (ポート 443 をリッスン) | |
| +-----------------------+ |
| | | | |
| (プロトコル判定) | | (プロトコル判定) |
| | | | |
| +---+ +---+ +----+
| | | | |
| v v v |
| +---------+ +---------+ +---------+
| | nginx | | sshd | | OpenVPN |
| |コンテナ | |(ホストOS)| |コンテナ |
| +---------+ +---------+ +---------+
| |
+-----------------------------+
sslh とは? - プロトコルマルチプレクサの仕組み
sslh は「プロトコルマルチプレクサ(Protocol Multiplexer)」と呼ばれるツールの一種です。
- マルチプレクサ (Multiplexer): 日本語で「多重化装置」。複数の信号をまとめて一つの伝送路で送るための装置や技術を指します。
クライアントからの接続時、sslh は通信パケットの最初の数バイトを検査します。例えば、SSH 接続であれば SSH-2.0...
といった特徴的な文字列が、TLS/SSL(HTTPS や OpenVPN など)接続であれば固有のバイナリパターンが含まれています。sslh はこれらのシグネチャを識別し、「これは SSH」「これは TLS/SSL」といった判断を下し、あらかじめ設定されたサーバー(コンテナ)へトラフィックを透過的に転送(フォワード)します。
この仕組みにより、外部からは単一のポートにアクセスしているように見えながら、内部では全く異なるサービスを動かすことが可能になるのです。
Docker Compose による環境構築
それでは、Docker Compose を使って環境を構築しましょう。以下の 3 つのサービスを 1 つの docker-compose.yml
ファイルで管理します。
sslh
: 中核となるプロトコルマルチプレクサnginx
: Web サーバー(HTTPS 通信担当)openvpn
: OpenVPN サーバー
なお、SSH サーバー(sshd)は、コンテナではなくホスト OS 上で直接稼働しているものを想定しています。
docker-compose.yml の作成
以下が docker-compose.yml
の全体像です。各サービスについては後ほど詳しく解説します。
services:
sslh:
image: ghcr.io/yrutschle/sslh:latest
container_name: sslh
ports:
- "443:443"
command: >
--foreground
--listen=0.0.0.0:443
--tls=nginx:443
--ssh=host.docker.internal:22
--openvpn=openvpn:1194
environment:
TZ: Asia/Tokyo
restart: always
extra_hosts:
- "host.docker.internal:host-gateway"
depends_on:
- nginx
- openvpn
nginx:
container_name: nginx
image: nginx:latest
restart: always
environment:
TZ: Asia/Tokyo
openvpn:
container_name: openvpn
image: openvpn/openvpn-as:latest
restart: unless-stopped
cap_add:
- NET_ADMIN
- MKNOD
devices:
- /dev/net/tun
environment:
TZ: Asia/Tokyo
各サービスの詳細解説
1. sslh サービス
ports: ["443:443"]
: これが唯一、外部(インターネット)に公開するポートです。ホストマシンの 443 番ポートに来た通信を、すべてこのコンテナが受け取ります。command
: sslh の挙動を決定する重要な部分です。--listen 0.0.0.0:443
: コンテナ内の 443 番ポートで待ち受けます。--ssh host.docker.internal:22
: SSH と判断した通信を、ホスト OS の 22 番ポートに転送します。host.docker.internal
はコンテナからホスト自身を指すための特別な DNS 名で、extra_hosts
の設定により有効化しています。--tls nginx:443
: SSL/TLS と判断した通信を、nginx
コンテナの 443 番ポートに転送します。--openvpn openvpn:1194
: OpenVPN と判断した通信を、openvpn
コンテナの 1194 番ポートに転送します。
depends_on
:nginx
とopenvpn
が起動してからsslh
が起動するように、サービスの依存関係を定義します。
2. nginx サービス
Web サーバーです。ports
の定義がない点に注目してください。これにより、コンテナは外部から直接アクセスできず、sslh
経由のトラフィックのみを受け付けるため、セキュリティが向上します。
3. openvpn サービス
OpenVPN サーバーです。これも ports
は非公開です。OpenVPN Access Server のより詳しい設定方法はこちらの記事などを参考にしてください。
サービスの起動
設定が完了したら、以下のコマンドで全サービスをバックグラウンドで起動します。
docker-compose up -d
外部からの動作確認方法
サーバーのグローバル IP アドレスまたは設定したドメイン名を your-domain.com
として、以下の方法で各サービスに接続できるか確認します。
-
Web (HTTPS):
ブラウザでhttps://your-domain.com
にアクセスし、Nginx のデフォルトページが表示されれば成功です。curl
コマンドでも確認できます。curl https://your-domain.com
-
SSH:
ssh
コマンドの-p
オプションでポートを 443 に指定します。ssh [email protected] -p 443
-
OpenVPN:
クライアント用の設定ファイル(.ovpn
)を開き、remote
ディレクティブを以下のように変更します。# 変更前 proto tcp remote your-domain.com port 1194 # 変更後 proto tcp remote your-domain.com port 443
ポートを
1194
から443
に変更するのがポイントです。この設定ファイルを使って OpenVPN クライアントから接続できれば成功です。
セキュリティに関する考慮事項
この構成は非常に便利ですが、単一のポートにサービスを集約するからこそ、セキュリティには一層の注意が必要です。
- SSH のパスワード認証無効化: 必ず公開鍵認証のみを許可するように
sshd_config
を設定してください。 - Fail2Ban の導入: SSH へのブルートフォースアタック(総当たり攻撃)を防ぐため、
fail2ban
のような侵入防止ソフトウェアの導入を強く推奨します。 - 強力なパスワードと鍵: OpenVPN の証明書や SSH の鍵、その他サービスで利用するパスワードは、すべて推測困難で強力なものを利用してください。
- 定期的なアップデート:
docker-compose pull
コマンドを定期的に実行し、各コンテナのイメージを最新の状態に保ち、既知の脆弱性からシステムを保護してください。
まとめ
今回は、sslh と Docker Compose を使い、443 番ポートという一般的に開放されているポートに Web、SSH、OpenVPN の 3 つのサービスを集約する方法を解説しました。これにより、どんなネットワーク環境からでも自宅サーバーに安全かつスマートにアクセスするための、強力なエントリーポイントを構築できます。
公開するポートを最小限にすることは、サーバーセキュリティの基本です。ぜひこのテクニックを活用して、より安全で便利な自宅サーバー環境を構築してみてください。