Может так случится, что появляется необходимость завести свой tcp сервис на 443 порту. Но что же делать, если там уже висит сайт, который доступен через nginx reverse-proxy. Это можно сделать с помощью конфига в nginx.

Необходимые условия

Для работы этого хака нужно, что бы nginx был скомпилирован с модулем ngx_stream_ssl_preread_module. Проверить это можно такой командой:

1
nginx -V 2>&1 | grep 'with-stream_ssl_preread_module'

Если в выводе что-то есть, значит grep нашел модель. Если модуля нет, то нужно сделать его “есть”. Это выходит за рамки заметки.

Пример с ssh сервисом

Почему ssh? Он есть и нужен почти всегда, а некоторые фаерволы блокируют все запросы мимо 80/443 портов, во избежание. Особенно это относится к публичным WiFi сетям и тому подобным.

Итак, добавляем stream, который будет слушать наш 443 порт и распределять подключения. При этому upstream-ы могут быть как на внутреннем ip, так и на публичном или каком-то удаленном адресе. Например, для ssh часто меняют порт, но с этим методом можно будет вообще убрать общедоступный порт из сети и привязать демон sshd на 127.0.0.1.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
stream {
    upstream ssh {
        server 127.0.0.1:22;
    }

    upstream web {
        server 127.0.0.1:443;
    }

    map $ssl_preread_protocol $upstream {
        default ssh;
        "TLSv1" web;
        "TLSv1.1" web;
        "TLSv1.2" web;
        "TLSv1.3" web;
    }

    # SSH and SSL on the same port
    server {
        listen 443;

        proxy_pass $upstream;
        ssl_preread on;
    }
}

Теперь подключится к ssh можно будет так:

1
ssh server.ip.addr -p 443

При обычном https запросе (скажем от браузера) - будет открыт сайт, который досутпен на апстреме web, что не помешает сайту быть доступным для пользователей и краулеров.