Как добиться DRY в конфигурации nginx для множества однотипных сайтов?

При переходе с nginx+apache на nginx+php-fpm возникла проблема с конфигами nginx.

На сервере ~5 пользователей, у каждого по несколько сайтов.
Половина сайтов имеют простую структуру:
/home/user_name/sites/example.com/log/...
/home/user_name/sites/example.com/tmp/...
/home/user_name/sites/example.com/www/...

Другая половина написана на yii, имеют backend и структура следующая:
/home/user_name/sites/example.com/backend/log/...
/home/user_name/sites/example.com/backend/tmp/...
/home/user_name/sites/example.com/backend/www/...

/home/user_name/sites/example.com/frontend/log/...
/home/user_name/sites/example.com/frontend/tmp/...
/home/user_name/sites/example.com/frontend/www/...

Структура конфигов nginx:
/etc/nginx/nginx.conf
/etc/nginx/sites/default.conf
/etc/nginx/sites/andrey/site.ru.conf
/etc/nginx/sites/andrey/example.com.conf
/etc/nginx/sites/ivan/example.ru.conf
...

/etc/nginx/nginx.conf:
...
http {
    ...
    include sites/default.conf;
    include sites/andrey/*.conf;
    include sites/ivan/*.conf;  
}

Хочу сделать так, чтобы конфиг любого сайта (к примеру /etc/nginx/sites/ivan/example.ru.conf) выглядел вот так:
set $user_name ivan;
set $site_name example.ru;

include  sites/basic_server.conf; # конфиг сервера для первой схемы
# или 
include  sites/advanced_server.conf; # конфиг сервера для второй схемы с бекэндом

Для примера, sites/basic_server.conf:
listen 80;
server_name $site_name www.$site_name;

access_log /home/$user_name/sites/$site_name/log/nginx_access.log main;
error_log /home/$user_name/sites/$site_name/log/nginx_error.log;

root /home/$user_name/sites/$site_name/www;
index index.php index.html;

if ($host = 'www.$site_name') {
    rewrite ^/(.*)$ http://$site_name/$1 permanent;
}

location ~ \.php$ {
    include conf.d/fastcgi.conf;
}


Вопросы:
1. Объявлять переменные (set) нельзя вне секции server { }. Как быть?
2. Конструкция server_name $site_name www.$site_name; не срабатывает (вернее не работают переменные в этой строке и вместо нужного сайта nginx отдает default). Если поменять переменные на нормальные значения - все ок.
3. Мне не дает покоя еще намного более DRY вариант из области фантастики: никаких отдельных конфигов, только единый nginx.conf в котором задаем ассоциативный массив аля:
set $sites array(
array('user' => ivan, 'name' => 'example.com', 'type' => 'basic'),
array('user' => andrey, 'name' => 'example.ru', 'type' => 'advanced'),
);

Который nginx обрабатывает и с помощью if подключает нужный конфиг (basic или advanced).
Может, nginx умеет работать с массивами и такое возможно?
4. Как вы добивались dry в конфигурации nginx? Какая у вас структура сайтов и схема подключения новых?
  • Вопрос задан
  • 2955 просмотров
Решения вопроса 2
grossws
@grossws
Можно не заморачиваться и генерировать шаблонизатором из SCM (типа chef/puppet/ansible/salt/cfengine/bcfg2)
Ответ написан
Комментировать
@miksir
IT
Генерировать чем-то еще. Это в какой-то мере полуофициальная позиция разработчиков nginx. Но если хочется все же поиграться с единым конфигом - смотрите в сторону одного server блока и подстановки туда всяких переменных (типа рута и т.п.) через map. Например,
map $host $newroot {
hostnames;
default /home/notfound/www/;
.mysite.ru /home/user1/mysite.ru/www/;
include user2_map.conf;
}
server {
  listen 80 default;
  server_name _:
  root $newroot;
}

Да, и вот такое
if ($host = 'www.$site_name') {
    rewrite ^/(.*)$ http://$site_name/$1 permanent;
}

лучше описать отдельно
server {
   server_name ~^www\.(?<newhost>.+)$;
   return 301 $scheme://$newhost$uri$is_args$query_string;
}
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
@Nc_Soft
Мне кажется надо в default разруливать root и прочее по хосту.
Но вообще isp не парится и прописывает каждый сайт, ничего тут страшного нет, зато гибко.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы