以下に示す nginx.conf ファイルがあります。
ポート 443/SSL で ssh と Web サーバーの両方を実行したいと考えています。これは
SSL ポート多重化とも呼ばれます。
同時に、SNI で ssl パススルーを使用したいと考えています。
ssh-multiplexing の場合は $ssl_preread_protocol を使用します。SSL
-SNI-passthrough の場合は $ssl_preread_server_name を使用します。
を設定するとproxy_pass $upstream;
、ssh は正常に動作しますが、Web ページは動作しません。
を設定するとproxy_pass $name;
、SSL-SNI-passthrough は動作しますが、ssh にアクセスできません。
2つのマップ命令を組み合わせるにはどうすればいいでしょうか?例えば、
if $upstream = ssh
then proxy_pass $upstream
else proxy_pass $name;
endif
問題は、プロトコル選択とサーバー名選択を組み合わせる方法が必要だということです。
if(ssh) => forward to port 22
else => forward to port xy depending on server_name
私の設定ファイルは次のとおりです:
stream{
upstream ssh
{
server 127.0.0.1:22;
}
upstream https_default_backend
{
server 127.0.0.1:443;
}
upstream daniel_backend
{
server 127.0.0.1:5005;
}
map $ssl_preread_protocol $upstream
{
default ssh;
"TLSv1.3" https_default_backend;
"TLSv1.2" https_default_backend;
"TLSv1.1" https_default_backend;
"TLSv1" https_default_backend;
}
map $ssl_preread_server_name $name
{
localhost daniel_backend;
prodesk daniel_backend;
daniel-steiger.ch daniel_backend;
www.daniel-steiger.ch daniel_backend;
default https_default_backend;
}
# SSH and SSL on the same port
server {
listen 443;
ssl_preread on;
#proxy_protocol on;
# proxy_pass $upstream;
proxy_pass $name;
}
}
答え1
すでに解決策は見つかりましたか?
私もこの問題を抱えており、これを試してみました。問題ないようです。
stream {
upstream ssh {
server 127.0.0.1:22;
}
upstream https_default_backend {
server 127.0.0.1:443;
}
upstream daniel_backend {
server 127.0.0.1:5005;
}
map $ssl_preread_protocol $upstream {
"" ssh;
default $name;
"TLSv1.3" $name;
"TLSv1.2" $name;
"TLSv1.1" $name;
"TLSv1" $name;
}
map $ssl_preread_server_name $name {
localhost daniel_backend;
prodesk daniel_backend;
daniel-steiger.ch daniel_backend;
www.daniel-steiger.ch daniel_backend;
default https_default_backend;
}
server {
listen 443;
ssl_preread on;
proxy_pass $upstream;
}
}
答え2
ネクロマンシング。
他の人の利益のために自分の質問に答えます。
これは nginx では不可能です (私の知る限り)。
ただし、HAproxy を使用すれば目標を達成できます。
設定はそれほど簡単ではないので、私がうまくいったハックを以下で参照してください。
メモ帳で検索と置換を使用してすべての値を変更したことに注意してください (エラーがある可能性があります)。
この構成では、次のことを前提としています。
パブリック IP 44.33.22.11 のサーバー
ポートで実行されているローカル http サーバー (HAproxy が実行される同じサーバー上の 8000+x、つまり 127.0.0.1)
127.0.0.1:22 で実行されている sshd (HAproxy と同じマシンのポート 22)
2 つのドメイン (それぞれ http と https):
http://firstname-lastname.com/
https://firstname-lastname.com/
http://forename-familyname.com/
https://forename-familyname.com/
これらのドメインはすべてDNSで44.33.22.11に解決されます
プロキシプロトコル(プロキシv2が最新)を使用する場合は、# send-proxy-v2
例えば次の行のコメントを解除します。
server web0 127.0.0.1:8005 # send-proxy-v2
なる
server web0 127.0.0.1:8005 send-proxy-v2
sni-passthroughはプロキシ順序を逆にすることに注意してください。nginx
では順序は
-> request -> decrypt -> proxy headering decrypted request -> re-encrypt request -> forward
haproxy SNI-passthroughでは順序は
-> request -> proxy headering encrypted request -> forward
したがって、 HAproxyを使用する場合、
nginxを使用するhttpサーバー(ポート8000+x)でのミドルウェアの処理順序は次のようになります。-> SSL-decrypt -> unheader -> process
-> unheader -> SSL-decrypt -> process
これは、HAproxy で sni-passthrough を使用し、nginx で SSL キー (パススルーなし) を使用しているためです。この厄介な小さな事実が、私に頭を悩ませました。
また、テスト目的で、hosts ファイルに example.int、foo.int、bar.int を設定し、ローカル ネットワークで 10.0.0.2 (HAproxy がインストールされているマシンの内部ネットワーク IP アドレス) に解決するようにしました。これらのエントリは、haproxy.cfg ファイルにも表示されます。
# /etc/haproxy/haproxy.cfg
# Validate:
# haproxy -c -V -f /etc/haproxy/haproxy.cfg
# Another way is to
# sudo service haproxy configtest
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
stats timeout 30s
user haproxy
group haproxy
daemon
# Default SSL material locations
ca-base /etc/ssl/certs
crt-base /etc/ssl/private
# See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate
ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_comACHA20_POLY1305_SHA256
ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
frontend http
bind *:80
mode http
option forwardfor
# option httpchk /check.cfm
# use-server server1 if { hdr(host) -i server1.domain.net }
# use-server server2 if { hdr(host) -i server2.domain.net }
# server server1 localhost:22201 check
# server server2 localhost:22202 check
# default_backend nodes
# redirect scheme https code 301 if !{ ssl_fc }
# http://10.0.0.2/.well-known/acme-challenge/token.txt
# http://44.33.22.11/.well-known/acme-challenge/token.txt
# http://firstname-lastname.com/.well-known/acme-challenge/token.txt
# http://forename-familyname.com/.well-known/acme-challenge/token.txt
# https://www.haproxy.com/documentation/aloha/12-5/traffic-management/lb-layer7/acls/
# For ACLs sharing the same name, the following rules apply:
# It is possible to use the same <aclname> for many ACLs, even if they do not have the same matching criterion
# A logical OR applies between all of them
# acl firstname_lastname_com dst 10.0.0.2
# acl firstname_lastname_com dst 44.33.22.11
acl firstname_lastname_com hdr(host) -i 44.33.22.11
acl firstname_lastname_com hdr(host) -i 10.0.0.2
acl firstname_lastname_com hdr(host) -i firstname-lastname.com
acl firstname_lastname_com hdr(host) -m end .firstname-lastname.com
acl forename_familyname_com hdr(host) -i forename-familyname.com
acl forename_familyname_com hdr(host) -m end .forename-familyname.com
#use_backend http_firstname_lastname_com if { hdr(host) -i firstname-lastname.com }
#use_backend http_firstname_lastname_com if { hdr(host) -m end .firstname-lastname.com }
use_backend http_firstname_lastname_com if firstname_lastname_com
use_backend http_forename_familyname_com if forename_familyname_com
backend http_firstname_lastname_com
mode http
balance roundrobin
server web0 127.0.0.1:8006
backend http_forename_familyname_com
mode http
balance roundrobin
server web0 127.0.0.1:8008
#backend nodes
# mode http
# balance roundrobin
# option forwardfor
# reqirep ^Host: Host:\ node1.myapp.mycompany.com
# server web01 node1.myapp.mycompany.com:80
# sudo systemctl stop nginx
# sudo systemctl disable nginx
# sudo systemctl enable haproxy
# service haproxy start
# sudo haproxy -c -V -f /etc/haproxy/haproxy.cfg
# service haproxy restart
frontend https
bind *:443
mode tcp
option tcplog
tcp-request inspect-delay 5s
tcp-request content accept if { req.ssl_hello_type 1 }
#tcp-request content accept if { req_ssl_hello_type 1 }
# https://datamakes.com/2018/02/17/high-intensity-port-sharing-with-haproxy/
# systemctl restart sshd
# systemctl disable sshd
# systemctl enable sshd
# sudo apt-get install openssh-server
# sudo systemctl status ssh
# sudo ufw allow ssh
# sudo ufw enable
# sudo ufw status
# ufw allow 443/tcp
# ufw allow 8443/tcp
# /etc/ssh/sshd_config ==> PermitRootLogin yes + PasswordAuthentication no + ChallengeResponseAuthentication no ~/.ssh/id_rsa.pub ==> ~/.ssh/authorized_keys
acl ssh_payload payload(0,7) -m bin 5353482d322e30
# /mnt/sshfs/var/www/.dotnet/corefx/cryptography/crls/
# sudo apt-get install exfat-utils exfat-fuse
# https://10.0.0.2/.well-known/acme-challenge/token.txt
# https://44.33.22.11/.well-known/acme-challenge/token.txt
# http://firstname-lastname.com/.well-known/acme-challenge/token.txt
# http://forename-familyname.com/.well-known/acme-challenge/token.txt
# https://www.haproxy.com/documentation/aloha/12-5/traffic-management/lb-layer7/acls/
# For ACLs sharing the same name, the following rules apply:
# It is possible to use the same <aclname> for many ACLs, even if they do not have the same matching criterion
# A logical OR applies between all of them
# sequence matters !
use_backend openssh if ssh_payload
use_backend openssh if !{ req.ssl_hello_type 1 } { req.len 0 }
# having these two lines here blocks ssh if use_backend openssh comes afterwards ...
# also, this fucks up SNI ...
# acl firstname_lastname_com dst 10.0.0.2
# acl firstname_lastname_com dst 44.33.22.11
acl firstname_lastname_com req_ssl_sni -i firstname-lastname.com
acl firstname_lastname_com req.ssl_sni -m end .firstname-lastname.com
acl forename_familyname_com req_ssl_sni -i forename-familyname.com
acl forename_familyname_com req.ssl_sni -m end .forename-familyname.com
# wildcard
use_backend https_firstname_lastname_com if firstname_lastname_com
use_backend https_forename_familyname_com if forename_familyname_com
# use_backend example_int if { req_ssl_sni -i example.int }
# use_backend example_int if { req_ssl_sni -m end .example.int }
# use_backend example_int if { req_ssl_sni -i example.int }
# use_backend foo_int if { req_ssl_sni -i foo.int }
# use_backend bar_int if { req_ssl_sni -i bar.int }
# sudo haproxy -c -V -f /etc/haproxy/haproxy.cfg
backend https_firstname_lastname_com
mode tcp
balance roundrobin
server web0 127.0.0.1:8005 # send-proxy-v2
backend https_forename_familyname_com
mode tcp
balance roundrobin
server web0 127.0.0.1:8007 # send-proxy-v2
backend foo_int
balance roundrobin
server web1 127.0.0.1:8005 send-proxy
backend bar_int
balance roundrobin
server web2 127.0.0.1:8005 ##send-proxy
backend openssh
mode tcp
# option tcplog
# option tcp-check
# tcp-check expect string SSH-2.0-
timeout server 3h
# server openssh 127.0.0.1:22 check
server openssh 127.0.0.1:22
この設定は、すべてのリクエストを転送します
ssh [email protected] -p 443
に127.0.0.1:22
そしてすべてのリクエスト
http://firstname-lastname.com127.0.0.1:800X(X = 2n(偶数))
https://firstname-lastname.com127.0.0.1:800X へ。ここで X = 2n+1 (奇数)
(http には 800X、https には 900X を使用する方がよいでしょう)