Цель: Предоставить конфигурацию виртуального сервера Nginx для работы Битрикс-cms в связке Nginx+PHP-FPM. Который в прочем подойдёт и для связки Nginx+Apache2, с небольшими доработками.

Целевая аудитория: Администраторы серверов, продвинутые администраторы сайтов, программисты.

Cтатей на эту тему достаточно, но если смотреть не официальные, то там как правило содержатся ошибки, а в официальных полно if которые в Nginx использовать не желательно. Надеюсь после того как я выложу данный конфиг к связке Nginx+PHP-FPM станут относиться серьёзнее.

Вот официальный конфиг для работы композитного кэша с отдачей через nginx.

Я покажу реализацию отдачи файлового композитного кэша. В целом отдача с memcached делается по аналогии. В конфигурации отдачи файлового кэша я насчитал 11 if, от которых я и избавился переделав их на map.

Начну с упрощённого варианта ЧПУ для тех кому нужна просто связка Nginx+PHP-FPM без отдачи композитного кэша через Nginx. Подразумевается что секция server уже настроена, с доменными именами и передачей в php-fpm.

location / { try_files $uri $uri/ /bitrix/urlrewrite.php$is_args$args; }

Как не удивительно смотря на те полотна конфигов которые мне попадались, этого достаточно чтобы битрикс корректно заработал. Если нужен редирект с index.php и index.html на без, то нужно ещё дописать вот эту строку:

if ($request_uri ~ ^(.*)/index.(html|php)) { return 301 $1/$is_args$args; }

К сожалению тут достойной замене if нет. Но данная строчка работает не создавая проблем.

Пример минималистичной конфигурации
server {
	listen 80;
	server_name site.ru;
	root   /var/www/site.ru/;
	index index.php;
	location ~ \.php$ {
		include /etc/nginx/fastcgi_params;
		fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
		fastcgi_index index.php;
		fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
		fastcgi_intercept_errors on;
	}
	if ($request_uri ~ ^(.*)/index.(html|php)) { return 301 $1/$is_args$args; }
	location / { try_files $uri $uri/ /bitrix/urlrewrite.php$is_args$args;	}
	location ~* @.*\.html$ { internal; }
}


Хочу подчеркнуть что это именно минималистичная конфигурация без правил для статики, сжатия, и я там прикрыл только файлы композитного кэша от прямого доступа. Конфигурация которая прикрывает определённые места от прямого доступа через nginx довольно индивидуальна. У меня есть вот такой набор который может кому-то подойти. Но использовать нужно аккуратно с осознанием дела. Учитите что внесение данных локейшенов в свою конфигурацию может привести к неработоспособности сайта или части его функций.

Фрагмент конфига закрывающий доступ к файлам которые должны быть доступны только при обращении из PHP
location ~ \.php$ {
	location ~* /\.\./ { internal; }
	location ~ /\.[^/]+$ { internal; }
	location ~* ^/upload/1c_[^/]+/ { internal; }
	location ~* ^/(bitrix/(cache|images|tmp)|upload)/ { internal; }
	location ~* ^/bitrix/(footer|header|license_key)\.php$ { internal; }
	location ~* ^/(bitrix|local)/components/(.*)/(.*)/(class|component)\.php$ { internal; }
	location ~* ^/(bitrix|local)/(backup|blocks|bx_cloud_upload|local_cache|module|modules|managed_cache|php_interface|public|stack_cache)/ { internal; }
	include /etc/nginx/fastcgi_params;
	fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
	fastcgi_index index.php;
	fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
	fastcgi_intercept_errors on;
}
location ~* \.(hg|svn|git|bzr)$ { internal; }
location ~* /\.\./ { internal; }
location ~* @.*\.html$ { internal; }
location / {
	location ~* ^/(bitrix|local)/(backup|blocks|bx_cloud_upload|local_cache|module|modules|managed_cache|php_interface|public|services|stack_cache)/ { internal; }
	location ~ /\.[^/]+$ { internal; }
	location ~* ^/upload/1c_[^/]+/ { internal; }
	try_files $uri $uri/ /bitrix/urlrewrite.php$is_args$args;
}


Ну и конечно пример location для статических файлов

location ~* \.(jpg|jpeg|png|tiff|gif|webp|xml|html|yml|ogg|ogv|svg|svgz|eot|otf|woff|woff2|mp4|ttf|rss|atom|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|rtf|pdf|txt|js|css|bmp|pnm|pbm|ppm)$ {
	access_log off;
	expires 97d;
}

Теперь перейдём к конфигу для работы композита с отдачей файлов кэша через nginx. Первым делом необходимо определить можно ли отдавать данному запросу композитный кэш или его нужно отправить на обработку через php. Для этого в Nginx в секции http добавим несколько map, а так же несколько директив:

modern_browser_value "modern";
modern_browser msie 10.0;
modern_browser unlisted;
map "$cookie_BITRIX_SM_LOGIN:$cookie_BITRIX_SM_UIDH:$cookie_BITRIX_SM_CC" $storedAuth {
	default "";
	"~*:*:Y" "";
	"~*:*:*" 1;
	"~*:*:" 1;
}
map "$request_method:$http_bx_action_type:$cookie_BITRIX_SM_NCC:$http_x_forwarded_scheme:$modern_browser:$storedAuth" $usecache {
	default "1";
	"~GET:::*https*" "1";
	"~GET:::*:*:" "";
}

Далее уже непосредственно в секции server прописываем


set $i "index@";
location / { try_files /bitrix/html_pages/$host$uri$i${args}.html /bitrix/html_pages/$host$uri$i${args}=.html /bitrix/html_pages/$host$uri/$i${args}.html$usecache /bitrix/html_pages/$host$uri/$i${args}=.html$usecache $uri $uri/ /bitrix/urlrewrite.php$is_args$args; }

Ну и для понимания как примерно будет выглядеть минимальная конфигурация секции server

Пример минималистичной конфигурации с отдачей файлового композитного кэша через nginx
server {
	listen 80;
	server_name site.ru;
	root   /var/www/site.ru/;
	index index.php;
	location ~ \.php$ {
		include /etc/nginx/fastcgi_params;
		fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
		fastcgi_index index.php;
		fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
		fastcgi_intercept_errors on;
	}
	if ($request_uri ~ ^(.*)/index.(html|php)) { return 301 $1/$is_args$args; }
	set $i "index@";
	location / { try_files /bitrix/html_pages/$host$uri$i${args}.html /bitrix/html_pages/$host$uri$i${args}=.html /bitrix/html_pages/$host$uri/$i${args}.html$usecache /bitrix/html_pages/$host$uri/$i${args}=.html$usecache $uri $uri/ /bitrix/urlrewrite.php$is_args$args; }
	location ~* @.*\.html$ { internal; }
}

Буду рад вопросам и предложениям по поводу данного конфига, а так же за радость посмотрю Ваши наработки.

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


  1. inkvizitor68sl
    03.02.2019 11:42
    +1

    > if ($request_uri ~ ^(.*)/index.(html|php)) { return 301 $1/$is_args$args; }
    Почему бы этот if не убрать, попробовав завести соответствующий location?


    1. castomi Автор
      03.02.2019 14:49

      Ну хотя бы потому что такой if нельзя заменить локейшеном. Цитирую документацию nginx

      $request_uri — первоначальный URI запроса целиком (с аргументами)


      Если провернуть тоже самое с локейшеном, то после редиректа запрос снова будет попадать в этот же локейшен и зациклится. Что вызовет ошибку 500.

      Попробую наглядно…

      запрашиваем /index.php
      В обоих случаях и с if и location произойдёт редирект на /

      Теперь запрос в / и $request_uri тут равно /, а значит редиректа не будет, в случае с локейшеном у нас отрабатывает директива index и происходит внутреннее перенаправление на index.php и снова идёт запрос на обработку в location, а там редирект)… и так до бесконечности)

      Если вдруг Вы нашли способ избавиться от такого if и при этом не сломать работу сайта, поделитесь) Буду признателен. Уверен что не только я.


    1. castomi Автор
      04.02.2019 00:15

      Решил всё таки заморочиться и сделать без if. Вот что у меня получилось

       map $request_uri $index {
        default "";
        "~(.*)/index.(html|php)" "$1/$is_args$args";
       }
       map $index $return {
        default "1";
        "" "";
       }
      
      location @index { return 301 $index; }
      location / { try_files $return$uri $return$uri/ $return/bitrix/urlrewrite.php$is_args$args @index; }
      


      Пока применил у себя на дев-сайте. Страшно сразу выбрасывать на прод, помучаю сначала.

      Позже добавлю в статью если нормально всё работать будет.

      P.S. Немного поправил от первоначального состояния. Пересмотрите те кто смотрел первоначальный вариант комментария. Оттестирую этот вариант у себя и если всё хорошо. допишу его в статью.


  1. mvs
    04.02.2019 13:29

    Не нужно тащить fastcgi_index index.php и fastcgi_intercept_errors on в location'ы, достаточно указать на уровне server.
    internal в большинстве location'ов лучше заменить на deny all.


    1. castomi Автор
      04.02.2019 13:32

      Собственно это образец. И я его взял с дефолтного локейшена php в Debian. Суть моего подхода излагается выше и кратко, всего одним локейшеном.