Пользователь
0,0
рейтинг
23 апреля 2012 в 19:07

Администрирование → Один конфиг Nginx для работы с кучей разных сайтов

Если вам приходилось настраивать Nginx под нужды веб-студии, сеошников или киберсквоттеров ;), то уже наверняка знаете про символ подчёркивания в качестве server_name. Тем не менее несколько других небесполезных приёмчиков из моего примера почерпнуть можно.

Чтоб создать новый сайт на сервере с такой конфигурацией, достаточно создать директорию с именем сайта и залить в неё содержимое. А конфигурационный файл остаётся единственным и неизменным.

Конфиг делает следующее:
1. Отрезает «www» от адреса, дабы сервер нашел директорию с сайтом невзирая на эти буквы в URL.
2. Выдаёт отдельную страничку при запросе несуществующего сайта.
3. Делает стандартный редирект на index.php в корне сайта при запросе несуществующего пути.
4. Перенаправляет запрос на php-fpm при вызове .php файлов.
5. Добавляет возможность обработки .htm(l) файлов как PHP.



Директории для сайтов создаются в /var/www/all/.
Симлинки с www на без www не требуются.
В директорию /var/www/all/undefined кладётся сайт-затычка при вызове несуществующих сайтов.
Если в каком-то сайте надо обрабатывать все html файлы как PHP, то в корень этого сайта надо положить пустой файл «.parse_html».
Ниже приведён конфигурационный файл сайта. Его можно положить в /etc/nginx/sites_enabled/default.

Ограничение, пожалуй, одно: рерайт только на index.php в корне. Но для 99.9% сайтов, что мне приходится окучивать, этот вариант подходит.

server {
	listen 80 default; # этот конфиг - умолчательный для 80 порта
	server_name _;  # хитрый ключик, обозначающий, что этот конфиг применим для любого сайта

	set $sathost $host;  # В sathost будет лежать имя сайта. Так же должна называться директрия с сайтом
	# убираем www
	if ( $host ~ ^(www\.)?(.+)$ ) {
		set $sathost $2;
	}
	
	root   /var/www/all/$sathost; # конень сайта определяем автоматически
	index index.php index.html index.htm; # в каком порядке искать индексные файлы

	access_log off;	
#	access_log /var/log/nginx/all/$sathost_access.log; # такая комбинация, к сожалению, не работает. жду пока допилят
	error_log  /var/log/nginx/all.error.log error;

	location / {   # правила ниже применяются для любых запросов
                if (!-d /var/www/all/$sathost) { # если не нашли директорию с именем запрошенного сайта
		# переадресуем на сайт под названием undefined, который лежит в /all/undefined
		set $sathost undefined;
		rewrite ^ /index.php last;
                }

		# начало rewrite
		set $rflag 1;   # так как логического объединения в условных выражениях нет, то вводим переменную для сложения двух условий. flag указывает на необходимость сделать переадресацию
		if (-e $request_filename) { # если есть запрошенный файл, то переадресация не нужна
			set $rflag 0;
		}
		if (!-f /var/www/all/$sathost/index.php) { # если нет index.php в корне сайта, то переадресация тоже не нужна, ибо некуда
			set $rflag 0;
		}
		if ($rflag = 1) {  #
			rewrite  ^ /index.php  last;
		}
		# конец rewrite

		if (-f $request_filename) { # для статических файлов включаем кэш на час
			expires  1h;
			break;
		}
	}

	location ~ \.php$ { # этот блок сработает при запросе .php файлов
		root   /var/www/all/$sathost;
		fastcgi_pass   127.0.0.1:9000; # тут висит php-fpm
		fastcgi_index  index.php;
		fastcgi_param  SCRIPT_FILENAME  /var/www/all/$sathost/$fastcgi_script_name;
		include fastcgi_params;
		break;
	}

	location ~ \.htm(l?)$ { # этот блок работает при вызове .html или .htm
		# если в корне сайта лежит файл «.parse_html», то обрабатываем HTML как PHP
		fastcgi_param  SCRIPT_FILENAME  /var/www/all/$sathost/$fastcgi_script_name;
		include fastcgi_params;
		if (!-f $request_filename) { # даже если запросили .html, это не значит что он у нас есть
		    # соотвественно, если файла нет, то тоже делаем rewrite
		    rewrite  ^ /index.php  last;
		}
		if (-f /var/www/all/$sathost/.parse_html) { # проверяем на наличие метки
		    # если в директории сайта лежит ключевой файлик, то все html обрабатываем как php
		    fastcgi_pass   127.0.0.1:9000;
		}
		break;
	}
	

	location ~ /\.ht { # в файлах, начинающихся на «.ht» могут лежать пароли или оставшиеся настройки от Апача - отдавать это ни к чему.
		deny  all;
	}
}
unwrecker @unwrecker
карма
0,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Администрирование

Комментарии (28)

  • +17
    Для разработки наверное кому-нибудь пригодится, но в продакшене такое лучше не использовать.
    • +4
      Почему нет, если продакшн состоит из 10000 сайтов с 10 хитами в день на каждом?
      • +13
        У кого десятки тысяч сайтов — скорее всего знают, как настраивать nginx. Я предостерегаю новичков от использования таких конфигов.
        • +3
          А можно всё-таки услышать хоть один агрумент против такого конфига?
          Пусть это будет не 10000 сайтов, а просто 10. Допустим, что способы вызова скриптов везде одинаковые. Чем такой конфиг будет хуже десяти отдельных?
          • +5
            1. Он не читабелен. Подобные вопросы так часто всплывают в рассылке, что привело к появлению в FAQ данного пункта: nginx.org/en/docs/faq/variables_in_config.html Не надо программировать на конфигах nginx.

            2. Он будет работать медленнее, потреблять больше ресурсов, чем 10 отдельных. Лучше написать скрипт, который вам сгенерирует N конфигов перед стартом nginx, чем использовать такие конструкции.

            Из этого есть одно исключение: ооочень, очень много сайтов. Для 10к сайтов потребление памяти будет заметно выше со статическими конфигами.
            • +10
              И еще не забываем об If Is Evil.
            • +13
              И еще не забываем, что php-fpm будет работать от одного пользователя: группы в одном пуле.
            • –3
              Ну так оно на самом деле и существует. На всякие приличные сайты свой конфиг (без злостных ifов :)) и свой пул (ибо нефиг). На многотысячную свалку — этот конфиг и сэйфмод в PHP.
  • +12
    server {
        server_name ~^(www\.)?(?<domain>.+)$;
    
        location / {
            root /sites/$domain;
        }
    }
    

    • +2
      Добавить в это include и вполне себе рабочее продакшн решение
    • +6
      server_name ~^(?:www\.)?(?<domain>.+)$;

      Не зачем лишнюю группу создавать.
    • 0
      Нет предела совершенству ^) Спасибо
    • 0
      В логах при таком конфиге server_name страшно выглядит. А именно — "^(www\.)?(?.+)$". Не информативно абсолютно.
  • +5
    Ура! Вы, получили первый уровень в nginx, теперь получите еще 30 и вперед делиться конфигами
  • +7
    location ~ /\.ht
    а какже .git, .svn, .ftpaccess? Добро пожаловать милости просим?
    Все файлы с точкой в начале нужно считать скрытыми

    location ~ /\. {
    deny all;
    access_log off;
    log_not_found off;
    }

    Реврайт на www у вас 302, а обычно надо 301 чтобы происходила склейка (и обратите внимае тут в регулярке используется 1 карман, вы же почему-то www в скобки тоже взяли)

    if ($host ~* www\.(.*)) {
    set $host_without_www $1;
    rewrite ^(.*)$ http://$host_without_www$1 permanent;
    }

    Вместо if (-e $request_filename) рекомендуется try files.
    И вообще, в конфиге много магии, вкупе с 1 пуллом и юзером это делает его малопригодным для продакшена.
    • 0
      Ну, пожалуй, от магии автоматического разбиения на пулы я бы не отказался :)

      Реврайт 301 нужен именно что для склейки, а в моём варианте её нет.
    • 0
      >> rewrite ^(.*)$ http://$host_without_www$1 permanent;

      Не нужен тут реврайт (он вообще практически никогда не нужен).

      return 301 http://$host_without_www$1

      Ну и уже выше показали, как имя хоста без www получить регуляркой в server_name, безо всяких if-ов.
  • +2
    А так?
    set $logName $sathost"_access.log";
    access_log /var/log/nginx/all/$logName;
    

    А вообще, Вам бы ещё не мешало разобраться с try_files, вместо этого огорода, ну и да, полистать чужие конфиги. Новичкам бы я этот не советовал.
    • 0
      Сработает, и так тоже (не надо доп. переменную создавать).
      access_log "/var/www/$sathost/logs/access.log";
      

      а вот с «error_log» такое уже не пройдет.
  • +2
        server_name _;  # хитрый ключик, обозначающий, что этот конфиг применим для любого сайта
    
    


    Нет. Это имя выбирают, чтобы с другими server не пересекалось.

        listen 80 default; # этот конфиг - умолчательный для 80 порта
    


    Вот этот ключ говорит nginx, что если подходящий server не найдет, использовать этот.
    • 0
      Вместо default нужно использовать default_server.
      До версии 0.8.21 этот параметр назывался просто default.

      • 0
        Это уже детали. Просто много людей думают, то "_" в качестве имени сделают этот сервер по-умолчанию, а потом пишут много вопросов на всяких askdev и.т.д.
  • +2
            fastcgi_param  SCRIPT_FILENAME  /var/www/all/$sathost/$fastcgi_script_name;
            include fastcgi_params;
    

    Потенциально бажный кусок. include после всех директив приведет к переопределению ранее инициированных значений.

    Правильно делать в include на файл в который вынесены общие правила и дальше ниже по конфигу для конкретного location задать требуемые значения.

    Вот кусок из моих конфигов:
    server {
    	...
        location / {
            index       index.php;
            try_files   $uri $uri/ @backend;
        }
    
        location ~ \.php$ {
            try_files       $uri @backend;
            fastcgi_pass    unix:/var/www/tmp/$server_name.fastcgi.socket;
            fastcgi_index   index.php;
    
            include         /etc/nginx/fastcgi_params;
    
            fastcgi_param   SCRIPT_FILENAME     /www/$server_name/public$fastcgi_script_name;
            fastcgi_param   QUERY_STRING        q=$uri&$args;
            fastcgi_param   REQUEST_URI         q=$uri&$args;
            fastcgi_param   DOCUMENT_ROOT       /www/$server_name/public;
        }
    
        location @backend {
            fastcgi_pass    unix:/var/www/tmp/$server_name.fastcgi.socket;
            fastcgi_index   index.php;
    
            include         /etc/nginx/fastcgi_params;
    
            fastcgi_param   SCRIPT_FILENAME     /www/$server_name/public/index.php;
            fastcgi_param   SCRIPT_NAME         index.php;
            fastcgi_param   QUERY_STRING        q=$uri&$args;
            fastcgi_param   REQUEST_URI         q=$uri&$args;
            fastcgi_param   DOCUMENT_ROOT       /www/$server_name/public;
        }
    }
    
    • +2
      Правильно вообще не дублировать значения. Они не переопределяются. Если у вас дважды указано какое-то значение на одном уровне (скажем в include и так), то оба значения будут отправлены на бэкенд в порядке их следования, а там уже зависит от бэкенда какое из них он возьмет — первое или последнее.
      • 0
        Что отправит как есть на бэкэнд это-то понятно. Но в данном контексте мы говорим о связке с PHP который переопределит данные. В результате конфига как у автора возможна ситуация, когда после добавления данных в общий конфиг который include-тся сломается один из location-ов. Что для не очень опытного админа чревато долгим чесанием головы.
  • 0
    Если вам приходилось настраивать Nginx под нужды… сеошников

    3. Делает стандартный редирект на index.php в корне сайта при запросе несуществующего пути.


    Что-то бред какой-то. Такой редирект явно не на пользу сео.
    Если путь не существует — надо на 404 страницу слать людей.
    • 0
      Хотя блин, вопрос конечно спорный. С точки зрения пользы для юзера — полезнее показать ему главную. С точки зрения поисковой системы — лучше не смешивать и на ошибки отдавать специальную страницу с 404 ответом сервера.
      • +2
        Не нужно показывать ему главную. Нужно показать ему 404-ую в рамках которой нужно попытаться устранить ошибку. К примеру, если страница была, но её удалили, то нужно об этом явно написать и есть у страницы есть новый адрес, то указать ссылку на него. При тихом редиректе на главную совершенно будет не понятно, что же пошло не так.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.