Красивые URL в Yii 2: настройка urlManager с нуля
Разбираем, как включить человекочитаемые адреса в Yii 2: настройка urlManager, правила маршрутизации, конфигурация Apache и Nginx. К концу у вас будут ссылки вида /post/hello вместо index.php?r=post/view&id=1.

По умолчанию Yii 2 отдаёт адреса вида index.php?r=post/view&id=42. К концу этого гайда у вас будут ссылки вида /post/42 или /post/hello-world, а старый формат перестанет попадать в браузерную строку. Займёт это 15–20 минут: правки в одном конфиге приложения и один файл на уровне веб-сервера.
Материал написан для Yii 2 (ветка 2.0.x, актуальная на момент написания). Yii 3 ещё в разработке и здесь не рассматривается. Если у вас advanced-шаблон, все правки делаются отдельно для frontend и backend — покажу, где именно.
Что нужно иметь до начала
- Установленный проект на Yii 2 (
basicилиadvanced). Проверить версию: в корне выполнитеphp yii— в шапке вывода будет строка вродеYii Framework 2.0.49. - Доступ к файлам конфигурации: для basic это
config/web.php, для advanced —frontend/config/main.php. - Веб-сервер, где вы можете править конфиг или класть
.htaccess: Apache с включённымmod_rewriteлибо Nginx с доступом к секцииserver. - Точка входа доступна по
/index.php— то есть сайт уже работает в базовом виде.
Если сайт ещё не открывается даже через index.php, красивые URL не помогут — сначала поднимите приложение.
Шаг 1. Включаем urlManager
Компонент urlManager в Yii 2 отвечает и за разбор входящего адреса, и за генерацию ссылок через Url::to(). Найдите в конфиге секцию components и добавьте туда:
// config/web.php (basic) или frontend/config/main.php (advanced)
'components' => [
// ... другие компоненты
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing' => false,
'rules' => [
],
],
],enablePrettyUrl включает режим красивых адресов. showScriptName убирает index.php из ссылок — но чтобы адреса без index.php реально открывались, нужен ещё Шаг 3.
Проверка: откройте любую существующую страницу и наведитесь на ссылку из меню. В адресной строке или в статусной строке браузера вместо ?r= должен появиться путь вида /site/about.
Шаг 2. Пишем правила маршрутизации
Массив rules сопоставляет шаблон URL с маршрутом контроллер/действие. Ключ — шаблон адреса, значение — маршрут. Заполним:
'rules' => [
// GET /posts -> PostController::actionIndex()
'posts' => 'post/index',
// GET /post/42 -> PostController::actionView(), id = 42
'post/<id:\d+>' => 'post/view',
// GET /post/hello-world -> actionView(), slug = hello-world
'post/<slug:[\w-]+>' => 'post/view',
// короткая запись сразу для нескольких действий одного контроллера
'GET <controller:\w+>/<id:\d+>' => '<controller>/view',
'POST <controller:\w+>s' => '<controller>/create',
],Конструкция <id:\d+> — это именованный параметр: слева имя, справа регулярное выражение для допустимых значений. \d+ — только цифры, [\w-]+ — буквы, цифры, подчёркивание и дефис. Значение попадёт в действие как $id или в $_GET.
Порядок правил критичен. Yii проверяет их сверху вниз и берёт первое совпадение. Если правило соslugстоит выше правила сid, адрес/post/42уйдёт в slug-ветку, потому что цифры тоже подходят под[\w-]+. Ставьте более строгие шаблоны выше.
В действии контроллера параметр принимается как аргумент:
// controllers/PostController.php
public function actionView($id)
{
$model = Post::findOne($id);
if ($model === null) {
throw new \yii\web\NotFoundHttpException('Пост не найден');
}
return $this->render('view', ['model' => $model]);
}Проверка: откройте /post/1 (подставьте реальный id). Должна отрендериться страница поста, а не 404 и не список.
Шаг 3. Настраиваем веб-сервер
Yii с showScriptName => false генерирует ссылки без index.php, но сервер об этом не знает: физического файла /post/42 на диске нет. Нужно перенаправить все несуществующие пути на точку входа.
Apache
Положите файл .htaccess в тот же каталог, где лежит index.php (в basic это корень или web/):
Options +FollowSymLinks
IndexIgnore */*
RewriteEngine on
# если файл или каталог существует физически — отдаём как есть
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# всё остальное — на точку входа
RewriteRule . index.phpДля работы нужен модуль mod_rewrite. Проверить, включён ли он: apache2ctl -M | grep rewrite (на Debian/Ubuntu). Ещё в конфиге виртуального хоста должно стоять AllowOverride All для этого каталога, иначе .htaccess просто игнорируется.
Nginx
Nginx .htaccess не читает, правьте секцию server:
location / {
# пробуем файл, потом каталог, потом отдаём в index.php
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}Точный путь к сокету php-fpm зависит от версии PHP и системы — сверьте с содержимым каталога /run/php/ или конфигом пула php-fpm. После правки: nginx -t и systemctl reload nginx.
Проверка: откройте /post/1 напрямую, набрав адрес руками (не переходя по ссылке). Если страница открылась без index.php в пути — сервер настроен верно.
Обратные ссылки: генерируйте, не пишите руками
Не пишите пути строкой в шаблонах. Используйте Url::to() и Html::a() — они читают те же rules и построят корректный адрес, даже если вы потом поменяете шаблон в конфиге.
use yii\helpers\Url;
use yii\helpers\Html;
// сгенерирует /post/42 по правилу post/<id:\d+>
$url = Url::to(['post/view', 'id' => 42]);
// готовая ссылка-тег
echo Html::a('Читать пост', ['post/view', 'id' => 42]);Если не получилось
- Открывается только главная, остальные страницы дают 404 сервера (не Yii). Веб-сервер не перенаправляет запросы на
index.php. Для Apache — не включёнmod_rewriteили стоитAllowOverride None. Для Nginx — нетtry_files. - Ссылки в меню всё ещё содержат
index.php. Не выставленshowScriptName => false, либо вы правите не тот конфиг (в advanced frontend и backend читают разные файлы). - Адрес
/post/42открывает не тот контроллер. Правило со slug стоит выше правила с id — поменяйте порядок, строгие шаблоны выше. - «Unable to resolve the request» от Yii. Запрос дошёл до приложения, но ни одно правило не совпало и контроллера с таким именем нет. Проверьте шаблон в
rulesи что действие существует. - Ссылка ведёт на нужный путь, но при переходе 404 от Yii. Регулярка в правиле не пропускает значение — например,
\d+при slug из букв. Расширьте шаблон или добавьте отдельное правило.
Что делать дальше
После базовой настройки посмотрите в сторону UrlRule с классом-обработчиком, если нужны нестандартные правила — например, множественные параметры или маршрут по полю модели из БД. Если планируете REST API, изучите yii\rest\UrlRule: он сам разворачивает CRUD-маршруты. Отдельная тема — SEO-редиректы со старых ?r=-адресов на новые: здесь мы её не разбираем, но enableStrictParsing => true заставит Yii отдавать 404 на адреса, не описанные в правилах, — полезно, чтобы отловить дубли.
Защитник прав потребителей: Досудебные претензии на возврат товара со ссылками на ЗоЗПП.
Спросить за 15 ₽Источники: Yii 2 Guide — Routing and URL Creation, Yii 2 Guide — Installing Apache and Nginx (URL configuration)
Частые вопросы
У меня advanced-шаблон, красивые URL не включаются во всём приложении
А если у меня Yii 1.1, а не Yii 2?
Настроил всё по инструкции, а страницы кроме главной всё равно 404
Обязательно ли убирать index.php через showScriptName?
Стоит ли включать enableStrictParsing на боевом сайте?
Как использовать slug вместо id в адресе?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.