Готовые .htaccess под задачу

Подобраны полные, готовые к установке файлы .htaccess под типовые сценарии — скопируйте, при необходимости поправьте пути/домен. Для своей CMS см. хабы /wordpress/ и /frameworks/, для точечной настройки — генератор и рецепты; краткая шпаргалка с самыми частыми строками — на одной странице. Хотите свой набор блоков — конструктор .htaccess.

1. Статический сайт-визитка (HTML/CSS/JS)

Подходит для сайта без PHP: портфолио, лендинг без форм, документация. Перенаправляет весь HTTP-трафик на HTTPS, канонизирует www, выключает листинг, gzip и кэш статики, закрывает системные файлы, отдаёт свою 404.

.htaccess для статического сайта-визиткикопировать
# -----------------------------------------------
# Статический сайт: https + www-канонизация + кэш
# -----------------------------------------------

# Включить mod_rewrite
RewriteEngine On

# HTTP -> HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# www -> без www (или поменяйте на противоположное)
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]

# Запрет листинга каталога
Options -Indexes

# Защита .ht-файлов
<Files ~ "^\.ht">
    Require all denied
</Files>

# Страница ошибки 404
ErrorDocument 404 /404.html

# Gzip для текста
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/css application/javascript image/svg+xml
</IfModule>

# Кэш статики
<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 text/css          "access plus 1 year"
    ExpiresByType application/javascript "access plus 1 year"
    ExpiresByType application/font-woff2 "access plus 1 year"
    ExpiresByType text/html         "access plus 0 seconds"
</IfModule>
  • Редирект HTTP → HTTPS и www → без www идут первыми, до остальных правил.
  • Все модули обёрнуты в <IfModule> — не даёт 500, если модуль отключён.
  • HTML кэшируется с "access plus 0 seconds" — не ломает обновления.
  • Поправьте /404.html на свой путь.

Рецепты .htaccess · Производительность · Линтер

2. Блог на WordPress

Полный боевой файл для WordPress: стандартный блок «красивых URL», принудительный HTTPS, защита wp-config.php и xmlrpc.php, запрет PHP в wp-content/uploads/, gzip, кэш и базовые заголовки безопасности. Подробнее о каждом блоке — хаб «.htaccess для WordPress».

.htaccess для блога на WordPressкопировать
# -----------------------------------------------
# WordPress: https + защита + кэш
# -----------------------------------------------

RewriteEngine On

# HTTP -> HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Защита wp-config.php
<Files wp-config.php>
    Require all denied
</Files>

# Заблокировать xmlrpc.php (если не используете)
<Files xmlrpc.php>
    Require all denied
</Files>

# Запрет PHP в папке загрузок
<IfModule mod_rewrite.c>
    RewriteRule ^wp-content/uploads/.*\.ph(p[0-9]?|tml)$ - [F,L]
</IfModule>

# Заголовки безопасности
<IfModule mod_headers.c>
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    Header always unset X-Powered-By
</IfModule>

# Gzip
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/css application/javascript application/json image/svg+xml
</IfModule>

# Кэш статики
<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 text/css          "access plus 1 month"
    ExpiresByType application/javascript "access plus 1 month"
    ExpiresByType text/html         "access plus 0 seconds"
</IfModule>

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
  • Блок # BEGIN WordPress — не редактируйте вручную: WordPress перезаписывает его при сохранении настроек постоянных ссылок.
  • Если используете плагины на основе XML-RPC (Jetpack, мобильное приложение) — уберите блокировку xmlrpc.php.
  • Для мультисайта блок фронт-контроллера будет другим — WordPress сгенерирует его сам.

Полный гид .htaccess для WordPress · Безопасность · Генератор .htpasswd

3. Интернет-магазин

Подходит для любого движка (OpenCart, Битрикс, самописный): HTTPS с HSTS, www-канонизация, заголовки безопасности (без агрессивного CSP), кэш статики, gzip, защита служебных файлов. Блок режима обслуживания включён, но закомментирован — раскомментируйте на время работ.

.htaccess для интернет-магазинакопировать
# -----------------------------------------------
# Интернет-магазин: https + безопасность + кэш
# -----------------------------------------------

RewriteEngine On

# HTTP -> HTTPS (+ www -> без www)
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ https://example.com%{REQUEST_URI} [R=301,L]

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

# Защита служебных файлов
<FilesMatch "(^\.|\.env$|wp-config\.php$|\.sql$|\.bak$|\.log$|composer\.(json|lock)$)">
    Require all denied
</FilesMatch>

# Запрет листинга
Options -Indexes

# Gzip
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/plain text/css application/javascript application/json image/svg+xml
</IfModule>

# Кэш статики
<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 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>

# Режим обслуживания (раскомментируйте на время работ; замените 1.2.3.4 на свой IP)
# RewriteCond %{REMOTE_ADDR} !=1.2.3.4
# RewriteCond %{REQUEST_URI} !^/maintenance\.html$ [NC]
# RewriteRule .* - [R=503,L]
# ErrorDocument 503 /maintenance.html

# Фронт-контроллер (раскомментируйте если нужен — замените index.php на точку входа)
# RewriteCond %{REQUEST_FILENAME} !-f
# RewriteCond %{REQUEST_FILENAME} !-d
# RewriteRule ^ index.php [L,QSA]

ErrorDocument 404 /404.html
ErrorDocument 403 /403.html
ErrorDocument 500 /500.html
  • Замените example.com в редиректе на свой домен.
  • HSTS включён — убедитесь, что сайт навсегда на HTTPS: откатить будет непросто.
  • Раскомментируйте фронт-контроллер, если ваш движок использует index.php.
  • Для Битрикс / OpenCart блок фронт-контроллера берите из родной документации.

Безопасность .htaccess · Производительность

4. Лендинг с формой

Одностраничный лендинг с PHP-обработчиком формы: HTTPS, защита конфигов и скрытых файлов, gzip, кэш, заголовки безопасности. Форма отправляется на тот же домен — ничего особенного для CORS не нужно.

.htaccess для лендинга с формойкопировать
# -----------------------------------------------
# Лендинг с формой: https + защита + кэш
# -----------------------------------------------

RewriteEngine On

# HTTP -> HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Запрет листинга
Options -Indexes

# Защита скрытых и конфигурационных файлов
<Files ~ "^\.">
    Require all denied
</Files>
<FilesMatch "\.(env|sql|bak|log|ini|conf)$">
    Require all denied
</FilesMatch>

# Заголовки безопасности
<IfModule mod_headers.c>
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    Header always unset X-Powered-By
</IfModule>

# Gzip
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/css application/javascript image/svg+xml
</IfModule>

# Кэш статики
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType image/jpeg             "access plus 6 months"
    ExpiresByType image/png              "access plus 6 months"
    ExpiresByType image/webp             "access plus 6 months"
    ExpiresByType text/css               "access plus 1 month"
    ExpiresByType application/javascript "access plus 1 month"
    ExpiresByType text/html              "access plus 0 seconds"
</IfModule>

ErrorDocument 404 /index.php
  • 404 отправляет на главную страницу — типичный выбор для лендинга.
  • Нет фронт-контроллера: если обработчик формы называется send.php — он доступен напрямую.
  • При добавлении стороннего виджета (чат, аналитика) убедитесь, что CSP-заголовок не сломает их.

Рецепты .htaccess · Генератор

5. Одностраничное приложение (SPA)

React, Vue, Angular или любой другой SPA с собранными в dist/ ассетами. Все запросы к несуществующим файлам и каталогам — на index.html (client-side routing). Хешированные ассеты — агрессивный кэш, index.html — no-cache.

.htaccess для SPA (React / Vue / Angular)копировать
# -----------------------------------------------
# SPA (React / Vue / Angular): фронт-контроллер
# -----------------------------------------------

RewriteEngine On

# HTTP -> HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Фронт-контроллер: всё несуществующее -> index.html
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.html [L]

# Запрет листинга
Options -Indexes

# Заголовки безопасности
<IfModule mod_headers.c>
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"

    # index.html — не кэшировать (браузер всегда проверяет)
    <FilesMatch "^index\.html$">
        Header set Cache-Control "no-cache, no-store, must-revalidate"
    </FilesMatch>

    # Хешированные ассеты (main.abc123.js) — агрессивный кэш
    <FilesMatch "\.(css|js|woff2|woff|ttf|eot)$">
        Header set Cache-Control "public, max-age=31536000, immutable"
    </FilesMatch>

    # Изображения
    <FilesMatch "\.(png|jpg|jpeg|webp|svg|ico|gif)$">
        Header set Cache-Control "public, max-age=2592000"
    </FilesMatch>
</IfModule>

# Gzip
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/css application/javascript application/json image/svg+xml
</IfModule>
  • Фронт-контроллер на index.html — чтобы React Router / Vue Router работали при прямом заходе на глубокие URL.
  • Ассеты с хешем в имени можно кэшировать на год — при изменении CRA/Vite/webpack сгенерирует новое имя.
  • index.htmlno-cache, чтобы браузер всегда брал актуальную версию при деплое.

Хаб: .htaccess для CMS и фреймворков · Оптимизация

6. REST API на бэкенде (PHP-фреймворк)

DocumentRoot указывает на public/ (Laravel, Symfony, Slim…). Фронт-контроллер на index.php, CGIPassAuth On — чтобы заголовок Authorization доходил до PHP-FPM, CORS для конкретного клиентского домена с обработкой preflight OPTIONS.

.htaccess для REST API (public/)копировать
# -----------------------------------------------
# REST API (Laravel / Slim / Symfony: public/)
# -----------------------------------------------

RewriteEngine On
Options -Indexes -MultiViews

# HTTP -> HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Передать Authorization в PHP-FPM
CGIPassAuth On

# CORS: разрешить конкретный клиентский origin
<IfModule mod_headers.c>
    SetEnvIf Origin "^https://app\.example\.com$" ALLOWED_ORIGIN=$0
    Header always set Access-Control-Allow-Origin "%{ALLOWED_ORIGIN}e" env=ALLOWED_ORIGIN
    Header always set Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS"
    Header always set Access-Control-Allow-Headers "Authorization, Content-Type, Accept, X-Requested-With"
    Header always set Access-Control-Allow-Credentials "true"
    Header always set Access-Control-Max-Age "86400"
</IfModule>

# Ответить на preflight OPTIONS сразу (без PHP)
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^ - [R=204,L]

# Защита .env и конфигов
<FilesMatch "(^\.|\.env$|composer\.(json|lock)$|artisan$)">
    Require all denied
</FilesMatch>

# Фронт-контроллер: всё -> index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [L,QSA]
  • CGIPassAuth On нужен для PHP-FPM: без него Authorization: Bearer … не попадает в $_SERVER.
  • CORS-заголовки ставятся через SetEnvIf — позволяет указать точный origin без wildcard *.
  • Preflight OPTIONS отрабатывается на уровне Apache (R=204), не тратя ресурсы PHP.
  • Замените app.example.com на свой клиентский домен.

Хаб: .htaccess для CMS и фреймворков · Справочник заголовков

7. Форум / сообщество

Типовой форум (phpBB, MyBB, Discourse-like PHP-движок): HTTPS с канонизацией, защита конфигов и скрытых файлов, запрет листинга, gzip и кэш, защита папок загрузок от исполнения PHP. Rate-limiting в .htaccess невозможен — используйте Fail2ban или решение на уровне WAF.

.htaccess для форума / сообществакопировать
# -----------------------------------------------
# Форум: https + защита загрузок + кэш
# -----------------------------------------------

RewriteEngine On

# HTTP -> HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# www -> без www
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]

# Запрет листинга
Options -Indexes

# Защита конфигов и скрытых файлов
<Files ~ "^\.">
    Require all denied
</Files>
<FilesMatch "(config\.php$|\.env$|\.sql$|\.bak$|install\.php$)">
    Require all denied
</FilesMatch>

# Запрет PHP в папке аватаров/вложений
<IfModule mod_rewrite.c>
    RewriteRule ^(uploads|attachments|avatars)/.*\.ph(p[0-9]?|tml)$ - [F,L]
</IfModule>

# Заголовки безопасности
<IfModule mod_headers.c>
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    Header always unset X-Powered-By
</IfModule>

# Gzip
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/plain text/css application/javascript image/svg+xml
</IfModule>

# Кэш статики
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType image/jpeg             "access plus 1 year"
    ExpiresByType image/png              "access plus 1 year"
    ExpiresByType image/gif              "access plus 1 year"
    ExpiresByType text/css               "access plus 1 month"
    ExpiresByType application/javascript "access plus 1 month"
    ExpiresByType text/html              "access plus 0 seconds"
</IfModule>

ErrorDocument 404 /404.php
ErrorDocument 403 /403.php
  • Запрет PHP в uploads/ / attachments/ — главная защита от загрузки веб-шеллов.
  • Rate-limiting через .htaccess ненадёжен; для защиты от брутфорса используйте Fail2ban, mod_evasive или Cloudflare.
  • Замените имена папок загрузок на реальные для вашего движка.

Безопасность .htaccess · Блокировка ботов

8. Закрытый раздел / staging-сайт

Staging-копия сайта, доступная только команде: либо по IP, либо по паролю (Basic Auth). Директива X-Robots-Tag: noindex запрещает индексацию — важно убрать её при переезде на прод.

.htaccess для staging (доступ по IP)копировать
# -----------------------------------------------
# Staging: доступ только по IP + noindex
# -----------------------------------------------

# Запрет листинга
Options -Indexes

# Не индексировать staging-сайт
<IfModule mod_headers.c>
    Header always set X-Robots-Tag "noindex, nofollow"
</IfModule>

# Доступ только со своих IP (замените на реальные)
Require ip 203.0.113.0/24
Require ip 198.51.100.7

ErrorDocument 403 /403.html

Альтернатива — закрыть паролем (вместо или вместе с IP):

.htaccess для staging (Basic Auth)копировать
# -----------------------------------------------
# Staging: HTTP Basic Auth + noindex
# -----------------------------------------------

Options -Indexes

<IfModule mod_headers.c>
    Header always set X-Robots-Tag "noindex, nofollow"
</IfModule>

AuthType Basic
AuthName "Staging — доступ ограничен"
AuthUserFile /home/user/.htpasswd
Require valid-user

# Разрешить публичный доступ к ресурсам (статика)
# <FilesMatch "\.(css|js|png|jpg|woff2)$">
#     Satisfy Any
#     Allow from all
# </FilesMatch>
  • При переезде на продакшен обязательно удалите X-Robots-Tag: noindex — иначе сайт не попадёт в индекс.
  • Файл .htpasswd кладите вне DocumentRoot (например, /home/user/.htpasswd).
  • Скомбинировать «офисный IP ИЛИ пароль» — используйте <RequireAny> (подробнее в /security/).

Генератор .htpasswd · Скорая помощь по .htaccess