Конфиг Nginx для нескольких сайтов

2022.07.15
Создадим один конфиг Nginx для нескольких хостов использующих одни и те же правила обработки запросов, для поддоменов и для разных сайтов

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

Реализовать единый конфиг Nginx для нескольких сайтов можно при помощи масок или регулярных выражений директивы server_name

Один конфиг для всех поддоменов

Недавно я писал про Wildcard сертификат Let's Encrypt для всех поддоменов, теперь настало время сделать для них единый конфиг.

Стоит учесть что при одном конфиге для всех поддоменов у них будет одна конфигурация и работать они будут по одним и тем же правилам.

В моем случае поддомены должны были работать на PHP и отдавать статику. Это нормальная схема. А вот случай когда один поддомен должен работать с использованием PHP, а другой на Node.js нужно рассматривать с двумя разными конфигами.

Итак, получается вот такой конфиг:

server {
    listen 80;
    # принимаем все входящие соединения на поддомены byurrer.ru
    # далее используем переменную $host для обозначени домена
    server_name *.byurrer.ru;
    root /var/www/$host/;
    
    # если директории виртуального хоста нет, тогда ответ 444
    # https://nginx.org/ru/docs/http/request_processing.html
    if (!-d /var/www/$host) {
        return 444;
    }
    
    index index.html index.htm index.php;
    
    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include /etc/nginx/fastcgi_params;
    }
}

Этот конфиг вводит ряд ограничений правил:

А теперь вариант конфига с использованием Wildcard сертификата:

# принимаем все входящие соединения с 80 порта (http)
# на все поддомены byurrer.ru и перенаправлем их на https
server {
    listen 80;
    server_name *.byurrer.ru;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name *.byurrer.ru;
    root /var/www/$host/;
    
    if (!-d /var/www/$host) {
        return 444;
    }
    
    index index.html index.htm index.php;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include /etc/nginx/fastcgi_params;
    }

    ssl_certificate /etc/letsencrypt/live/byurrer.ru/fullchain.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/byurrer.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/byurrer.ru/privkey.pem;
}

Один конфиг для нескольких сайтов

Теперь сделаем конфиг для нескольких сайтов при помощи регулярных выражений.

Реглярные выражения в конфиге Nginx совместимы с PCRE, поэтому можно использовать именованные выделения, типа domain как в примере.

server {
    listen 80;
    server_name ~^(?<domain>.+)$;
    
    if (!-d /var/www/$domain) {
        return 444;
    }
    
    index index.html index.htm index.php;

    root /var/www/$domain/;

    location / {
        try_files $uri $uri/ =404;
    }
    
    location ~ \.php$ {
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include /etc/nginx/fastcgi_params;
    }
}

Разница между масками и регулярными выражениями в примерах почти незначительна. С масками мы используем переменную host, а с регулярными выражения именнованное выделение domain.

Редиректы и сертификаты для конфига оставлю в качестве домашнего задания, там не сложно догадаться и трудно ошибиться :)

Результат

Как оказалось, при использовании Nginx вовсе необязательно дублировать конфиг виртуального хоста, если правила работы одинаковы.

Догадаться о таком решении при небольшом опыте использвания оказалось не трудно, а тут еще и русскоязычна документация :)

В телеграм канале DevOps от первого лица можно оставить комментарий или почитать интересные истории из практики DevOps