Может ли nginx одновременно обслуживать SSH и HTTP (S) на одном и том же порту?

7939
JohnW

контекст

У меня есть личный сервер, который я использую для Интернета. Мне иногда нужно SSH / SFTP к нему.

Disclamer: у меня очень мало опыта работы с nginxвнутренностями.

проблема

Этим утром я выяснил, что бесплатный Wi-Fi в известной сети кафе блокирует SSH (фактически, они блокируют все, что не в 80/443). Но когда мне нужен SSH, он мне нужен, поэтому я искал способы совместного использования SSH и HTTPS на одном и том же порту.

На что я смотрел

Я рассмотрел несколько возможных решений, которые могут работать на порту 443:

  • SSHLмультиплексор SSH / OpenVPN / HTTPS;
  • OpenVPN: VPN-решение имеет встроенный мультиплексор для OpenVPN и HTTPS;
  • HAProxyВеб-сервер / балансировщик нагрузки может также мультиплексировать все.

Все это кажется довольно простым, но мне не очень нравится факт добавления слоев и сложности и, возможно, замедления всего лишь в том маловероятном случае, когда мне понадобится SSH на 443.

Положив nginx в смесь

Я знаю, что nginxуже поддерживает обработку необработанных потоков TCP. Поэтому мне было интересно, смогу ли я использовать это на порту 443 слишком напрямую nginx. Идея заключалась в том, что nginxможно было бы использовать httpмодуль, если он распознает HTTP (S) или streamдля всего остального.

Вопросы

В этом контексте у меня есть два вопроса:

  • nginxСпособен ли даже сделать такое различие? (Я даже не уверен, что смогу слушать порт 443 одновременно httpи в streamблоке, и в блоке.)
  • Если так, будут ли какие-либо явные проблемы с производительностью с этой настройкой? (Например, я думаю о скорости передачи по SFTP, а не по SSH.)
5
Я знаю достаточно об этих протоколах, чтобы объяснить, в какой степени такое обнаружение протокола возможно. Однако я не знаю, на что способен Nginx. Название `stream` не похоже на функцию, способную обнаруживать любые протоколы. Независимо от того, что вы используете на стороне сервера, вам нужно будет либо инкапсулировать трафик SSH в другой протокол, либо использовать SSH-клиент, который достаточно недавний, чтобы иметь возможность выступать перед сервером. Полагаться на сервер, чтобы обнаружить протокол клиента, который еще не говорил, было бы хрупким. kasperd 7 лет назад 0
Поддержка `nginx` кажется довольно небольшой, и кажется, что она полагается только на номер порта для« маршрутизации »трафика. Из того, что я понял, блок `http` - это просто способ загрузить нужный модуль для соответствующего соответствующего сервера, прослушивающего данный порт. Этот модуль, в свою очередь, будет выполнять всю магию `SNI`. Но я не эксперт, и я просто хотел убедиться, что правильно понял. JohnW 7 лет назад 0
Мне не понятно, почему вы даже спрашиваете о Nginx. Похоже, у вас нет опыта работы с Nginx и нет доказательств того, что он должен быть способен выполнять то, о чем вы просите. Если вы ясно дадите понять, как выглядит ваша текущая настройка, вы, вероятно, получите гораздо лучший ответ. kasperd 7 лет назад 1
При этом `SNI` происходит на уровне TLS: если нет` SNI`, `nginx` ** может ** по умолчанию вместо этого выполнять потоковую передачу. JohnW 7 лет назад 0

9 ответов на вопрос

6
sattellite

Начиная с версии nginx 1.15.2 добавлена ​​новая переменная $ssl_preread_protocol. А в официальном блоге добавлен пост о том, как использовать эту переменную для мультиплексирования HTTPS и SSH на одном и том же порту https://www.nginx.com/blog/running-non-ssl-protocols-over-ssl-port-nginx-1 -15-2 /

Пример настройки SSH (по умолчанию) и HTTPS:

stream { upstream ssh { server 192.0.2.1:22; }  upstream web { server 192.0.2.2:443; }  map $ssl_preread_protocol $upstream { default ssh; "TLSv1.2" web; }  # SSH and SSL on the same port server { listen 443;  proxy_pass $upstream; ssl_preread on; } } 
Возможно ли, чтобы оба сервера ssh и (nginx) https находились на одном хосте? Я предполагаю, что вам нужно было бы заставить https «слушать» на порту 444 или что-то еще, и направить предварительный ssh, который слушает на 443, на порт 444 для https? starbeamrainbowlabs 5 лет назад 1
@starbeamrainbowlabs Вы не можете установить оба на 443, но вы можете использовать сокет домена unix, поэтому вам не нужно запускать два процесса nginx. Вы можете сделать `listen unix: / run / nginx.sock` в http> серверных блоках. kissgyorgy 5 лет назад 0
4
mtsdev

Или вы можете использовать прокси-туннель ssh через nginx через HTTP / S-соединение

Посмотрите: proxytunnel

3
tux

У меня есть рабочая конфигурация туннелирования ssh через tls на порт 443, используя модуль потока nginx. Я также делаю XMPP через TLS и обычный HTTP на том же порту. Я делаю мутплексирование через ALPN.

(Вам нужно nginx> 1.13.10, чтобы использовать модуль ssl_preread с alpn http://nginx.org/en/docs/stream/ngx_stream_ssl_preread_module.html#ssl_preread )

Моя конфигурация использует версию докера nginx, но она также должна работать без докера.

stream { # check ALPN for xmpp client or server and redirect to local ssl termination endpoints map $ssl_preread_alpn_protocols $ssl_multiplexer { "xmpp-client" 127.0.0.1:5422; "xmpp-server" 127.0.0.1:5469; "identifyssh" 127.0.0.1:8822; default 127.0.0.1:8443; }  server { listen 443; ssl_preread on; proxy_pass $ssl_multiplexer; proxy_protocol on; set_real_ip_from 172.18.0.0/32; }  # ssl termination for c2s connections server { listen 5422 ssl proxy_protocol; # ... <- tls keys and options here proxy_ssl off; proxy_pass ejabberd:5222; }  # ssl termination for s2s connections server { listen 5469 ssl proxy_protocol; # ... <- tls keys and options here proxy_ssl off; proxy_pass ejabberd:5269; }  # ssl termination for ssh connections server { listen 8822 ssl proxy_protocol; # ... <- tls keys and options here proxy_ssl off; proxy_pass yourserver:22; } } 

Если вы хотите использовать XMPP, вам нужно добавить некоторые записи SRV для указания на порт 443 вашего сервера, см. Https://xmpp.org/extensions/xep-0368.html.

Если вы хотите подключиться к вашему ssh-серверу, вы должны обернуть ваш ssh-сеанс в ssl-сеанс, который отправляет строку ALPN, определенную вами в конфигурации потока. Я использовал «identifssh» в примере выше. Вы можете использовать что угодно, но стараться не вступать в конфликт с официальными именами: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids

Чтобы запустить сессию ssh с вашего клиента на ваш подготовленный сервер, используйте:

ssh you@yourserver -o "ProxyCommand openssl s_client -alpn identifyssh -ign_eof -connect yourserver:443" 

И вы должны быть на связи.

Следует также отметить, что я использую proxy_protocol, чтобы сохранить заголовки клиентов и IP-адрес при передаче их бэкэндам.

Ваш обычный http-сервер, настроенный в разделе http {}, должен позаботиться об этом:

server { listen 8443 ssl proxy_protocol; # ... } 

Лучше всего то, что вам не нужны такие инструменты, как sslh, stunnel, proxytunnel или другие, чтобы сделать эту работу. Вам нужен только новый nginx и openssl. Надеюсь, это кому-нибудь поможет. Это помогло бы мне разобраться в этом.

2
cnst

Этот вопрос немного связан с другим, на который я недавно ответил:

https://stackoverflow.com/questions/34741571/nginx-tcp-forwarding-based-on-hostname/34958192#34958192

Да, это технически возможно провести различие между sshи httpsтрафик, и маршрут соединения надлежащим образом ; однако, насколько мне известно, nginx в настоящее время не имеет такой поддержки.

Однако, что вы можете сделать, это просто запустить sshdнепосредственно на httpsпорт в дополнение к sshone ( /usr/sbin/sshd -p 22 -p 443) и / или использовать брандмауэр и / или стук порта, чтобы определить, куда 443перенаправляются соединения с портом .

Похоже, что nginx теперь может иметь поддержку с [ngx_stream_ssl_preload_mode] (https://nginx.org/en/docs/stream/ngx_stream_ssl_preread_module.html). starbeamrainbowlabs 5 лет назад 0
2
symcbean

Вы можете настроить правило iptables для переадресации соединений из вашего известного кафе через порт 443 на порт 22. В качестве альтернативы можно переадресовывать трафик с ретранслятора порта в другом месте в Интернете, изменяя номер pirt.

Просто попытка решить проблему с nginx не сработает.

1
Gea-Suan Lin

Насколько я знаю, в настоящее время nginx не поддерживает его.

В SSH-2 клиент отправит приветственное сообщение на сервер:

Когда соединение установлено, обе стороны ДОЛЖНЫ отправить идентификационную строку. Эта идентификационная строка ДОЛЖНА быть

 SSH-protoversion-softwareversion SP comments CR LF 

В TLS 1.2 клиенты должны сначала отправить:

 Client Server  ClientHello --------> ServerHello [ChangeCipherSpec] <-------- Finished [ChangeCipherSpec] Finished --------> Application Data <-------> Application Data 

Клиенты могут использовать эту информацию для реализации.

Этот ответ немного неточный. Исторически протокол SSH заставлял сервер говорить первым. Но в SSH-2 клиенту разрешено говорить, не дожидаясь, пока сервер заговорит первым. Любой клиент OpenSSH, которому меньше пары лет, будет говорить, не дожидаясь, пока сервер заговорит первым, если вы не включите поддержку SSH-1 в клиенте. kasperd 7 лет назад 1
Да, вы правы, я исправлю свой ответ. Gea-Suan Lin 7 лет назад 0
1
Hendi Fauzi

Since Nginx Version 1.9.0,NGINX support ngx_stream_core_module module, it should be enabled with the --with-stream. When stream module is enable they are possible to ssh protocol tcp proxy

stream { upstream ssh { server 192.168.1.12:22; } server { listen 12345; proxy_pass ssh; } } 

https://www.nginx.com/resources/admin-guide/tcp-load-balancing/

Это не позволяет вам мультиплексировать. Ivan Vučica 6 лет назад 2
0
kensai

Для nginx существует не поддерживаемое исправление для поддержки мультиплексирования протоколов для SSH и HTTPS: https://github.com/shawnl/nginx-ssh

Однако это больше не поддерживается, не-nginx проект, который поддерживает то, что вы ищете: https://github.com/yrutschle/sslh

Я предлагаю вам использовать SSLH перед вашим nginx и ssh сервером.

0
Thraidh

Может быть, вы можете использовать nginScript для реализации своего собственного мультиплексора? Смотрите здесь для введения: https://www.nginx.com/blog/introduction-nginscript/