HTTPS-PORTALは、Nginx、Let's Encrypt、および Dockerを利用した、完全自動化されたHTTPSサーバーです。 これを使用することで、追加の設定を1行だけ加えることで、既存のWebアプリケーションをHTTPS上で動作させることができます。
SSL証明書は、Let's Encryptから自動的に取得および更新されます。
Docker Hubページ: https://hub.docker.com/r/steveltn/https-portal/
翻訳者注意:このドキュメントは 2023年11月26日(rev: 1a4f095494616591dd6c701f3a14f738a2e8ebe8)のコミットを元に翻訳しています。最新のドキュメントと相違がある可能性があります。必要に応じて、最新のドキュメントを参照してください。
HTTPS-PORTALはDockerイメージとして提供されます。これを使用するには、以下の条件を満たすLinuxマシン(ローカルまたはリモートホスト)が必要です:
- 80番および443番ポートが利用可能で公開されていること。
- Docker Engineがインストールされていること。さらに、Docker Composeの使用を強く推奨します。これにより操作が容易になります。当ドキュメントの例は主にDocker Composeフォーマットで示されています。
- 以下の例で使用するすべてのドメインが、そのマシンに解決されること。
Dockerに関する知識は必須ではありませんが、HTTPS-PORTALを使用するにはある程度の知識があると良いでしょう。
以下の内容で任意のディレクトリにdocker-compose.yml
ファイルを作成してください:
version: '3'
services:
https-portal:
image: steveltn/https-portal:1
ports:
- '80:80'
- '443:443'
environment:
DOMAINS: 'example.com'
# STAGE: 'production' # ステージングが正常に動作するまでは本番環境を使用しないでください
volumes:
- https-portal-data:/var/lib/https-portal
volumes:
https-portal-data: # HTTPS-PORTALをアップグレードする際に再署名を避けるために推奨されます
同じディレクトリでdocker-compose up
コマンドを実行してください。
しばらくすると、https://example.comでウェルカムページが稼働します。
こちらはより実践的な例です:別のディレクトリでdocker-compose.yml
ファイルを作成してください:
version: '3'
https-portal:
image: steveltn/https-portal:1
ports:
- '80:80'
- '443:443'
restart: always
environment:
DOMAINS: 'wordpress.example.com -> http://wordpress:80'
# STAGE: 'production' # ステージングが機能するまで本番環境を使用しないでください
# FORCE_RENEW: 'true'
volumes:
- https-portal-data:/var/lib/https-portal
wordpress:
image: wordpress
db:
image: mariadb
environment:
MYSQL_ROOT_PASSWORD: '<a secure password>'
volumes:
https-portal-data:
docker-compose up -d
コマンドを実行してください。しばらくすると、https://wordpress.example.comでWordPressが稼働します。
上記の例では、https-portal
セクションの環境変数のみがHTTPS-PORTALに関する設定です。今回は追加のパラメーター-d
を使用しました。これにより、docker-compose.yml
で定義されたアプリケーションをバックグラウンドで実行するようDocker Composeに指示します。
注記:
- デフォルトでは
STAGE
はstaging
で、これはLet's Encryptからのテスト用(信頼されていない)証明書を意味します。 wordpress
はHTTPS-PORTALコンテナ内のWordPressコンテナのホスト名です。通常はWordPressコンテナのサービス名を使用できます。
HTTPS-PORTALをローカルであなたのアプリケーションスタックと一緒にテストすることができます。
https-portal:
# ...
environment:
STAGE: local
DOMAINS: 'example.com'
この操作を行うことで、HTTPS-PORTALは自己署名証明書を生成します。 この証明書はブラウザに信用される可能性は低いですが、docker-composeファイルのテストには使用できます。 あなたのアプリケーションスタックとの互換性があることを確認してください。
HTTPS-PORTALは、composeファイルで指定したexample.com
にのみ応答することに注意してください。
HTTPS-PORTALがあなたの接続に応答するようにするためには、次のいずれかを行う必要があります:
hosts
ファイルを変更して、example.com
があなたのdockerホスト(127.0.0.1やその他のDockerホストを指すIPアドレス)に解決されるようにします。
または
- コンピューターやルーターにDNSMasqを設定します。この方法はより柔軟性があります。
または
docker-compose.yml
のDOMAINS: 'example.com'
を'mysite.lvh.me'
に変更します(lvh.meは任意の第二レベル名を127.0.0.1に解決するワイルドカードDNSエントリです)。これにより、https://mysite.lvh.me にアクセスできるようになります。
テストが完了したら、アプリケーションスタックをサーバーにデプロイできます。
HTTPS-PORTALはの迅速なリダイレクションのセットアップをサポートしています。
https-portal:
# ...
environment:
DOMAINS: 'example.com => https://target.example.com' # 通常の「->」ではなく「=>」であることに注意してください
すべてのパスはターゲットにリダイレクトされます。例えば、https://example.com/foo/bar
は307リダイレクトで https://target.example.com/foo/bar
になります。
永続的なリダイレクションを望む場合は、環境変数 REDIRECT_CODE=301
を設定してください。
一般的な使用例としては、www.example.com
を example.com
にリダイレクトすることがあります。DNSを設定し、www.example.com
と example.com
の両方がHTTPS-PORTALホストに解決されるようにして、以下のcomposeを使用してください:
https-portal:
# ...
environment:
DOMAINS: 'www.example.com => https://example.com' # 通常の「->」ではなく「=>」であることに注意してください
警告: この機能の使用は、絶対に必要な場合を除いて強くお勧めしません。Dockerソケットをコンテナに公開する(:ro
であっても)ことは、基本的にホストOSへのルートアクセス権をコンテナに与えることになります。それでも使用する場合は、ソースコードを慎重に確認してください。詳細
HTTPS-PORTALは、Docker APIソケットがコンテナ内でアクセス可能である限り、同じホスト上で実行中の他のDockerコンテナを発見することができます。
これを可能にするためには、以下のdocker-compose.yml
を使用してHTTPS-PORTALを起動します。
version: '2'
services:
https-portal:
# ...
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro # 危険、上記の警告を参照してください
そして、以下のように一つまたは複数のウェブアプリケーションを起動します:
version: '2'
services:
a-web-application:
# ...
environment:
# tell HTTPS-PORTAL to set up "example.com"
VIRTUAL_HOST: example.com
注意点: あなたのウェブアプリケーションは、HTTPS-PORTALと同じネットワーク内で作成される必要があります。
ここで、ウェブサービスをHTTPS-PORTALにリンクする必要はありませんし、HTTPS-PORTALの環境変数DOMAINS
にexample.com
を設定すべきではありません。
この機能により、同じホスト上に複数のウェブアプリケーションをデプロイすることができます。 HTTPS-PORTAL自体を再起動したり、ウェブアプリケーションを追加/削除する間に他のアプリケーションを中断することなく行えます。
ウェブサービスが複数のポートを公開している場合(ウェブサービスのDockerfileでポートが公開されている可能性があります)、環境変数VIRTUAL_PORT
を使用してHTTPリクエストを受け入れるポートを指定します:
a-multi-port-web-application:
# ...
expose:
- '80'
- '8080'
environment:
VIRTUAL_HOST: example.com
VIRTUAL_PORT: '8080'
もちろん、コンテナ発見はENVで指定されたドメインと組み合わせて機能します:
https-portal:
# ...
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro # DANGEROUS, see the warning above
environment:
DOMAINS: 'example.com -> http://upstream'
Dockerコンテナではなくホストマシン上で直接実行されるウェブアプリケーションはhost.docker.internal
で利用可能です。これはDocker for MacやDocker for Windowsでも動作します。
例えば、アプリケーションがホストマシンの8080ポートでHTTPリクエストを受け入れる場合、HTTPS-PORTALは以下のように起動できます:
https-portal:
# ...
environment:
DOMAINS: 'example.com -> http://host.docker.internal:8080'
ufwのようなファイアウォールを使用している場合、コンテナからDockerホストマシンへの通信を許可する必要があるかもしれません。
ufwがアクティブかどうかは、ufw status
を実行して確認できます。
コマンドがactive
と返した場合、HTTPS-PORTALのコンテナIPからDockerホストIPのウェブアプリケーションがアクセス可能なポートへの8080ポートでの通信を許可するufwルールを追加します:
DOCKER_HOST_IP=`docker network inspect code_default --format='{{ .IPAM.Config}}' |awk '{print $2}'` # ネットワークがcode_defaultという名前であると仮定します。
HTTPS_PORTAL_IP=`docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' code_https-portal_1` # コンテナの名前がcode_https-portal_1であると仮定します。
ufw allow from $HTTPS_PORTAL_IP to $DOCKER_HOST_IP port 8080
コンマで区切ることで複数のドメインを指定できます:
https-portal:
# ...
environment:
DOMAINS: 'wordpress.example.com -> http://wordpress:80, gitlab.example.com -> http://gitlab'
また、各サイトのステージ(local
、staging
、またはproduction
)を指定することもできます。個々のサイトのステージはグローバルステージを上書きすることに注意してください:
DOMAINS: 'wordpress.example.com -> http://wordpress #local, gitlab.example.com #staging'
ロードバランシングやHA(高可用性)のために、ドメインに複数のアップストリームを定義することが可能です。 パイプ区切りで追加のアップストリームを追加してください。各アップストリームにはカスタムパラメータを設定できます。
https-portal:
# ...
environment:
DOMAINS: 'wordpress.example.com -> http://wordpress1:80|wordpress2:80[weight=2 max_conns=100]
利用可能なパラメータについては、Nginx Upstream-Moduleを参照してください。
ウェブアプリケーションにリクエストを転送する代わりに、HTTPS-PORTALは直接(複数の)静的サイトを提供することもできます:
https-portal:
# ...
environment:
DOMAINS: 'hexo.example.com, octopress.example.com'
volumes:
- https-portal-data:/var/lib/https-portal
- /data/https-portal/vhosts:/var/www/vhosts
HTTPS-PORTALが起動されると、ホストマシン上の/data/https-portal/vhosts
ディレクトリ内に、各仮想ホストのための対応するサブディレクトリが作成されます:
/data/https-portal/vhosts
├── hexo.example.com
│ └── index.html
└── octopress.example.com
└── index.html
このディレクトリ階層にあなた自身の静的ファイルを配置できますが、上書きされることはありません。ホームページとして提供されるindex.html
が必要です。
任意のホストディレクトリを/var/lib/https-portal
にdata volumeとしてマウントすることができます。
例えば:
https-portal:
# ...
volumes:
- /data/ssl_certs:/var/lib/https-portal
これで、証明書はホストの/data/ssl_certs
に利用可能になります。
HTTPベーシック認証は簡単に設定できます。ウェブサイトをオンラインにはしたいが、準備が整うまで一般公開したくない場合に便利です。
docker-composeファイルでの設定方法:
https-portal:
# ...
environment:
DOMAINS: 'username:[email protected] -> <upstream>'
注意:Docker for MacやDocker for Windowsでは、アクセス制限が意図したとおりに機能しない場合があります。これらのシステムでは、Dockerは基本的にVM(仮想マシン)内で実行されるため、リクエスト元のIPはプロキシサービスのIPになります。
IPアクセス制限を有効にして、ウェブサイトを保護することができます。環境変数 ACCESS_RESTRICTION
を使用して全体的な制限を指定することができます。加えて、各ウェブサイトに個別の制限を設けることも可能です。
全体的な制限を使用した例:
https-portal:
# ...
environment:
ACCESS_RESTRICTION: "1.2.3.4/24 4.3.2.1"
個別の制限を使用した例:
https-portal:
# ...
environment:
DOMAINS: "[1.2.3.4/24] a.example.com -> <upstream> , [1.2.3.4/24 4.3.2.1] b.example.com"
自動発見の例:
https-portal:
# ...
my_app:
image: ...
environment:
VIRTUAL_HOST: "[1.2.3.4] example.com"
有効なIP値については、Nginx allowを参照してください。
デフォルトではNginxのアクセスログは書き込まれず、エラーログはstdoutに書き込まれ、Dockerによってキャプチャされます。これらを設定するいくつかのオプションがあります:
-
エラーログ/アクセスログをstdout/stderrにリダイレクトする:
https-portal: # ... environment: ERROR_LOG: stdout ACCESS_LOG: stderr
-
ログをデフォルトの場所に書き込む:
https-portal: # ... environment: ERROR_LOG: default ACCESS_LOG: default volumes: - https-portal-data:/var/lib/https-portal - /path/to/log/directory:/var/log/nginx/ - /path/to/logrotate/state/directory:/var/lib/logrotate/
デフォルトのログファイルのパスは
/var/log/nginx/access.log
と/var/log/nginx/error.log
です。デフォルトの場所
/var/log/nginx/*.log
にあるログファイルは毎日ローテーションされます。 HTTPS-PORTALは最大30個のログファイルを保持し、2日以上経過したファイルは圧縮されます (現在の日と前日のログはプレーンテキストで利用可能で、それ以前のものは圧縮されます)。ログローテーションの設定を変更したい場合は、
/etc/logrotate.d/nginx
を上書きできます。 -
カスタムの場所にログを書き込む:
https-portal: # ... environment: ERROR_LOG: /var/log/custom-logs/error.log ACCESS_LOG: /var/log/custom-logs/access.log volumes: - https-portal-data:/var/lib/https-portal - /path/to/log/directory:/var/log/custom-logs/
この場合、自動的なログローテーションは行われないことに注意してください。
-
その他の環境変数:
ロギングに関する他の設定可能な環境変数もあります:
ACCESS_LOG_BUFFER
- アクセスログのバッファサイズを制御します。例:16k。ERROR_LOG_LEVEL
- エラーログのレベルを制御します。デフォルト値はerror
です。
環境変数 DEBUG=true
を設定すると、ドメイン解析に関するより詳細な情報が表示されます。例えば:
DEBUG: name:'example.com' upstreams:'' redirect_target:''
デフォルトでは、HTTPS-PORTALは証明書の有効期限の約30日前に証明書を更新します。これをカスタマイズするには:
RENEW_MARGIN_DAYS=30
ドメインにASCII以外の文字が含まれている場合は、HTTPS-PORTALを使用する前にASCII互換エンコーディング(ACE)形式に変換してください。
Nginxのデフォルトパラメータを変更する必要がある場合、Nginxを設定するために使用できる追加の環境変数がいくつかあります。
これらは通常 nginx.conf
に設定するオプションに対応しています。
利用可能なパラメータとそのデフォルト値は以下の通りです:
INDEX_FILES=index.html # 探索するインデックスファイル名のスペース区切りリスト
WORKER_PROCESSES=1
WORKER_CONNECTIONS=1024
KEEPALIVE_TIMEOUT=65
GZIP=on # 'off'にすることもできます(クオートが必要です)
SERVER_TOKENS=off
SERVER_NAMES_HASH_MAX_SIZE=512
SERVER_NAMES_HASH_BUCKET_SIZE=32 # CPUに基づいて32または64にデフォルト設定されます
CLIENT_MAX_BODY_SIZE=1M # 0はリクエストボディサイズのチェックを無効にします
PROXY_BUFFERS="8 4k" # プラットフォームに応じて4kまたは8k
PROXY_BUFFER_SIZE="4k" # プラットフォームに応じて4kまたは8k
RESOLVER="カスタムソルバー文字列"
PROXY_CONNECT_TIMEOUT=60;
PROXY_SEND_TIMEOUT=60;
PROXY_READ_TIMEOUT=60;
ACCESS_LOG=off;
ACCESS_LOG_INCLUDE_HOST=off; # アクセスログにvhostを含める(goaccess用 => log-format=VCOMBINEDを使用)
REDIRECT_CODE=307 # 1.20.1まではデフォルトで301でした
追加することができます
WEBSOCKET=true
HTTPS-PORTALがWEBSOCKET接続をプロキシするように設定します。
nginxのDNSキャッシュを回避するために、動的アップストリームを有効にする
RESOLVER="127.0.0.11 ipv6=off valid=30s"
DYNAMIC_UPSTREAM=true
以下の環境変数を使用して、HSTSヘッダーを設定できます。
警告: 希望の高いmax_age値に設定する前に、低い値でテストしてください。一度このヘッダーを送信すると、訪れたすべてのクライアントはHTTPへのダウングレードを拒否します。その結果、ウェブサイトをHTTPにフォールバックすることは不可能になります。
HSTS_MAX_AGE=60 # in seconds
注意: IPv6はLinuxホストでのみサポートされています。
以下の変数を使用してIPv6接続を有効にできます:
LISTEN_IPV6=true
各ドメインに追加のserver
ブロックレベルの設定を追加できます:
environment:
...
CUSTOM_NGINX_SERVER_CONFIG_BLOCK: add_header Strict-Transport-Security "max-age=60" always;
また、複数行にすることもできます:
environment:
...
CUSTOM_NGINX_SERVER_CONFIG_BLOCK: |
add_header Strict-Transport-Security "max-age=60" always;
auth_basic "Password";
変数を使用する場合、それらを$でエスケープする必要があります:
environment:
...
CUSTOM_NGINX_GLOBAL_HTTP_CONFIG_BLOCK: |
limit_req_zone $$binary_remote_addr zone=one:10m rate=1000r/m;
CUSTOM_NGINX_SERVER_CONFIG_BLOCK
は、「環境変数を通じてNginxを設定する」セクションに記載されている他のすべての設定ブロックの後に挿入されますが、他の設定と競合する可能性があります。
全ての設定に適用されるグローバルなCUSTOM_NGINX_SERVER_CONFIG_BLOCK
に加えて、特定のサイトの設定ファイルにのみ挿入されるCUSTOM_NGINX_<大文字とアンダースコアで区切られたドメイン名>_CONFIG_BLOCK
があります。例えば、example.com
にのみ特定の変更を加えるには、環境変数CUSTOM_NGINX_EXAMPLE_COM_CONFIG_BLOCK
を作成します。
# generated Nginx config:
server {
listen 443 ssl;
... # (other configurations)
<%= CUSTOM_NGINX_SERVER_CONFIG_BLOCK %>
<%= CUSTOM_NGINX_<DOMAIN_NAME>_CONFIG_BLOCK %>
location / {
...
}
}
変数CUSTOM_NGINX_GLOBAL_HTTP_CONFIG_BLOCK
およびCUSTOM_NGINX_SERVER_PLAIN_CONFIG_BLOCK
は、Nginxのステートメントをグローバルなhttp
ブロックや平文(非SSL)のserver
ブロックに追加するために使用できます。
まれに/.well-known/acme-challenge/
のリクエスト処理を変更したい場合は、ACME_CHALLENGE_BLOCK
を設定することでデフォルトの設定が上書きされます。詳細はNginx設定テンプレートをご覧ください。
環境変数は、ファイル/var/lib/https-portal/dynamic-env
の変更を通じて動的に上書きされることができます。ファイルの名前と内容は、それぞれ環境変数の名前と内容を作成します。最後の変更から約1秒後、変更された設定が反映されます。これにより、ダウンタイムなしで設定を変更することが可能です。
デフォルトのnginx設定を上書きするには、有効なserver
ブロックを含むnginx.confの設定セグメントを提供します。カスタムnginx設定はERBテンプレートであり、使用前にレンダリングされます。
単一サイトの設定のみ、または全てのサイトの設定を上書きすることができます。
この場合、<your-domain>.conf.erb
と<your-domain>.ssl.conf.erb
を提供します。前者はLet's Encryptからの所有権検証とHTTPS URLへのリダイレクトを担当し、後者はHTTPS接続を処理します。
例えば、my.example.com
のHTTPSおよびHTTP設定の両方を上書きするには、HTTPS-PORTALを以下のように起動します:
https-portal:
# ...
volumes:
- https-portal-data:/var/lib/https-portal
- /path/to/http_config_file:/var/lib/nginx-conf/my.example.com.conf.erb:ro
- /path/to/https_config_file:/var/lib/nginx-conf/my.example.com.ssl.conf.erb:ro
このファイル と このファイル は、HTTPS-PORTALによって使用されるデフォルトの設定ファイルです。 これらのファイルをコピーして開始するのが良いでしょう。変数をそのまま使用することも、ドメインやアップストリームなどをハードコードすることもできます。
別の例は こちら で見ることができます。
すべてのサイトで使用されるNginx設定を作成したい場合、/var/lib/nginx-conf/default.conf.erb
や /var/lib/nginx-conf/default.ssl.conf.erb
を上書きすることができます。これらのファイルは、サイト固有の設定ファイルが提供されていない場合、各サイトに適用されます。
設定ファイルがすべてのサイトで使用されるため、ファイル内の変数をそのまま使用し、何もハードコードしないでください。
デフォルトでは、HTTPS-PORTALは2048
ビット長のRSA秘密鍵を生成します。
しかし、NUMBITS
環境変数を通じてRSA秘密鍵の長さ(openssl genrsa
コマンドのnumbits
)を手動で設定することができます。
https-portal:
# ...
environment:
NUMBITS: '4096'
また、Mozillaによって推奨されているように、CERTIFICATE_ALGORITHM
環境変数をprime256v1
に設定することもできます。ただし、この設定は一部の古いクライアント/システムが接続できなくなることに注意してください。
これらの設定は新しく生成された鍵にのみ適用されます。既存の鍵を更新したい場合は、/var/lib/https-portal
の下に保存されている既存の鍵を削除して、https-portal
を再起動してください。
以下動作を実施しています:
- Let's Encryptからあなたの各サブドメインのSSL証明書を取得。
- HTTPSを使用するようにNginxを設定(HTTPをHTTPSにリダイレクトしてHTTPSを強制)
- 証明書が30日以内に期限切れになる場合、毎週証明書をチェックし、更新するためのcronジョブを設定。
Let's Encryptのサービスは公平な使用を保証するために利用制限が設けられています。様々な利用制限について自分自身で調べてください。このドキュメントページは現在の利用制限値の公式情報源です。
ほとんどの人にとって最も重要な利用制限は:
- 時間あたり5回の検証失敗
- 週あたりの登録ドメインごとに50件の証明書
- 週あたり5件の重複証明書(更新用)
単一の証明書で複数のサブドメインにHTTPSを使用したい場合、Let's Encryptは1つの証明書に最大100のドメインを入れることをサポートしていますが、注意深い計画が必要で、自動化が難しい場合があります。そのため、HTTPS-PORTALでは単一ドメイン名の証明書のみを扱います。
HTTPS-PORTALはあなたの証明書をデータボリュームに保存し、有効な証明書が見つかった場合、期限切れの30日前まで証明書を再署名しません(環境変数FORCE_RENEW: 'true'
を使用して証明書を強制更新することができます)。しかし、イメージを多用すると、制限に達することがあります。そのため、STAGE
はデフォルトでstaging
に設定されており、Let's Encryptのステージングサーバーを使用しています。実験が終わり、すべてがうまくいっていると感じたら、STAGE: 'production'
に切り替えることができます。
証明書が正しくチェーンされていないと判断した場合は、以下の設定でコンテナをもう一度実行してください:
https-portal:
# ...
environment:
# ...
FORCE_RENEW: 'true' # <-- here
これは、ACME v2がACME v1とは異なり、部分的なチェーンではなく完全なチェーンを返すためです。古い証明書が保存されている場合、HTTPS-PORTALは正しく対応できないことがあります。この問題に遭遇した場合は、FORCE_RENEW
を実行して新しい証明書セットを取得してください。
HTTPS-PORTALが期待通りに動作していないと感じた場合は、データボリュームをリセットしてみてください:
docker-compose down -v
docker-compose up
- acme-tiny by Daniel Roesler.
- docker-gen by Jason Wilder.
- s6-overlay.