Unifi Controller + Nginx. HTTP & HTTPS

в 9:05, , рубрики: nginx, unifi nginx, Сетевые технологии, системное администрирование, метки:

image

Краткая суть:

Пошаговая инструкция по проксированию Unifi-контроллера через Nginx по http или https.

Конфиги, понятные примеры, комментарии.

Пролог:

Наша компания занимается разработкой мобильных приложений, и как вы могли догадаться, в офисе находится огромное количество различных девайсов, все они любят Wi-Fi и не просто Wi-Fi, а бесшовный, чтобы можно было свободно погулять по коридору, не прерывая разговоры по Skype, и просто наслаждаться всеми плодами непрерывной вафли.

Для этих целей решили взять несколько Unifi тарелок с целью не заморачиваться с настройкой и чтобы все работало из коробки. По-крупному все так и было за одним НО, который и послужил причиной создания этого tutorial: контроллер тарелок умеет работать только через https, а так же к нему не полагается нормальной инструкции по проксированию через Nginx, существующая, мягко говоря, оставляет желать лучшего, а так же не предусматривает сценарий работы с HTTP.

Требуемый уровень подготовки:

Будем считать, что азы Nginx известны, куда помещать конфиги и так понятно, а сам веб сервер тоже развернут. Кроме этого, подразумевается, что контроллер посуды уже настроен. Если с этим возникают сложности, то у Ubiquity есть отличная инструкция для Linux и Windows. Но в дальнейшем будем считать, что мы все здесь прожженные линуксоиды.

Вся конфигурация проверялась на Unifi Controller v5.2.9, Nginx v1.10.1, Debian Jessie, Java 8

И так, поехали.

HTTP:

Все просто, нужно только положить конфиг куда надо, но потребуются определенные пояснения и предупреждения.

Всем, кому лень думать читать, а просто надо, чтобы все работало, можно скопировать конфиг и заменить в нем server_name на подходящий, а так же адрес/порт в блоке upstream, если контроллер расположен не в локалхосте:

upstream unifi {
    server 127.0.0.1:8443;
}

server {
    listen 80;
    server_name unifi.domain.com;

    error_log /var/log/unifi/nginx.log;
    access_log /var/log/unifi/access.log;

    proxy_ssl_verify off;
    proxy_ssl_session_reuse on;
    proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

    proxy_cache off;
    proxy_store off;

    server_tokens off;

    location / {
        proxy_set_header Referer "";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass https://unifi;   
        proxy_redirect https:// http://;
        header_filter_by_lua_block {
            if ngx.header["Set-Cookie"] then 
                ngx.header["Set-Cookie"] = { 
                    string.gsub(ngx.header["Set-Cookie"][1], "(.*)Secure;(.*)", "%1%2"),
                    string.gsub(ngx.header["Set-Cookie"][2], "(.*)Secure(.*)", "%1%2") 
                }
            end
        }
    }
}

Если Nginx собран из исходников, то нужно отдельно установить модуль ngx_http_lua_module.

Теперь можно перезагрузить Nginx:

sudo service nginx reload

Нюансы:
Так как контроллер из коробки поддерживает только HTTPS, то для его проксирования через HTTP нам придется модифицировать Cookie, отрезав флаг secure, и в принципе отключить любую валидацию ssl upstream сервера. Ушлые админы кинут в меня тапком, сказав, что можно добавить доверенный сертификат, предварительно прописав его в контроллер, но мы этот кейс рассматривать не будем в виду его избыточной сложности.

Тем не менее, не рекомендуется держать инфраструктурные вещи на HTTP. Только если совсем нет сертификата, а хочется, чтобы контроллер красиво торчал наружу.

Можно поменять слушающий порт и любые другие настройки по вкусу.

HTTPS с дефолтным сертификатом контроллера:

Это ленивый вариант HTTPS. Контроллер имеет свой ssl сертификат из коробки, но его можно заменить на любой другой. И вместо того, чтобы его скурпулезно настраивать, мы просто попросим Nginx соглашаться на все.

Простыми словами, весь трафик идет из интернетов сети по HTTPS до Nginx, а от Nginx к контроллеру уже незащищенный. Если Unifi контроллер и Nginx находятся в пределах локалхоста или доверенной сети, то это наш случай:

upstream unifi {
    server 127.0.0.1:8443;
}

# Редиректим на HTTPS
server {
    listen       80;
    server_name  unifi.domain.com;
    server_tokens off;
    rewrite ^ https://$http_host$request_uri?;
}

server {
    listen 443 ssl;
    server_name unifi.domain.com;

    error_log /var/log/unifi/nginx.log;
    access_log /var/log/unifi/access.log;  

    ssl on;
    ssl_certificate /etc/nginx/ssl/server.crt;
    ssl_certificate_key /etc/nginx/ssl/server.key;
    ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 5m;
    add_header Strict-Transport-Security "max-age=31536000" always;
    server_tokens off;

    proxy_ssl_verify off;
    proxy_ssl_session_reuse on;
    proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    proxy_cache off;
    proxy_store off;

    location / {
        proxy_set_header Referer "";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass https://unifi;
    }
}

Дополнительные настройки

Можно сделать перманентный редирект, заменив

rewrite ^ https://$http_host$request_uri?;

на

rewrite ^ https://$http_host$request_uri? permanent;

Но лучше этим заниматься, когда вы убедились в правильной работе всей системы.

В этом конфиге надо заменить следующие параметры на свои:

  • Путь до сертификата ssl_certificate
  • Путь до ключа сертификата ssl_certificate_key
  • Имя сервера обоих серверов(ssl и редирект) server_name
  • Порт и адрес upstream сервера при необходимости

И не забываем делать reload Nginx:

sudo service nginx reload

Вы можете спросить: "Но мэн, почему в твоем конфиге два сервера, хотя у меня он один?". Я отвечу: один сервер принимает ssl трафик, проксируя его контроллеру, а другой редиректит на первый, если к нам обратились по HTTP, чтобы не подвергать опасности наши дыры безопасности.

А теперь осталось самое сладкое, для настоящих параноиков серьезных администраторов.

HTTPS с кастомным сертификатом контроллера

Предположим, что Nginx и контроллер находятся теперь не в доверенной сети и мы не можем быть на 100% уверены в безопасности соединения между ними. В таком случае нам придется воспользоваться выданным ssl сертификатом для нашего домена на котором будет находиться контроллер, либо сгенерировать свой.

Процедуру генерации self signed сертификата мы описывать здесь не будем, она только косвенно касается данного tutorial. Считаем, что уже все готово и мы молодцы.

И так, убедимся, что у нас есть на руках crt и key файлы, они нам потребуются, чтобы подложить наш сертификат в Unifi контроллер. Будем считать, что они называются unifi.crt и unifi.key соответственно.

Теперь нам нужно сгенерировать keystore файл для контроллера. Следующие команды нужно выполнять в папке с unifi.crt и unifi.key в корне. Не важно, где лежит эта папка, нам потребуется в итоге только финальный файл:

openssl pkcs12 -export -in unifi.crt -inkey unifi.key -out unifi.p12

keytool -importkeystore -deststorepass aircontrolenterprise -destkeypass aircontrolenterprise -destkeystore keystore -srckeystore unifi.p12 -srcstoretype PKCS12 -srcstorepass aircontrolenterprise

Теперь берем полученный keystore и перемещаем его в папку data в корне контроллера. Дефолтное местоположение корневой папки: /usr/lib/unifi. Файл в итоге должен оказаться по следующему пути: /usr/lib/unifi/data/keystore

P12 документик нам не потребуется, можно его удалить или оставить на память, поставив в рамочку.

Теперь рестартим сервис Unifi:

sudo service unifi restart

С контроллером никаких манипуляций больше не потребуется, теперь дело за Nginx. Наш конфиг будет мало отличаться от предыдущего варианта, за исключением факта, что мы уже не будем слепо принимать любой сертификат. Если сертификат self signed, то укажем Nginx доверять ему.

Случай для выданного сертификата

Конфиг Nginx:

upstream unifi {
    server 127.0.0.1:8443;
}

server {
    listen       80;
    server_name  unifi.domain.com;
    server_tokens off;
    rewrite ^ https://$http_host$request_uri?;
}

server {
    listen 443 ssl;
    server_name unifi.domain.com;

    error_log /var/log/unifi/nginx.log;
    access_log /var/log/unifi/access.log;  

    ssl on;
    ssl_certificate /etc/nginx/ssl/server.crt;
    ssl_certificate_key /etc/nginx/ssl/server.key;
    ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 5m;
    add_header Strict-Transport-Security "max-age=31536000" always;
    server_tokens off;

    proxy_ssl_session_reuse on;

    location / {
        proxy_set_header Referer "";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass https://unifi;
    }
}

Повторюсь, что нужно заменить следующие параметры конфига:

  • Путь до сертификата ssl_certificate
  • Путь до ключа сертификата ssl_certificate_key
  • Имя сервера обоих серверов(ssl и редирект) server_name
  • Порт и адрес upstream сервера при необходимости

Теперь self signed сертификат:

Нам потребуются два уже знакомых файла из прошлых шагов: unifi.crt и unifi.key. Для выданного сертификата они нам не требовались, так как Nginx умненький и умеет валидировать их в бюро сертифкации. Здесь же нам придется ему явно их указать.

Конфиг Nginx:

upstream unifi {
    server 127.0.0.1:8443;
}

server {
    listen       80;
    server_name  unifi.domain.com;
    server_tokens off;
    rewrite ^ https://$http_host$request_uri?;
}

server {
    listen 443 ssl;
    server_name unifi.domain.com;

    error_log /var/log/unifi/nginx.log;
    access_log /var/log/unifi/access.log;  

    ssl on;
    ssl_certificate /etc/nginx/ssl/server.crt;
    ssl_certificate_key /etc/nginx/ssl/server.key;
    ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 5m;
    add_header Strict-Transport-Security "max-age=31536000" always;
    server_tokens off;

    proxy_ssl_verify on;
    proxy_ssl_certificate     /etc/nginx/ssl/unifi.crt;
    proxy_ssl_certificate_key /etc/nginx/ssl/unifi.key;
    proxy_ssl_trusted_certificate /etc/nginx/ssl/unifi.crt;
    proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    proxy_ssl_session_reuse on;

    location / {
        proxy_set_header Referer "";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass https://unifi;
    }
}

Как и выше, не забываем заменять параметры конфига на свои:

  • Путь до сертификата ssl_certificate
  • Путь до ключа сертификата ssl_certificate_key
  • Имя сервера обоих серверов(ssl и редирект) server_name
  • Порт и адрес upstream сервера при необходимости
    А также
  • Путь до unifi.crt и unifi.key файлов (их можно положить куда угодно. Я бы рекомендовал сделать отдельную папку в корне Nginx, чтобы ничего не потерялось)

Теперь можно перезагрузить Nginx:

sudo service nginx reload


Вот и все, мы добились желаемого. Наш контроллер теперь доступен по указанному адресу.

Картинка с результатом

image

Буду рад ответить на любые вопросы и принять обратную связь.

Автор: Mehdzor

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js