Главная/Статьи/Настройка .htaccess для 1С-Битрикс: полное руководство

Настройка .htaccess для 1С-Битрикс: полное руководство

Оптимальная конфигурация .htaccess: редиректы, ЧПУ, сжатие, кэширование браузера. Готовые примеры для production.

ДМ
Дмитрий Мещеряков
📅 4 августа 2019 г.📖 9 мин чтения

.htaccess — файл, в который на боевых проектах слоями оседает всё: редиректы от прошлого подрядчика, правила от сеошника, «защита», скопированная с форума в 2014 году. Разбирать такой файл приходится обычно в момент, когда сайт уже отдаёт 500.

Ниже — разбор того, что действительно нужно в .htaccess для Битрикса, что туда попадает по инерции, и три директивы, которые чаще всего и кладут сайт при переезде на новый сервер.

💡 Совет

Сначала проверьте, читается ли ваш .htaccess вообще. На типовой конфигурации BitrixVM перед Apache стоит nginx, и статику — картинки, CSS, JS — он отдаёт сам, не доходя до Apache. Всё, что вы напишете в .htaccess про сжатие и заголовки кэширования для статических файлов, в этом случае просто не выполнится, а вы будете полдня выяснять, почему заголовки не меняются. Проверяется одной командой: curl -I https://site.ru/bitrix/js/main/core/core.js — по заголовку Server видно, кто ответил.

И второе: .htaccess читается Apache при каждом запросе, для каждой директории в пути. Если у вас есть доступ к конфигу виртуального хоста — правила там работают быстрее, а AllowOverride None убирает лишние обращения к диску.

Расположение файла

Файл .htaccess находится в корне сайта. Редактируйте через SFTP/FTP (FileZilla, WinSCP), а не через админку Битрикса.

⚠️ Важно

Важно: Перед изменением сделайте резервную копию файла. Ошибка в .htaccess может привести к 500 ошибке на всём сайте.

Базовая конфигурация

apache
# Кодировка по умолчанию
AddDefaultCharset utf-8

# Отключаем листинг директорий
Options -Indexes

# Отключаем обработку SSI
Options -IncludesNoExec

# Включаем символические ссылки
Options +FollowSymLinks

# Обработка PHP.
# ВНИМАНИЕ: директивы php_flag/php_value понимает только mod_php.
# На PHP-FPM (а это большинство современных серверов) они дают
# 500 Internal Server Error — см. предупреждение ниже
php_flag display_errors off
php_flag allow_url_fopen on

# Защита служебных файлов.
# Синтаксис Apache 2.4; для 2.2 использовался Order/Deny
<Files *.sql>
    Require all denied
</Files>

<FilesMatch "\.(log|bak|sql|sql\.gz|tar|zip)$">
    Require all denied
</FilesMatch>

# Включаем mod_rewrite
<IfModule mod_rewrite.c>
    RewriteEngine On
</IfModule>
⚠️ Важно

Три директивы, которые кладут сайт при переезде на новый сервер. Все три дают одинаковый симптом — 500 на всём сайте и запись «Invalid command» в error.log Apache.

php_flag и php_value. Работают только с mod_php. На PHP-FPM Apache их не понимает. Настройки PHP в этом случае задаются в пуле FPM или через .user.ini в корне сайта.

Order, Deny from, Allow from. Это синтаксис Apache 2.2. В 2.4 он поддерживается только при подключённом mod_access_compat, которого в минимальных сборках нет. Современный эквивалент — Require all denied / Require all granted.

Options +FollowSymLinks. Если хостер запретил переопределять Options через AllowOverride, эта строка тоже даёт 500. При проблемах пробуйте Options +SymLinksIfOwnerMatch.

Отсюда практическое правило: после любой правки .htaccess первым делом смотрите не на сайт, а в error.log Apache — там будет точная строка и номер.

Редиректы

1. С www на без www (или наоборот)

apache
# С www на без www
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]

# Или с без www на www
# RewriteCond %{HTTP_HOST} !^www\. [NC]
# RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L]

2. С HTTP на HTTPS

apache
RewriteCond %{HTTPS} off
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]

3. Удаление index.php

apache
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(.*)index\.php($|\ |\?)
RewriteRule ^(.*)index\.php$ /$1 [R=301,L]

4. Добавление слэша в конце URL

apache
# Только для директорий, не для файлов
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{REQUEST_URI} !\.[a-zA-Z0-9]{1,5}$
RewriteRule ^(.*)$ $1/ [R=301,L]

5. Удаление дублирующихся слэшей

apache
RewriteCond %{THE_REQUEST} //
RewriteRule ^.*$ /$0 [R=301,L]
💡 Совет

Проверяйте цепочки редиректов, а не отдельные правила. Каждое из правил выше по отдельности корректно, но вместе они складываются: запрос на http://www.site.ru/catalog/index.php пройдёт через убирание www, переход на HTTPS, удаление index.php и добавление слэша — четыре последовательных 301. Для пользователя это лишние круги, для поисковика — размытие сигнала, а на длинной цепочке часть роботов просто перестаёт идти дальше.

Проверять нужно так: curl -sIL http://www.site.ru/catalog/index.php | grep -E "^(HTTP|Location)". Идеал — один редирект на конечный адрес; порядок правил в файле для этого важнее их содержимого.

ЧПУ для Битрикс

apache
<IfModule mod_rewrite.c>
    RewriteEngine On
    
    # Базовая директория
    RewriteBase /
    
    # Если файл или директория существует — отдаём как есть
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-l
    
    # Иначе передаём в Битрикс
    RewriteRule ^(.*)$ /bitrix/urlrewrite.php [L]
</IfModule>

Сжатие (mod_deflate)

apache
<IfModule mod_deflate.c>
    # Сжимаем текстовые файлы
    AddOutputFilterByType DEFLATE text/html
    AddOutputFilterByType DEFLATE text/plain
    AddOutputFilterByType DEFLATE text/xml
    AddOutputFilterByType DEFLATE text/css
    AddOutputFilterByType DEFLATE text/javascript
    AddOutputFilterByType DEFLATE application/javascript
    AddOutputFilterByType DEFLATE application/x-javascript
    AddOutputFilterByType DEFLATE application/json
    AddOutputFilterByType DEFLATE application/xml
    AddOutputFilterByType DEFLATE application/rss+xml
    AddOutputFilterByType DEFLATE image/svg+xml
    
    # Исключаем браузеры с проблемами
    BrowserMatch ^Mozilla/4 gzip-only-text/html
    BrowserMatch ^Mozilla/4\.0[678] no-gzip
    BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
</IfModule>

Кэширование браузера

apache
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresDefault "access plus 1 month"
    
    # HTML — без кэша
    ExpiresByType text/html "access plus 0 seconds"
    
    # Данные — без кэша
    ExpiresByType application/json "access plus 0 seconds"
    ExpiresByType application/xml "access plus 0 seconds"
    
    # RSS/Atom
    ExpiresByType application/rss+xml "access plus 1 hour"
    ExpiresByType application/atom+xml "access plus 1 hour"
    
    # Favicon
    ExpiresByType image/x-icon "access plus 1 week"
    ExpiresByType image/vnd.microsoft.icon "access plus 1 week"
    
    # Медиа
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType image/png "access plus 1 year"
    ExpiresByType image/gif "access plus 1 year"
    ExpiresByType image/webp "access plus 1 year"
    ExpiresByType image/svg+xml "access plus 1 month"
    ExpiresByType video/mp4 "access plus 1 year"
    ExpiresByType audio/mp3 "access plus 1 year"
    
    # Шрифты
    ExpiresByType font/woff "access plus 1 year"
    ExpiresByType font/woff2 "access plus 1 year"
    ExpiresByType application/font-woff "access plus 1 year"
    ExpiresByType application/font-woff2 "access plus 1 year"
    
    # CSS и JS
    ExpiresByType text/css "access plus 1 year"
    ExpiresByType application/javascript "access plus 1 year"
    ExpiresByType text/javascript "access plus 1 year"
</IfModule>

# Cache-Control заголовки
<IfModule mod_headers.c>
    # Статика — долгий кэш
    <FilesMatch "\.(ico|jpg|jpeg|png|gif|webp|svg|woff|woff2|css|js)$">
        Header set Cache-Control "public, max-age=31536000, immutable"
    </FilesMatch>
    
    # HTML — без кэша
    <FilesMatch "\.(html|htm|php)$">
        Header set Cache-Control "no-cache, no-store, must-revalidate"
    </FilesMatch>
</IfModule>

Защита от атак

Раздел, который стоит читать критически: большая часть «защиты» в типовых .htaccess даёт больше вреда, чем пользы. Разберу конкретно, что с ней не так, — но сначала сам код, потому что вы его всё равно встретите на любом унаследованном проекте.

apache
# Блокировка сканеров уязвимостей
RewriteCond %{QUERY_STRING} (\<|%3C).*script.*(\>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} GLOBALS(=|\[|\%[0-9A-Z]{0,2}) [OR]
RewriteCond %{QUERY_STRING} _REQUEST(=|\[|\%[0-9A-Z]{0,2})
RewriteRule .* - [F,L]

# Защита от SQL-инъекций
RewriteCond %{QUERY_STRING} union.*select.*\( [NC,OR]
RewriteCond %{QUERY_STRING} concat.*\( [NC]
RewriteRule .* - [F,L]

# Блокировка подозрительных User-Agent
<IfModule mod_setenvif.c>
    SetEnvIfNoCase User-Agent "^$" bad_bot
    SetEnvIfNoCase User-Agent "wget" bad_bot
    SetEnvIfNoCase User-Agent "curl" bad_bot
    SetEnvIfNoCase User-Agent "HTTrack" bad_bot
    
    <Limit GET POST HEAD>
        Order Allow,Deny
        Allow from all
        Deny from env=bad_bot
    </Limit>
</IfModule>
⚠️ Важно

Что не так с этим блоком.

Фильтрация SQL-инъекций по QUERY_STRING — это имитация WAF, которая не останавливает настоящую атаку (обходится кодированием и регистром) и при этом ломает нормальные запросы. Поиск по сайту со словом «select», товар с «concat(» в названии, любой параметр, содержащий подстроку _REQUEST, — всё это получит 403. Защита от инъекций находится в коде, в подготовленных запросах, а не в регулярке на входе.

Блокировка curl и wget по User-Agent — самый вредный пункт списка. Настоящий сканер подставит Mozilla/5.0 первой же строкой конфига. А под запрет попадёте вы сами: мониторинг доступности, health-check, вебхуки платёжных систем и служб доставки, интеграции по API, ваш собственный curl -I для проверки редиректов. Разбор инцидента «платежи перестали подтверждаться» с такой строкой в .htaccess занимает часы, потому что искать причину идут в код оплаты.

Блокировка пустого User-Agent — по тем же причинам: часть легитимных серверных клиентов его не отправляет.

Что действительно работает вместо этого: ограничение частоты запросов на уровне nginx или Apache, актуальные версии CMS и модулей, и — если нужен именно WAF — отдельный инструмент вроде ModSecurity с поддерживаемым набором правил, а не десять строк регулярок.

Полная конфигурация для production

apache
# ============================================
# .htaccess для 1С-Битрикс
# ============================================

# Кодировка
AddDefaultCharset utf-8

# Безопасность
Options -Indexes -IncludesNoExec +FollowSymLinks
php_flag display_errors off

<Files .htaccess>
    Order allow,deny
    Deny from all
</Files>

# ============================================
# Редиректы и ЧПУ
# ============================================
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    
    # HTTPS
    RewriteCond %{HTTPS} off
    RewriteCond %{HTTP:X-Forwarded-Proto} !https
    RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
    
    # www -> без www
    RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
    RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
    
    # Удаление index.php
    RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(.*)index\.php($|\ |\?)
    RewriteRule ^(.*)index\.php$ /$1 [R=301,L]
    
    # Trailing slash
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_URI} !/$
    RewriteCond %{REQUEST_URI} !\.[a-zA-Z0-9]{1,5}$
    RewriteRule ^(.*)$ $1/ [R=301,L]
    
    # ЧПУ Битрикс
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-l
    RewriteRule ^(.*)$ /bitrix/urlrewrite.php [L]
</IfModule>

# ============================================
# Сжатие
# ============================================
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/plain text/xml
    AddOutputFilterByType DEFLATE text/css text/javascript
    AddOutputFilterByType DEFLATE application/javascript application/json
    AddOutputFilterByType DEFLATE application/xml image/svg+xml
</IfModule>

# ============================================
# Кэширование
# ============================================
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresDefault "access plus 1 month"
    ExpiresByType text/html "access plus 0 seconds"
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType image/png "access plus 1 year"
    ExpiresByType image/webp "access plus 1 year"
    ExpiresByType text/css "access plus 1 year"
    ExpiresByType application/javascript "access plus 1 year"
    ExpiresByType font/woff2 "access plus 1 year"
</IfModule>
⚠️ Важно

Год кэширования для CSS и JS требует версионирования. ExpiresByType text/css "access plus 1 year" означает, что браузер вернувшегося пользователя не станет перезапрашивать файл — со всеми последствиями после выкладки новой вёрстки. Работает это только если в адресе файла меняется что-то при каждом изменении содержимого: style.css?v=hash или имя с хэшем. Собственные CSS и JS шаблона такого версионирования обычно не имеют — для них год слишком много, разумнее месяц или явный параметр версии в шаблоне.

Итоги

Здоровый .htaccess для Битрикса — это редиректы (по одному правилу на каждый вид дублей), правило ЧПУ и, если запросы до Apache действительно доходят, сжатие с кэшированием. Всё остальное, что обычно в нём лежит, стоит пересмотреть.

Порядок работы, который экономит время:

  1. Убедитесь, что файл вообще применяется. На связке nginx + Apache половина правил не работает для статики.
  2. Проверяйте цепочки редиректов, а не отдельные правила: curl -sIL.
  3. После правки — сразу в error.log Apache. Три четверти пятисоток по теме объясняются одной строкой в логе.
  4. Не держите «защиту» из регулярок. Она не останавливает атакующего и ломает свои же интеграции.
  5. Если есть доступ к конфигу виртуального хоста — переносите правила туда. Быстрее и не читается на каждый запрос.
💡 Совет

Перед выкладкой сохраните работающую копию файла рядом (.htaccess.bak) и проверьте результат из другого браузера или приватного окна — кэш редиректов на стороне браузера сам по себе способен убедить вас в том, что правило работает не так, как есть на самом деле. curl от этого свободен, поэтому проверять лучше им.

🚀

Хотите такое же решение?

Настрою окружение под ваш проект, учту специфику инфраструктуры и обучу команду.

Обсудить проект →
Бесплатная консультация · Ответ в течение дня

Комментарии

Система комментариев скоро будет подключена. А пока вы можете написать мне в Telegram или на email.