Развёртывание за обратным прокси

Развёртывание за обратным прокси — установка сервера RuDesktop во внутренней сети с внешним HAProxy или Nginx перед ним, который принимает подключения снаружи и пересылает их на сервер. Раздел описывает, какой трафик можно проксировать и каким способом, готовые примеры конфигураций и список типовых проблем

Важно

По умолчанию сервер RuDesktop уже разворачивает у себя локальный Nginx, который терминирует TLS на 443 и проксирует запросы к веб-части и к нативному компоненту relay / rz через unix-сокеты /run/rudesktop-web.sock и /run/rudesktop/rude.sock (см. Архитектура). Эта страница описывает внешний обратный прокси, который ставится перед сервером RuDesktop

Зачем нужен обратный прокси перед RuDesktop

Типовые сценарии:

  • TLS-терминация на единой точке — сертификаты обслуживаются одним фронтом, не на каждом узле

  • Единая точка входа для нескольких внутренних сервисов организации

  • Балансировка между несколькими узлами отказоустойчивого кластера

  • Ограничение доступа — фильтрация по IP, ACL, аутентификация заголовка

  • Публикация веб-части наружу, при том что прямой TCP-доступ к relay / rz остаётся внутри периметра

Какой трафик принимает сервер RuDesktop

По умолчанию весь трафик клиентов и веб-интерфейса идёт через единый порт ``443/TCP`` на встроенный Nginx сервера, который терминирует TLS и проксирует запросы к веб-части и компоненту relay / rz через unix-сокеты. Снаружи это выглядит как обычный HTTPS-сайт с дополнительным WebSocket-эндпоинтом

Эндпоинты на 443/TCP:

  • / — административная веб-панель и API (/api/, /portal/, /media/)

  • /v1/WebSocket-канал к нативному компоненту relay / rz через unix-сокет /run/rudesktop/rude.sock. Используется десктопным и мобильным клиентами для управляющего канала и сессионного трафика

  • /ws/WebSocket-канал к веб-части (/run/rudesktop-web.sock). Используется браузерным интерфейсом для live-обновлений и для обратной совместимости при разделении портов

  • /analytics/ — встроенный модуль аналитики (Apache Superset), проксируется на unix-сокет /run/rudesktop-web-superset.sock

  • /static/ — статика веб-интерфейса (alias /usr/share/rudesktop/public/)

  • /download/ — установочные пакеты клиентов (alias /usr/share/rudesktop/public/download/)

  • /tftp/ — файлы для PXE-установки (alias /var/lib/rudesktop/pxe/tftp/); единственный путь, доступный по HTTP на 80/TCP без редиректа на HTTPS

  • /root.pem — публичный CA-сертификат сервера, отдаваемый клиентам

Дополнительно при Разделении портов клиентский трафик можно вынести на отдельный HTTPS-порт (например, 8443) с набором эндпоинтов /api/, /media/, /portal/, /v1/, /ws/ — это всё тот же L7 HTTPS, не отдельный TCP-поток

Важно

Большая часть путей выше (/analytics/, /ws/, /tftp/, защищённые медиа и др.) объявлена в файле /etc/nginx/rudesktop_params, который подключается во встроенный vhost директивой include rudesktop_params;. При ручной правке /etc/nginx/sites-enabled/rudesktop не удаляйте этот include — иначе перечисленные эндпоинты перестанут работать

Подсказка

Весь трафик RuDesktop — это HTTP(S) с поддержкой WebSocket. Достаточно одного L7-прокси (HAProxy mode http или Nginx). Отдельный TCP-passthrough для какого-либо нестандартного порта не требуется

Что можно проксировать и каким способом

Что

Режим прокси

Особенности

/ — веб и API

L7 HTTP(S)

Стандартное HTTPS-проксирование. Передавать X-Forwarded-For, X-Forwarded-Proto, Host

/v1/ — WebSocket к relay / rz

L7 HTTP(S) с upgrade

Обязательны заголовки Upgrade: websocket / Connection: upgrade. Увеличить таймауты чтения/записи до 600s

/ws/ — WebSocket к веб-части

L7 HTTP(S) с upgrade

Те же требования, что и для /v1/: Upgrade / Connection: upgrade

/analytics/ — модуль аналитики

L7 HTTP(S)

Проксируется как /. Особенности доступа описаны в Смена адреса для модуля аналитики

/portal/, /api/, /media/, /static/, /download/, /root.pem

L7 HTTP(S)

Ничего особенного, проксируется как /

/tftp/

L7 HTTP

Раздаётся также по HTTP без TLS (порт 80/TCP) — для совместимости с PXE-загрузчиками. Если PXE используется, то проксирование /tftp/ нужно делать по HTTP, не редиректя на HTTPS. PXE-загрузчики не умеют HTTPS, и редирект на 443 сломает им загрузку. При отсутствии PXE проще не публиковать этот путь через фронт вообще

Важно

Что нельзя: проксировать /v1/ без upgrade-заголовков WebSocket. Если фронтальный прокси настроен только на HTTP без upgrade — управляющий канал клиента не установится, в десктопном клиенте будет вечный «Подключение…», в веб-интерфейсе пропадут live-обновления

Подсказка

Дефолты встроенного nginx (см. /etc/nginx/sites-enabled/rudesktop), которые имеет смысл воспроизвести и на внешнем фронте: proxy_connect_timeout 120s, proxy_send_timeout 600s, proxy_read_timeout 600s для /v1/ и client_max_body_size 1000G (загрузка пакетов и обновлений может превышать стандартные ограничения)

Подготовка сервера RuDesktop

Перед включением фронтального прокси:

  1. Убедитесь, что встроенный сервер работает на 127.0.0.1 или unix-сокете и не выставлен наружу напрямую — см. Смена и установка IP, Ограничение доступа к веб

  2. Если фронт будет терминировать TLS — на самом сервере RuDesktop можно оставить самоподписанный сертификат (он используется только во внутренней сети). Для прямого подключения клиентов к серверу без фронта см. Добавление собственных SSL-сертификатов

  3. Зафиксируйте публичный FQDN, по которому клиенты будут обращаться к фронту, и задайте его в качестве адреса сервера командой rude install (или rude reinstall, если требуется сброс конфигурации, см. Смена и установка IP):

    rude install rd.example.com
    

    Команда формирует /etc/default/rudesktop с переменными окружения PUBLIC_HOST='rd.example.com' и PUBLIC_PORT='443'. Из PUBLIC_HOST / PUBLIC_PORT веб-часть сервера формирует CSRF_TRUSTED_ORIGINS, и от них же зависят ссылки, которые сервер отдаёт клиентам. Список адресов в ALLOWED_HOSTS и server_name встроенного Nginx формируются из списка хостов сервера и обновляются той же командой

Подсказка

Подробнее о смене адреса сервера и о работе с двумя адресами одновременно — Смена и установка IP

Пример конфигурации HAProxy

Универсальный вариант — единый фронтенд на 443/TCP с TLS-терминацией, проксирование веба и WebSocket к одному backend-серверу RuDesktop на адресе 10.0.0.10:443

# /etc/haproxy/haproxy.cfg

global
    maxconn 50000
    log /dev/log local0
    ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11
    tune.ssl.default-dh-param 2048

defaults
    log     global
    mode    http
    option  httplog
    option  dontlognull
    timeout connect 10s
    timeout client  600s
    timeout server  600s
    timeout tunnel  1h

frontend rudesktop_https
    bind *:443 ssl crt /etc/haproxy/certs/rudesktop.pem alpn h2,http/1.1
    http-request set-header X-Forwarded-Proto https
    http-request set-header X-Forwarded-Port  %[dst_port]
    # FQDN, по которому ходят клиенты
    http-request set-header X-Forwarded-Host  %[req.hdr(host)]

    default_backend rudesktop_web

backend rudesktop_web
    balance roundrobin
    option forwardfor
    option http-server-close
    # Проброс WebSocket-апгрейда
    http-request set-header Connection upgrade if { hdr(Upgrade) -i websocket }
    server rd1 10.0.0.10:443 ssl verify none check

Важно

  • timeout tunnel 1h обязателен — иначе HAProxy будет рвать длинные WebSocket-соединения по таймауту

  • ssl verify none подходит для встроенного самоподписанного сертификата сервера. Для строгой проверки замените на verify required ca-file /etc/haproxy/ca/rudesktop_ca.pem

  • При наличии нескольких узлов кластера добавьте ещё server rd2 ..., но подключения должны быть sticky по cookie или source IP, чтобы один клиент попадал на один и тот же узел в рамках сессии

Если веб и клиентский трафик разнесены по разным портам

При использовании Разделения портов на стороне сервера клиентский трафик слушает на отдельном HTTPS-порту (например, 8443). На фронте это можно отразить вторым HTTPS-frontend’ом с тем же набором заголовков и таймаутов:

frontend rudesktop_client_https
    bind *:8443 ssl crt /etc/haproxy/certs/rudesktop.pem
    http-request set-header X-Forwarded-Proto https
    default_backend rudesktop_client_backend

backend rudesktop_client_backend
    option forwardfor
    http-request set-header Connection upgrade if { hdr(Upgrade) -i websocket }
    server rd1 10.0.0.10:8443 ssl verify none check

Пример конфигурации Nginx

Универсальный вариант — фронтальный Nginx, терминирующий TLS на 443 и проксирующий весь трафик на сервер RuDesktop (адрес 10.0.0.10)

# /etc/nginx/sites-available/rudesktop-front
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

upstream rudesktop_backend {
    server 10.0.0.10:443;
    keepalive 32;
}

server {
    listen 80;
    server_name rd.example.com;
    # PXE через фронт не пробрасывается — обращения к /tftp/ возвращаем 404,
    # PXE-клиенты должны ходить к серверу RuDesktop напрямую внутри сети.
    # Если PXE нужно публиковать через фронт — замените блок /tftp/ на proxy_pass http://10.0.0.10/tftp/;
    location /tftp/ { return 404; }
    location /     { return 301 https://$host$request_uri; }
}

server {
    listen 443 ssl http2;
    server_name rd.example.com;

    ssl_certificate     /etc/ssl/private/rd.example.com.pem;
    ssl_certificate_key /etc/ssl/private/rd.example.com.key;

    # Размер тела для загрузки больших файлов и обновлений
    client_max_body_size 1000G;

    proxy_http_version 1.1;
    proxy_set_header Host              $http_host;
    proxy_set_header X-Real-IP         $remote_addr;
    proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Forwarded-Host  $host;

    # WebSocket-канал /v1/ — увеличенные таймауты + upgrade
    location /v1/ {
        proxy_pass https://rudesktop_backend;
        proxy_ssl_verify off;
        proxy_set_header Upgrade    $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_connect_timeout 120s;
        proxy_send_timeout    600s;
        proxy_read_timeout    600s;
    }

    # WebSocket-канал /ws/ для браузерного интерфейса — те же требования к upgrade
    location /ws/ {
        proxy_pass https://rudesktop_backend;
        proxy_ssl_verify off;
        proxy_set_header Upgrade    $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_read_timeout    600s;
    }

    # Весь остальной трафик веб-панели и API
    location / {
        proxy_pass https://rudesktop_backend;
        proxy_ssl_verify off;
        add_header  Cache-Control 'no-cache';
    }
}

Важно

  • Блок map $http_upgrade $connection_upgrade должен находиться в http {} — например, в отдельном файле в /etc/nginx/conf.d/

  • proxy_ssl_verify off нужно для встроенного самоподписанного сертификата. Если на сервере RuDesktop установлен доверенный сертификат, переключите на proxy_ssl_verify on и пропишите proxy_ssl_trusted_certificate

  • Длинные таймауты в location /v1/ обязательны — иначе будет регулярный обрыв WebSocket с ошибкой upstream timed out

  • WebSocket-апгрейд должен быть прописан в обоих WebSocket-локациях (/v1/ и /ws/). Если оставить их без Upgrade / Connection — у клиентов отвалится управляющий канал, а в браузере пропадут live-обновления и аналитика

Решение проблем

Mixed content / CSRF Origin checking failed

  • Причина: клиент обращается по IP или домену, который не был указан при rude install, из-за чего этот адрес отсутствует в CSRF_TRUSTED_ORIGINS и Django отклоняет запрос

  • Решение: проверить, что фронт всегда добавляет X-Forwarded-Proto: https и X-Forwarded-Host: <FQDN>. PUBLIC_HOST и PUBLIC_PORT сервера должны совпадать с FQDN и портом фронта — поправляются командой rude install <FQDN>[:порт]. Из них Django формирует CSRF_TRUSTED_ORIGINS вида https://<PUBLIC_HOST> (или https://<PUBLIC_HOST>:<PUBLIC_PORT> при нестандартном порте)

Связанные страницы