Начиная с версии Nginx 1.15.9, появилась возможность использовать переменные в директивах ssl_certificate и ssl_certificate_key. Для этого обязательна также openssl версии не ниже 1.0.2
В моём случае возникла ситуация, когда на балансировщике должны слушать домены вида:
*.sub1.rmn-lux.ru
*.sub2.rmn-lux.ru
*.sub3.rmn-lux.ru
Для вышеописанных доменов 4 уровня были выписаны wildcard сертификаты, которые лежат по пути:
ls -1 /etc/nginx/certs
sub1.cer
sub1.key
sub2.cer
sub2.key
sub3.cer
sub3.key
Решил сделать не совсем стандартное и более правильное, как я думаю, решение, чтобы не плодить конфиги, отличие которых друг от друга будет лишь в пути до сертификата и ключа.
Основной итоговый конфиг будет следующим (с условными доменами):
map $ssl_server_name $cert {
~*sub1.rmn-lux.ru sub1;
~*sub1.rmn-lux.ru sub2;
~*sub1.rmn-lux.ru sub3;
}
server {
listen 443 ssl;
server_name .*(sub1|sub2|sub3)\.rmn-lux\.ru;
ssl_certificate "/etc/nginx/certs/$cert.cer";
ssl_certificate_key "/etc/nginx/certs/$cert.key";
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers EECDH:+AES256:-3DES:RSA+AES:RSA+3DES:!NULL:!RC4;
...
}
Пробежимся по основным моментам.
В конструкции map под регулярное выражение попадают все три записи:
*.sub1.rmn-lux.ru
*.sub2.rmn-lux.ru
*.sub3.rmn-lux.ru
и в соответствии от того, какая содержится в строенной переменной $ssl_server_name (по идее также можно юзать $host), заполняется моя пользовательская переменная $cert.
После этого в основном блоке Server прописывается регулярное выражение вида:
.*(sub1|sub2|sub3)\.rmn-lux\.ru
под которое попадает любое выражение на все три поддомена, к примеру, такие:
1.sub1.rmn-lux.ru
2.sub2.rmn-lux.ru
3.sub3.rmn-lux.ru
и соответственно подгружается правильный сертификат.
Очень удобно проверять regex на онлайновом ресурсе, вот один, вот второй (рекомендую второй).
Схема вышла несложная и простая для чтения и понимания, в отличие от той, если бы пришлось городить 3 таких конфига с минимальными отличиями.
Стоит иметь ввиду, что при использовании такого способа,во время каждой операции TLS-рукопожатия будет загружаться сертификат, что будет влиять на производительность.
Также при настройке у меня возникли некоторые нюансы, о них ниже.
Если в поле server_name прописано несколько доменов, например, вот так
server_name *.sub1.rmn-lux.ru *.sub2.rmn-lux.ru *.sub3.rmn-lux.ru;
то в таком случае даже если map отработает корректно, домен в server_name будет выбран тот, который стоит первый в списке (по умолчанию), и соответственно с сертификатом возникнет проблема. Так происходит из-за особенностей работы протокола TLS: сначала устанавливается TLS-соединение, а потом только прилетает http-запрос с именем сервера, а потому nginx не может знать имени сервера заранее и предлагает сертификат сервера по умолчанию. Именно поэтому была применена регулярка для server_name.