Документация

ЧПУ без .htaccess

ЧПУ — это урлы понятные человеку. То есть не бессмысленный набор символов вида http://domain.ru/modules.php?module=vitrina&action=superstition&cat_id=999&product_id=7293, а читаемый http://domain.ru/vitrina/snowboards/burton_genie. Ну, это лирика :)

Достичь ЧПУ можно с помощью так называемых преобразований строки урла в ту же «бессмысленную» с человеческой точки зрения строку, а можно заранее предусмотреть ЧПУ в разработки скриптов. Как бы то ни было, без преобразований урла не обойтись.

Как уже знаем, в nginx не существует апачевского .htaccess, где можно было бы настроить правила для столь популярного mod_rewrite, собственно mod_rewrite — это модуль именно для Apache...

Но не стоит расстраиваться! У nginx есть свой модуль — ngx_http_rewrite_module. По моему скромному мнению, модуль rewrite у nginx более гибок, понятен и прост в освоении, нежели mod_rewrite у Apache. Хотя, оба требуют особого понимания работы системы «ревратов» для написания правил :)

Правила преобразования нужно прописывать в конфигурационный файл сайта.

Для перевода из .htaccess в nginx можно воспользоваться htaccess-конвертером для nginx нашей собственной разработки.

Пример правила перезаписывания урла

rewrite  ^/users/(.*)$  /show.php?user=$1  last;

Если серверу приходит запрос /users/alex, то мы такой запрос перепишем на другой /show.php?user=alex и выполнится скрипт /show.php с GET-параметром user. При этом пользователь будет видеть в строке адреса в браузере первоначальный запрос.

Приведенный пример лишь показывает как можно преобразовать строку запроса. Опять же по моему скромному мнению, так делать нельзя. Нужно сводить все запросы на несуществующие файлы к единому обработчику-роутеру (это может быть index.php), который разберет урл запроса и передаст управление нужным контроллерам с нужными данными.

Примерно это должно выглядеть так:

server {
    listen 80;

    server_name my-domain.local www.my-domain.local;

    index index.html index.php;

    root home/my-domain.local/public_html;

    location / {
        try_files $uri $uri/index.html $uri/index.php @router;
    }

    location @router {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME $document_root/index.php;
        include fastcgi_params;
    }

    location ~ \.php$ {
        try_files $uri @router;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

}

Основное правило перезаписей — чем меньше условий и правил, тем лучше :)

Пример типичных правил для Drupal

В Apache мы имеем следующее:

<FilesMatch "\.(engine|inc|info|install|make|module|profile|test|po|sh|.*sql|theme|tpl(\.php)?|xtmpl)$|^(\..*|Entries.*|Repository|Root|Tag|Template)$">
    Order allow,deny
</FilesMatch>

RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^ index.php [L]

Перепишем правило для nginx:

location ~* \.(engine|inc|info|install|make|module|profile|test|po|sh|.*sql|theme|tpl(\.php)?|xtmpl)$ {
    deny all;
}

location ~* ^/(\..*|Entries.*|Repository|Root|Tag|Template)$ {
    deny all;
}

location /favicon.ico {
}

location / {
    try_files $uri @drupal;

    ## либо так:
    #try_files $uri /index.php$is_args$args;

    ## другой вариант:
    #if (!-f $request_filename) {
    #   rewrite ^(.*)$ /index.php;
    #}
}

location @drupal {
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_param SCRIPT_FILENAME $document_root/index.php;
    include fastcgi_params;
}

Примечание. В примере излишне длинная строка запретных запросов, которую можно было бы избежать, убрав из «видимой» части нежелательные файлы и папки. Данное поведение неправильно, но для примера осталось неизменным.

Пример типичных правил для Joomla

RewriteBase /
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteCond %{REQUEST_URI} !^/index\.php
RewriteCond %{REQUEST_URI} /component/|(/[^.]*|\.(php|html?|feed|pdf|vcf|raw))$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php [L]

Перепишем правило для nginx:

location / {
    try_files $uri @joomla;
}

location @joomla {
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_param SCRIPT_FILENAME $document_root/index.php;
    include fastcgi_params;
}

Примечание. В примере излишние условия проверок убраны при переводе на nginx (их можно было убрать и в Apache).

Пример типичных правил для Wordpress

RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

Перепишем правило для nginx:

location / {
    try_files $uri @wordpress;
}

location @wordpress {
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_param SCRIPT_FILENAME $document_root/index.php;
    include fastcgi_params;
}

Пример типичных правил для MODX

RewriteEngine On
RewriteBase /

RewriteCond %{HTTP_USER_AGENT} ^.*internal\ dummy\ connection.*$ [NC]
RewriteRule .* - [F,L]

RewriteRule ^(manager|assets) - [L]

# For Friendly URLs
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]

Перепишем правило для nginx:

if ($http_user_agent ~* "internal dummy connection") {
    return 403;
}

location /manager {
}

location /assets {
}

location / {
    try_files $uri @modx;

    ## или так:
    #try_files $uri /index.php?q=$uri&$args;

    ## другой вариант:
    #if (!-f $request_filename) {
    #   rewrite ^(.*)$ /index.php?q=$1;
    #}
}

location @modx {
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_param SCRIPT_FILENAME $document_root/index.php;
    include fastcgi_params;
    fastcgi_param QUERY_STRING q=$uri&$args;
}

Как видим, здесь немного есть отличия, скрипт index.php не может (не хочет?) сам определить запрошенный урл и желает его получить в GET-переменную q. Что ж, мило :)

Кроме того, можно смело избавиться от первой строчки, где проверяется наличие строки "internal dummy connection" в юзер-агенте, потому что это фикс для Apache, а у нас-то с вами nginx, не так ли? :)

Пример типичных правил для Битрикс

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !/bitrix/urlrewrite.php$
RewriteRule ^(.*)$ /bitrix/urlrewrite.php [L]

Перепишем правило для nginx:

location / {
    try_files $uri @bitrix;
}

location @bitrix {
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_param SCRIPT_FILENAME $document_root/bitrix/urlrewrite.php;
    include fastcgi_params;
}

Без комментариев ;)

Winginx © Alexei Shabalin, 2011-2023