Файл .htaccess: редиректы, https, www, ЧПУ, запрет доступа и кеширование
Коротко
Файл .htaccess - настройки Apache для папки сайта: в нём делают 301 редирект, переход с http на https, склейку www, ЧПУ, запрет доступа и кеширование. Ниже - готовые блоки, которые можно вставить в файл в корне сайта, с пояснением каждой строки. Помните: Nginx .htaccess не читает, а ошибка в файле ломает весь сайт кодом 500, поэтому перед правкой сохраняйте копию.
Содержание
Что такое файл .htaccess и где он работает
Файл .htaccess - это файл настроек веб-сервера Apache для отдельной папки. Его кладут в корень сайта (или в любую подпапку), и Apache применяет правила к этой папке и всему, что внутри. Через .htaccess делают 301 редирект, переход с http на https, склейку www, ЧПУ, запрет доступа к файлам, кеширование и сжатие - без доступа к главному конфигу сервера, что важно на виртуальном хостинге.

Что нужно знать до начала:
- Имя файла начинается с точки и не имеет расширения. В Windows создайте его в редакторе кода через "Сохранить как" с именем
.htaccess. В FTP-клиенте включите показ скрытых файлов - иначе, например, WinSCP не видит .htaccess. - Файл работает только в Apache и совместимых серверах (LiteSpeed). Nginx .htaccess не читает: на сервере только с Nginx те же правила пишут в конфиг сайта.
- Чтобы Apache читал файл, в конфиге виртуального хоста должна быть директива
AllowOverride Allдля папки сайта. На хостинге она обычно уже включена. - Для редиректов и ЧПУ нужен модуль
mod_rewrite. На своём сервере с Ubuntu он включается командойsudo a2enmod rewrite.
Одна ошибка в .htaccess - и весь сайт отдаёт код 500. Перед правкой сохраните копию файла. Если сайт упал, верните копию или переименуйте файл; подробная диагностика - в статье ошибка 500 Internal Server Error.
Правила читаются сверху вниз. Для ориентира - общий порядок блоков в файле: сначала защита и запреты, затем редиректы (https, www, перенесённые страницы), затем ЧПУ, в конце кеширование и сжатие.
301 редирект в .htaccess
Код 301 говорит браузеру и поисковикам, что страница переехала навсегда: Яндекс и Google передают новому адресу накопленный вес и со временем заменяют адрес в выдаче. Временный 302 для переезда не подходит.
Редирект одной страницы
Самый простой способ - директива Redirect из модуля mod_alias:
# Старый адрес → новый (путь от корня, новый - полностью)
Redirect 301 /old-page.html https://site.ru/new-page/
Redirect 301 /blog/2019/sale/ https://site.ru/akcii/
Для адресов с параметрами (?id=15) и шаблонов нужен mod_rewrite:
RewriteEngine On
# /product.php?id=15 → /catalog/15/
RewriteCond %{QUERY_STRING} ^id=(\d+)$
RewriteRule ^product\.php$ /catalog/%1/? [R=301,L]
# Целый раздел: /news/любой-адрес → /blog/любой-адрес
RewriteRule ^news/(.*)$ /blog/$1 [R=301,L]
Знак ? в конце нового адреса отбрасывает старую строку параметров. Флаг L останавливает обработку правил для этого запроса.
Редирект на другой домен с сохранением пути
При переезде сайта на новый домен каждая старая страница должна вести на ту же страницу нового домена, а не на главную. Положите .htaccess в корень старого сайта:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www\.)?old-site\.ru$ [NC]
RewriteRule ^(.*)$ https://new-site.ru/$1 [R=301,L]
Проверьте результат командой curl -I https://old-site.ru/catalog/: в ответе должны быть HTTP/1.1 301 и строка Location: https://new-site.ru/catalog/.

Пока настраиваете правила, ставьте R=302: браузер надолго запоминает 301, и после исправления ошибки вы будете видеть старый редирект. Когда всё работает, поменяйте на R=301. Проверяйте в режиме инкогнито или через curl.
Редирект с http на https
После подключения SSL-сертификата все адреса с http:// должны вести одним 301 на https://. Стандартное правило:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
На многих хостингах перед Apache стоит Nginx, который сам принимает HTTPS, а Apache получает запрос уже по http. Тогда %{HTTPS} всегда равен off, и правило выше даёт бесконечный редирект - браузер покажет ERR_TOO_MANY_REDIRECTS. В этом случае проверяйте заголовок, который передаёт Nginx:
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
Обратную переадресацию с https на http делают редко - например, если сертификат перестал работать. Это временная мера: без HTTPS браузеры помечают сайт как небезопасный.
Сайт с www или без www
Для поисковиков site.ru и www.site.ru - разные адреса. Выберите один вариант главным зеркалом и перенаправьте второй. Лучше сразу совместить с https, чтобы любая комбинация приводила на правильный адрес за один редирект, без цепочек:
RewriteEngine On
# Всё (http, www) → https://site.ru одним 301
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC,OR]
RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
Если нужен вариант с www, правило зеркальное:
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\. [NC,OR]
RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^(.*)$ https://www.%1/$1 [R=301,L]
Проверьте все четыре варианта главной: http://site.ru, http://www.site.ru, https://www.site.ru и https://site.ru. Первые три должны отдавать один 301 сразу на главное зеркало.
ЧПУ: красивые адреса через .htaccess
ЧПУ (человекопонятные URL) - адреса вида /catalog/phones/ вместо /index.php?page=catalog&cat=7. Современные фреймворки и CMS используют схему "единой точки входа": если запрошенного файла или папки нет, запрос передаётся в index.php, а PHP разбирает адрес сам.
RewriteEngine On
RewriteBase /
# Существующие файлы и папки отдаём как есть
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Всё остальное - в index.php
RewriteRule ^ index.php [L]
В index.php адрес берётся из $_SERVER['REQUEST_URI']:
<?php
declare(strict_types=1);
// Путь без строки параметров: /catalog/phones/
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) ?? '/';
$parts = array_values(array_filter(explode('/', $path)));
match ($parts[0] ?? '') {
'' => require __DIR__ . '/pages/home.php',
'catalog' => require __DIR__ . '/pages/catalog.php',
default => http_response_code(404),
};
Как устроен такой роутер в связке с контроллерами и шаблонами, показано в статье MVC на чистом PHP.
Слеш в конце адреса
Адреса со слешем и без - тоже дубли. Добавить слеш ко всем адресам, кроме файлов:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !/$
RewriteRule ^(.*)$ /$1/ [R=301,L]
Это правило ставят выше блока ЧПУ, иначе запрос уйдёт в index.php раньше редиректа.
Стандартный .htaccess WordPress и Laravel
WordPress создаёт свой блок между метками # BEGIN WordPress и # END WordPress и перезаписывает его при сохранении "Настройки → Постоянные ссылки". Свои правила (редиректы, защиту) пишите выше этого блока, иначе они пропадут. Если файл испорчен, удалите блок и нажмите "Сохранить изменения" на странице постоянных ссылок - WordPress создаст правильный заново.
В Laravel .htaccess лежит в папке public, и корень сайта на хостинге должен указывать именно на неё. Файл из коробки уже содержит правила для ЧПУ и передачу заголовка Authorization; менять его почти не нужно.
Запрет доступа: deny from all, IP и файлы
В Apache 2.4 доступ настраивается директивой Require. Старая запись Deny from all из Apache 2.2 работает только при подключённом модуле совместимости, поэтому в новых файлах используйте Require all denied - смысл тот же: "никого не пускать".
# Закрыть всю папку (например, /uploads/backup/)
Require all denied
# Пустить только свой IP - например, в папку админки
Require ip 203.0.113.25
# Заблокировать IP и подсеть, остальных пускать
<RequireAll>
Require all granted
Require not ip 198.51.100.7
Require not ip 192.0.2.0/24
</RequireAll>
Защита служебных файлов
Файлы .env, .git, дампы баз и логи не должны открываться из браузера. Закройте их в корневом .htaccess:
# Скрытые файлы и папки: .env, .git, .htpasswd, сам .htaccess
<FilesMatch "^\.">
Require all denied
</FilesMatch>
# Дампы, логи и резервные копии
<FilesMatch "\.(sql|log|bak|ini)$">
Require all denied
</FilesMatch>
# Отключить список файлов в папках без index
Options -Indexes

Пароль на папку
Чтобы закрыть тестовую версию сайта паролем, создайте файл паролей вне папки сайта и подключите его:
# Создать файл и пользователя (утилита из пакета apache2-utils)
htpasswd -c /home/user/.htpasswd admin
AuthType Basic
AuthName "Закрытый раздел"
AuthUserFile /home/user/.htpasswd
Require valid-user
Путь в AuthUserFile - полный путь на сервере, а не адрес на сайте.
Кеширование и сжатие
Браузер может хранить картинки, стили и скрипты у себя и не скачивать их при каждом заходе. Это ускоряет сайт и улучшает оценку PageSpeed. За срок хранения отвечает модуль mod_expires, за сжатие - mod_deflate. Оборачивайте директивы в <IfModule>: если модуля нет, сайт не упадёт с ошибкой 500.
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/webp "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/svg+xml "access plus 1 year"
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType font/woff2 "access plus 1 year"
</IfModule>
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/css text/plain
AddOutputFilterByType DEFLATE application/javascript application/json image/svg+xml
</IfModule>
Если вы надолго кешируете CSS и JS, после каждой правки меняйте версию в ссылке: style.css?v=2. Иначе посетители ещё месяц будут видеть старый файл. Проверить, что сжатие работает, можно так:
curl -sI -H "Accept-Encoding: gzip" https://site.ru/style.css | grep -i -E "content-encoding|expires|cache-control"
Другие полезные настройки
Свои страницы ошибок
ErrorDocument 404 /404.html
ErrorDocument 500 /500.html
Страница 404 должна отдаваться именно с кодом 404, а не перенаправлять на главную: иначе поисковики увидят сотни дублей главной.
Настройки PHP: память и размер загрузки
Запрос "htaccess переопределить память" встречается часто, но директивы php_value memory_limit 256M работают только если PHP подключён как модуль Apache (mod_php). На большинстве современных хостингов PHP работает через FPM, и такая строка даёт ошибку 500. Надёжнее положить в корень сайта файл .user.ini:
memory_limit = 256M
upload_max_filesize = 64M
post_max_size = 64M
Все варианты, где менять настройки PHP и как убедиться, что они применились, - в статье php.ini: где находится.
Кодировка по умолчанию
AddDefaultCharset UTF-8
Как проверить .htaccess и найти ошибку
- После каждого изменения откройте сайт в режиме инкогнито и пару внутренних страниц.
- Проверьте редиректы командой
curl -IL адрес: она покажет всю цепочку. Хороший результат - один 301 и затем 200. - Если сайт отдаёт 500, посмотрите лог ошибок Apache: там будет строка файла .htaccess с ошибкой.
- Если правила не срабатывают вовсе, проверьте, что включены
mod_rewriteиAllowOverride All.

Локально удобно тренироваться в XAMPP: там Apache и .htaccess работают так же, как на хостинге, а ошибка не уронит рабочий сайт.
Частые вопросы
Где находится файл .htaccess?
В корне сайта, обычно в public_html или www. Файл скрытый: включите показ скрытых файлов в FTP-клиенте или файловом менеджере хостинга. Если файла нет, его можно создать.
Как сделать редирект с http на https в .htaccess?
Добавьте RewriteEngine On, условие RewriteCond %{HTTPS} off и правило RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]. Если перед Apache стоит Nginx, проверяйте заголовок X-Forwarded-Proto.
Что значит deny from all в .htaccess?
Это запрет доступа к папке для всех посетителей в синтаксисе Apache 2.2. В Apache 2.4 то же самое пишется как Require all denied.
Как заблокировать IP в .htaccess?
Внутри блока <RequireAll> укажите Require all granted и строку Require not ip 198.51.100.7. Подсеть задаётся так: 192.0.2.0/24.
Почему .htaccess не работает?
Сервер работает на Nginx, который не читает .htaccess, в конфиге Apache не включён AllowOverride All или не подключён mod_rewrite. Проверьте и то, что файл назван точно .htaccess, без расширения .txt.
Можно ли увеличить память PHP через .htaccess?
Только если PHP работает как модуль Apache: php_value memory_limit 256M. При PHP-FPM эта строка вызовет ошибку 500, используйте файл .user.ini.



