Рецепты .htaccess

Готовые блоки .htaccess под типовые задачи: вставляйте в файл .htaccess в корне сайта (или в нужном каталоге), перед каждым блоком указано, что он делает. При сомнениях прогоните файл через линтер /check/, а правила mod_rewrite — через тестер /rewrite/; собрать .htaccess из чекбоксов можно в генераторе. Плейсхолдеры (example.com, 203.0.113.x, пути-примеры) замените на свои. А как работает mod_rewrite — в туториале «Как работает mod_rewrite».

Если ищете именно про защиту сайта — отдельный гид «Безопасность сайта через .htaccess» собирает все «защитные» рецепты вместе с разбором: заголовки безопасности, закрытие файлов, доступ по IP, пароль, запрет PHP в загрузках, анти-бот.

А про скорость — гид «Ускорение сайта через .htaccess»: кэш статики, gzip / Brotli, ETag, preload-подсказки.

Не уверены в регулярках внутри правил? — справочник «PCRE: регулярные выражения для mod_rewrite» (якоря, классы, кванторы, группы, экранирование).

Для WordPress — отдельный хаб: «.htaccess для WordPress» (стандартный файл, защита wp-config/wp-login/xmlrpc, кэш, частые проблемы); для других CMS/фреймворков (Laravel, Joomla, Drupal, Bitrix, Yii…) — хаб «.htaccess для CMS и фреймворков»; всё про SEO и редиректы (301 vs 302, переезд домена, цепочки) — хаб «SEO и редиректы через .htaccess»; краткая шпаргалка и готовые .htaccess под задачу.

1. Редирект с www на без www (и обратно)

Зачем: склейка зеркал, один канонический хост — лучше для SEO и куки.

.htaccess (www → без www)копировать
RewriteEngine On
# www.example.com  ->  example.com
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]
.htaccess (без www → www)копировать
RewriteEngine On
# example.com  ->  www.example.com
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

Как работает: RewriteCond ловит хост, начинающийся с www.; %1 — это всё после www. (захваченная группа условия); [R=301,L] — постоянный редирект, на нём обработка останавливается. Меняйте https на http, если у сайта нет TLS.

→ собрать в генераторе (блок «WWW») · → проверить на конкретном URL

2. Принудительный HTTPS

Зачем: весь трафик по защищённому соединению; нужен установленный сертификат.

.htaccessкопировать
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
.htaccess (вариант за reverse-proxy / CDN)копировать
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

Как работает: если соединение не по HTTPS — 301 на тот же URL по https://. Ставьте это правило раньше остальных rewrite-правил. За прокси/CDN %{HTTPS} может всегда быть off — тогда проверяйте заголовок %{HTTP:X-Forwarded-Proto} (второй вариант).

→ собрать в генераторе (блок «Редирект на HTTPS») · → проверить на конкретном URL

3. 301-редирект старой страницы на новую (и массовый список)

Зачем: перенос/переименование страниц без потери позиций и ссылок.

.htaccess (одна страница, mod_alias)копировать
Redirect 301 /old-page.html /new-page.html
.htaccess (одна страница через mod_rewrite)копировать
RewriteEngine On
RewriteRule ^old-page\.html$ /new-page.html [R=301,L]

Как работает: Redirect 301 <старый-путь> <новый-путь-или-URL> — точное совпадение пути. Для целого раздела используйте RedirectMatch 301 ^/old-section/(.*)$ /new-section/$1. Десятки/сотни редиректов удобнее сгенерировать пакетно.

→ пакетный генератор 301-редиректов из списка «старый URL → новый URL» · → проверить на конкретном URL

4. Убрать .php (или .html) из URL

Зачем: красивые URL вида /about вместо /about.php.

.htaccessкопировать
RewriteEngine On
# если запрошен не существующий файл/каталог, но есть <имя>.php — отдать его
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^([^.]+)$ $1.php [L]
.htaccess (опционально: 301 со старого .php на чистый URL)копировать
RewriteCond %{THE_REQUEST} \s/+([^.\s]+)\.php[\s?] [NC]
RewriteRule ^ /%1 [R=301,L]

Как работает: первый блок внутренне подставляет .php к запросу без расширения, если такой файл существует; второй (опционально) убирает .php из адресной строки 301-редиректом. [L] — стоп.

→ пошагово проверить · → проверить синтаксис

5. Своя страница ошибки 404 / 403 / 500

Зачем: вместо стандартной серверной заглушки — ваша страница с навигацией.

.htaccessкопировать
ErrorDocument 404 /404.html
ErrorDocument 403 /403.html
ErrorDocument 500 /500.html

Как работает: при ошибке с указанным кодом Apache внутренне отдаёт ваш файл (статус остаётся 404/403/500). Убедитесь, что сама страница ошибки доступна и не вызывает ту же ошибку.

→ собрать в генераторе (блок «Страницы ошибок») · → проверить синтаксис

6. Защита папки паролем (Basic Auth)

Зачем: закрыть админку/каталог простым логином-паролем.

.htaccess (в защищаемом каталоге)копировать
AuthType Basic
AuthName "Закрытая зона"
AuthUserFile "/srv/site/.htpasswd"
Require valid-user

Как работает: AuthUserFileабсолютный путь к файлу .htpasswd (его лучше держать вне DocumentRoot); Require valid-user — пускать любого из этого файла (либо Require user alice bob — только указанных). Сам .htpasswd — это строки логин:хеш (рекомендуется bcrypt). Дополнительно закройте сам .htpasswd от веба правилом из рецепта 7.

→ генератор содержимого .htpasswd и этого блока · → подробная статья о парольной защите

7. Запрет доступа к файлам и каталогам

Зачем: спрятать .env, wp-config.php, дампы БД, .git/, служебные каталоги.

.htaccess (Apache 2.4 — закрыть «опасные» файлы)копировать
<FilesMatch "(^\.|\.env$|\.sql$|\.bak$|\.log$|composer\.(json|lock)$)">
    Require all denied
</FilesMatch>
.htaccess (закрыть весь каталог)копировать
Require all denied

Как работает: <FilesMatch> применяет правило к файлам, чьё имя матчит regex; Require all denied — 403 для всех. Каталог .git/ обычно закрывают отдельным правилом RedirectMatch 404 ^/\.git или блоком на <DirectoryMatch>.htaccess доступен RedirectMatch).

→ проверить синтаксис · → если у вас старый Order/Deny

8. Блокировка по IP-адресу

Зачем: отрезать конкретного посетителя/подсеть (спам, брутфорс).

.htaccess (Apache 2.4 — пускать всех, кроме)копировать
<RequireAll>
    Require all granted
    Require not ip 203.0.113.10
    Require not ip 203.0.113.0/24
</RequireAll>
.htaccess (наоборот — пускать только своих)копировать
Require ip 203.0.113.0/24
Require ip 198.51.100.7

Как работает: <RequireAll> требует выполнения всех вложенных условий: доступ разрешён всем (Require all granted), кроме перечисленных IP/подсетей (Require not ip …).

→ перевести старый Order/Allow/Deny в этот синтаксис · → подробная статья о фильтрации по IP

9. Блокировка ботов по User-Agent

Зачем: отсечь агрессивные SEO-сканеры/скраперы, экономия ресурсов.

.htaccessкопировать
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} (AhrefsBot|SemrushBot|MJ12bot|DotBot|PetalBot|DataForSeoBot|BLEXBot) [NC]
RewriteRule ^ - [F]

Как работает: если строка User-Agent содержит одно из имён (без учёта регистра) — [F] отдаёт 403, - означает «подстановки нет, только применить флаг».

→ собрать в генераторе (блок «Блокировка ботов» — там список можно собрать чекбоксами) · → проверить на конкретном URL

Зачем: чужие сайты не должны показывать ваши картинки со своих страниц (воровство трафика).

.htaccessкопировать
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://([a-z0-9-]+\.)?example\.com [NC]
RewriteRule \.(jpe?g|png|gif|webp|svg)$ - [F,NC]

Как работает: если у запроса картинки есть Referer (не пустой) и он не с вашего домена — 403. Пустой Referer (прямой заход, сохранение картинки) пропускаем. Замените example.com на свой домен; при необходимости вместо [F] можно отдавать «заглушку»: RewriteRule \.(jpe?g|png|gif)$ /hotlink.png [L,NC].

→ собрать в генераторе (блок «Защита от хотлинка») · → проверить на конкретном URL

11. Заголовки безопасности

Зачем: базовая защита от кликджекинга, MIME-sniffing, утечки реферера.

.htaccessкопировать
<IfModule mod_headers.c>
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set X-Content-Type-Options "nosniff"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
    # HSTS — включайте только когда уверены, что сайт навсегда на HTTPS:
    # Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</IfModule>

Как работает: Header always set добавляет заголовок к любому ответу (включая ошибки). X-Frame-Options: SAMEORIGIN запрещает встраивать сайт в <iframe> с других доменов; nosniff запрещает браузеру «угадывать» MIME-тип. HSTS оставлен закомментированным намеренно: с ним сайт нельзя будет открыть по http:// в течение max-age — включайте осознанно.

→ собрать в генераторе (блок «Security headers» — соберёт нужные заголовки чекбоксами) · → подробнее про каждый заголовок (CSP, HSTS, CORS, кэш) — справочник HTTP-заголовков

12. Кэширование статики в браузере

Зачем: повторные визиты загружаются быстрее, меньше запросов к серверу.

.htaccessкопировать
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType image/jpeg             "access plus 1 year"
    ExpiresByType image/png              "access plus 1 year"
    ExpiresByType image/webp             "access plus 1 year"
    ExpiresByType image/svg+xml          "access plus 1 year"
    ExpiresByType image/x-icon           "access plus 1 year"
    ExpiresByType text/css               "access plus 1 month"
    ExpiresByType application/javascript "access plus 1 month"
    ExpiresByType application/font-woff2 "access plus 1 year"
    ExpiresByType text/html              "access plus 0 seconds"
</IfModule>

Как работает: ExpiresByType <mime> "access plus <срок>" ставит заголовки Expires и Cache-Control: max-age=…. HTML кэшировать надолго не стоит (0 seconds), иначе пользователи будут видеть старую версию. После выкладки новой версии файла меняйте его имя (style.v2.css) — иначе из кэша возьмётся старый.

→ собрать в генераторе (блок «Кэш статики»)

13. Сжатие GZIP

Зачем: текстовые ответы (HTML/CSS/JS) передаются в 3–5 раз меньше по объёму.

.htaccessкопировать
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css
    AddOutputFilterByType DEFLATE application/javascript application/json
    AddOutputFilterByType DEFLATE application/xml application/rss+xml
    AddOutputFilterByType DEFLATE image/svg+xml application/vnd.ms-fontobject font/ttf font/otf
</IfModule>

Как работает: AddOutputFilterByType DEFLATE <mime…> включает gzip-сжатие для перечисленных типов. Уже сжатые форматы (JPEG, PNG, WEBP, ZIP, PDF) сжимать не нужно — выигрыша нет. Если на хостинге доступен Brotli, аналогично работает mod_brotli (AddOutputFilterByType BROTLI_COMPRESS …).

→ собрать в генераторе (блок «GZIP»)

14. Отключить листинг каталога

Зачем: чтобы посетитель не видел содержимое каталога без index.*-файла.

.htaccessкопировать
Options -Indexes

Как работает: Options -Indexes убирает автогенерируемый список файлов; вместо него вернётся 403. Если хостинг запрещает менять Options через .htaccess, появится ошибка 500 — тогда уберите эту строку.

→ собрать в генераторе (блок «Options»)

15. Своя стартовая страница каталога

Зачем: указать, какой файл отдавать при заходе на / или /каталог/.

.htaccessкопировать
DirectoryIndex index.php index.html home.html

Как работает: Apache берёт первый существующий файл из списка (слева направо). Полезно, если стартовый файл называется не index.html (например home.php) или нужно отдать предпочтение .php над .html.

→ проверить синтаксис

16. Режим обслуживания (с белым списком по IP)

Зачем: на время работ показывать всем «сайт на обслуживании», но себя пускать.

.htaccessкопировать
RewriteEngine On
RewriteCond %{REMOTE_ADDR} !^203\.0\.113\.10$
RewriteCond %{REQUEST_URI} !^/maintenance\.html$ [NC]
RewriteCond %{REQUEST_URI} !\.(css|js|png|jpe?g|svg|ico|woff2?)$ [NC]
RewriteRule ^ /maintenance.html [R=503,L]
ErrorDocument 503 /maintenance.html
<IfModule mod_headers.c>
    Header always set Retry-After "3600"
</IfModule>

Как работает: всех, кроме вашего IP, перенаправляет на /maintenance.html с кодом 503 (а не 200 — это важно: 503 говорит поисковикам «временно, зайдите позже», статика при этом грузится — последнее RewriteCond исключает CSS/JS/картинки). Retry-After: 3600 — подсказка «вернитесь через час». Не забудьте убрать этот блок после работ.

→ собрать в генераторе (блок «Режим обслуживания») · → проверить на конкретном URL

Инструменты и статьи

Генератор .htaccess · Пакетный генератор 301-редиректов · Генератор .htpasswd · Конвертер Apache 2.2 → 2.4 · Проверка .htaccess (линтер) · Тестер RewriteRule

Статьи: Фильтрация по IP · Парольная защита · Блокировка по referer