6

контекст

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

Отказ от ответственности: у меня очень мало опыта работы с внутренностями 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.)

9 ответов9

7

Начиная с версии 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;
    }
}
4

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

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

3

У меня есть рабочая конфигурация туннелирования 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

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

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

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

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

2

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

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

1

Начиная с Nginx версии 1.9.0, NGINX поддерживает модуль ngx_stream_core_module, его следует включить с помощью --with-stream. Когда потоковый модуль включен, они могут использовать протокол ssh по протоколу tcp.

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/

1

Насколько я знаю, в настоящее время 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

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

0

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

0

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

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

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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .