Конфигурация сайта: конфигурация сервера

Продолжим, пожалуй, разговор про конфиги (часть 1, часть 2.1, часть 2.2).

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

Законфигурируем, пожалуй, какую-нибудь конфигурацию :) Допустим, конфигурацию веб-сервера и пусть сервером этим будет Nginx.

Задача более конкретно:

  • Разрабатываем сайт example.ru
  • Я разрабатываю в своей локальной версии — go.example.local, а другой разработчик в своей — hugo.example.local + ещё верстальщик с дизайнером
  • Есть у нас общая локальная версия example.local на локальном сервере.
  • И есть тестовый поддомен test.example.ru, на котором заказчик проверяет последнии фишки, перед тем, как их зальют собственно на example.ru
  • test.example.ru находится в открытом доступе и его следует закрыть хотя бы с помощью htpasswd
  • Все загружаемые изображения лежат на поддомене «img.*», то есть img.example.ru, img.go.example.local и т.д.

Итак, у нас уже 7 версий сайта. Каждая на своём хосте. И для каждого хоста нужно иметь nginx-конфиг. Все конфиги имеют одинаковую структуру, но отличаются частностями.

Что мы будем их 7 раз копипастить и корректировать? А любое изменение в структуре вручную в каждую версию вносить? К чёрту! Давайте всё автоматизируем.

Шаблон

Для начала нарисуем шаблон конфига:

server {
 
    listen {{ listen }};
    server_name {{ server_name }};
    root {{ root }};
 
    {{ IF htpasswd }}
    # если надо закрыть от посторонних глаз - закрываем
    auth_basic "Password, please!";
    auth_basic_user_file {{ htpasswd }};
    {{ END }}
 
    # К картинкам и стилям доступ обычный
    location ~* ^/(i|css|js)/ {
        expires 7d;
    }
 
    # К robots.txt также
    location = /robots.txt {
    }
 
    # Всё остальное перехватываем на файл index.php
    location / {
        fastcgi_pass   {{ fastcgi_pass }};
        include        fastcgi_params;
        fastcgi_param  SCRIPT_FILENAME $document_root/index.php;
        fastcgi_read_timeout 600;
    }
}
# Upload-поддомен
server {
    listen {{ listen_upload }};
    server_name {{ server_name_upload }};
    root {{ root_upload }};
 
    location / {
    }
}

В примере мы воспользовались синтаксисом шаблонизатора Blitz. Вообще можно хоть на Smarty, хоть на чём угодно.

Параметры

Теперь вспомним, что мы говорили про платформы. У нас получается 7 конечных платформ (4 у разработчиков + local + test + рабочий сайт). Наследуются они от базовой конфигурации. Раздел этой базовой конфигурации, отвечающей за сервер, сейчас и набросаем (всё что NULL — требует переопределения для каждой платформы):

return array(
 
    'listen'      => 80,   // обычно у всех будет 80-й порт
    'server_name' => null,
    'root'        => null,
 
    'htpasswd'    => false, // у большинства htpasswd не нужен
 
    'fastcgi_pass' => 'php-fpm', // у большинства PHP-FPM, но может быть, например, SPAWN-FCGI
 
    'listen_upload'      => 80,
    'server_name_upload' => null,
    'root_upload'        => null,
);

А теперь определяем настройки конкретной платформы (например, для go.example.local):

return array(
    'server_name' => 'go.example.local',
    'root'        => '/home/go/go.example.local/www',
 
    'server_name_upload' => 'img.go.example.local',
    'root_upload'        => '/home/go/go.example.local/img',
);

Для test.example.ru прописываем путь до htpasswd.

Генерация config-файла

Теперь осталось написать скриптик, который берёт итоговую конфигурацию, берёт шаблон, пропускает это всё через шаблонизатор и сохраняет результат в файлик.

Остаётся запустить этот скриптик в нужный момент, скопировать результирующий файл в каталог с конфигами nginx’а и перезапустить сервер. Можно повесить это всё на хук в системе контроля версий (не говорите только, что при таком количестве народа её нет).

Что и файл каждый раз копировать лениво? Автоматически скопировать в каталог nginx’а не выйдет — прав скорее всего нет. Поставить права на запись — некошерно как-то, да и всё своё лучше носить с собой.

Поэтому создаём у себя каталог, например, local, игнорируем в системе контроля версий и все подобные генерируемые файлы храним там. В nginx’е же делаем inclide всех подобных файлов или делаем на них символические ссылки.

Мы избавились от лишней ручной работы. Мы молодцы.

Промежуточные платформы

Вспомним теперь про промежуточные платформы.

У нас два ярко выраженных типа платформ:

  1. Dev: разработчики и example.local. Для пущего объединения, предположим что все они работают на одном сервере, а разработчики вносят изменения, подключившись через samb’у.
  2. Prod: это, конечно, рабочий сайт. А ещё — test.example.ru — он лежит на том же сервере, должен работать в том же окружении и с теми же настройками, чтобы быть максимально приближенном к конечному результату.

Возьмём и сделаем эти две промежуточные платформы.

Зачем дизайнеру и верстальщику отдельные img-поддомены? Зачем им заполнять их тестовыми данными, а в случае изменения формата переконверчивать их. Им только вывод настраивать надо. Сделаем им один и тот же поддомен вместе с example.local, и только у разработчиков переопределим его.

return array(
    'server_name_upload' => 'img.go.example.local',
    'root_upload'        => '/home/go/go.example.local/img',
);

fastcgi_pass также на всём сервере будет один.

Шаблоны параметров

Заметим ещё несколько закономерностей: имя поддомена обычно имеет вид «img. + хост», порт поддомена обычно тот же, что и у основного хоста. Хосты разработчиков располагаются на поддоменах одного домена и пути к ним обычно имеют один формат. Мы избавились от множества рутины, но по прежнему копипсинтаксисомастим. Возьмём и впихнём Blitz ещё и в параметры:

/* Базовая конфигурация */
return array(
 
    'base_server_name'   => null,
    'prefix_server_name' => null,
    'www_home'           => null,    
    'prefix_upload'      => 'img.',
 
    'listen'       => 80,
    'server_name'  => '{{ prefix_server_name }}{{ base_server_name }}',
    'project_home' => '{{ www_home }}/{{ server_name }}',
    'root'         => '{{ project_home }}/www',
 
    'htpasswd'     => false,    
    'fastcgi_pass' => 'php-fpm',
 
    'listen_upload'      => '{{ listen }}',
    'server_name_upload' => '{{ prefix_upload }}{{ server_name }}',
    'root_upload'        => '{{ project_home }}/img',
);

Теперь конфигурация DEV-платформ:

return array(
    'base_server_name' => 'example.local',
);

И конфигурация платформы разработчика go:

return array(
    'prefix_server_name' => 'go.',
    'www_home'           => '/home/go',    
);

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

array(
    'base_server_name'   => 'example.local',
    'prefix_server_name' => 'go.',
    'www_home'           => '/home/go/',    
    'prefix_upload'      => 'img.',
 
    'listen'       => 80,
    'server_name'  => '{{ prefix_server_name }}{{ base_server_name }}',
    'project_home' => '{{ www_home }}/{{ server_name }}',
    'root'         => '{{ project_home }}/www',
 
    'htpasswd'     => false,    
    'fastcgi_pass' => 'php-fpm',
 
    'listen_upload'      => '{{ listen }}',
    'server_name_upload' => '{{ prefix_upload }}{{ server_name }}',
    'root_upload'        => '{{ project_home }}/img',
);

В скриптике же генерации nginx-конфига просто сперва пропускаем каждый параметр через шаблонизатор, передавая каждый раз в качестве переменных сам этот массив. И в итоге получаем:

array(
    'base_server_name'   => 'example.local',
    'prefix_server_name' => 'go.',
    'www_home'           => '/home/go/',
    'prefix_upload'      => 'img.',
 
    'listen'       => 80,
    'server_name'  => 'go.example.local', // {{ prefix_server_name }}{{ base_server_name }}
    'project_home' => '/home/go/go.example.local', // {{ www_home }}/{{ server_name }}
    'root'         => '/home/go/go.example.local/www'. // {{ project_home }}/www
 
    'htpasswd'     => false,    
    'fastcgi_pass' => 'php-fpm',
 
    'listen_upload'      => 80, // {{ listen }}
    'server_name_upload' => 'img.go.example.local', // {{ prefix_upload }}{{ server_name }}
    'root_upload'        => '/home/go/go.example.local/img // {{ project_home }}/img
);

Ну и сам итоговый конфиг:

server {
 
    listen 80;
    server_name go.example.local;
    root /home/go/go.example.local/www;
 
    # К картинкам и стилям доступ обычный
    location ~* ^/(i|css|js)/ {
        expires 7d;
    }
 
    # К robots.txt также
    location = /robots.txt {
    }
 
    # Всё остальное перехватываем на файл index.php
    location / {
        fastcgi_pass   php-fpm;
        include        fastcgi_params;
        fastcgi_param  SCRIPT_FILENAME $document_root/index.php;
        fastcgi_read_timeout 600;
    }
}
# Upload-поддомен
server {
    listen 80;
    server_name img.go.example.local;
    root /home/go/go.example.local/img;
 
    location / {
    }
}

Другие сервисы

Какие там у нас ещё используются сервисы, требующие файла конфигурации? Sphinx? Ещё какие-то? Так тоже самое с ними.

2 комментария »

  • Offtopic: Олег, хорошо бы тебе на этот блог добавить кнопочки закладочных сервисов. Только не говори, что ты пишешь для себя :)

    artoodetoo, 19.02.2012, 10:31

  • artoodetoo, я простой гуманитарий, я даже не знаю, что такое закладочные сервисы.

    vasa_c, 19.02.2012, 12:14

Leave a comment