Soft2Soft Dev Practical knowledge base
Yii2

Yii2 Pretty URLs Return 404: Step-by-Step Apache and Nginx Troubleshooting

13 views
yii2 pretty-url 404 apache nginx

First Identify the Source of the 404

A 404 status can originate at different levels. The web server may fail to pass the request to index.php, or Yii2 may receive the request but fail to find the route.

SymptomCauseWhere to Look
Default Apache or Nginx 404 pageThe rewrite rule did not run, or the document root is incorrectVirtualHost, server block, .htaccess, try_files
Yii2-styled error pageThe request reached the application, but the route was not foundurlManager, rules, controllers, and actions
/index.php/site/index works, but /site/index does notThe pretty URL is not being passed to the entry pointmod_rewrite or try_files
Even the URL containing index.php does not workThe site root or PHP handling is incorrectdocument root, PHP-FPM, index.php

Start with these two requests:

curl -I https://example.test/index.php/site/index
curl -I https://example.test/site/index

If the first URL opens but the second returns a server-generated 404, the problem occurs before Yii2. If both requests reach Yii2, check the application routes.

Check enablePrettyUrl and showScriptName

'components' => [
    'urlManager' => [
        'enablePrettyUrl' => true,
        'showScriptName' => false,
        'rules' => [],
    ],
],

enablePrettyUrl enables parsing of pretty URLs, while showScriptName = false removes index.php from generated links. This setting does not configure Apache or Nginx: the request must still reach the entry point.

During troubleshooting, leave rules empty and test the standard /site/index route. This makes it easier to distinguish a rewrite problem from an error in a custom rule.

Check the Document Root

In Yii2 Advanced, the public directory of the frontend application must be frontend/web, not the project root or the frontend directory. This directory contains index.php, assets, and the .htaccess file.

/var/www/project/frontend/web/index.php

For the Basic Template, the public directory is web:

/var/www/project/web/index.php
If the document root points to frontend/web, the rewrite rules must apply to that exact directory. The server may not read a file located in the repository root at all.

Apache: mod_rewrite and .htaccess

Check the Rewrite Module

apachectl -M | grep rewrite

The output must include rewrite_module. After changing modules or the VirtualHost configuration, reload the Apache configuration.

Allow .htaccess Processing

When AllowOverride None is set, Apache ignores rules from .htaccess. For the public directory, you can configure:

<Directory /var/www/project/frontend/web>
    Options FollowSymLinks
    AllowOverride All
    Require all granted
</Directory>

Then validate the configuration:

apachectl configtest
systemctl reload apache2

Use Minimal Rules

The frontend/web/.htaccess file:

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

Existing files and directories are served directly, while all other requests are routed to Yii2. Do not add RewriteBase unless necessary: an incorrect value often breaks an application installed in a subdirectory.

Verify the VirtualHost

<VirtualHost *:80>
    ServerName example.test
    DocumentRoot /var/www/project/frontend/web
<Directory /var/www/project/frontend/web>
    Options FollowSymLinks
    AllowOverride All
    Require all granted
</Directory>

Make sure the domain is served by this exact VirtualHost. An error in ServerName, the hosts file, or the virtual host order may route the request to the default configuration.

Nginx: location and try_files

Nginx does not read .htaccess. Routing must be configured in the active server block:

server {
    listen 80;
    server_name example.test;
    root /var/www/project/frontend/web;
    index index.php;
location / {
    try_files $uri $uri/ /index.php?$query_string;
}
location ~ .php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php-fpm.sock;
}
}

try_files first looks for an existing file or directory, then passes the request to index.php. $query_string preserves GET parameters.

A common mistake is using try_files $uri $uri/ =404;. In that case, a nonexistent path ends with a server-generated 404 and never reaches Yii2. Another possible cause is that the correct location / block is placed in a different server block from the one serving the domain.

nginx -t
systemctl reload nginx

If even /index.php/site/index does not open, check the PHP-FPM socket or address, access permissions, and the SCRIPT_FILENAME value.

When baseUrl Is Required

baseUrl is required when the application is published under a subdirectory rather than at the domain root, for example at https://example.test/app. When the application is installed on a dedicated domain, Yii2 usually detects the base path automatically.

'components' => [
    'request' => [
        'baseUrl' => '/app',
    ],
],

The value must match the external URL prefix, not the filesystem path. Do not specify /var/www/project/frontend/web. An incorrect baseUrl causes incorrect links, assets, and redirects, but it does not replace rewrite configuration.

For a subdirectory installation, align the external prefix, the web server rule, and request.baseUrl. When using a reverse proxy, verify that the prefix is passed to the application.

Troubleshooting Sequence

  1. Open /index.php/site/index. If it does not work, fix the document root and PHP handling.
  2. Open an existing static file from frontend/web to confirm that the public directory is correct.
  3. Enable Pretty URLs, disable the script name, and temporarily remove custom rules.
  4. Check /site/index. A server-generated 404 points to Apache or Nginx, while a Yii 404 page points to a routing problem.
  5. For Apache, check the module, AllowOverride, the location of .htaccess, and the active VirtualHost.
  6. For Nginx, check root, location /, try_files, and the active server block.
  7. Restore custom rules after the standard route works.
  8. For a subdirectory installation, compare the external URL with baseUrl.

Cache and Configuration Reloading

After changes, Apache or Nginx must reload its configuration. PHP-FPM usually does not need to be restarted for rewrite changes, but it may be necessary after modifying the pool or PHP settings.

To rule out application cache issues, use the project's standard console command:

php yii cache/flush-all

Run it from the directory containing the console yii file. It requires a configured console application. Also test the URL with curl or clear the browser cache, especially after permanent redirects.

Clearing the cache does not fix an incorrect document root or enable rewrite. If the 404 is generated by the web server itself, clearing the Yii cache will not change the result.

Checklist

  • DocumentRoot or root points to frontend/web or web.
  • The URL containing index.php opens the standard Yii2 route.
  • enablePrettyUrl is enabled, and showScriptName is disabled.
  • In Apache, mod_rewrite is loaded, .htaccess is allowed, and the rules are located in the public directory.
  • Nginx uses try_files $uri $uri/ /index.php?$query_string;.
  • The domain is served by the expected VirtualHost or server block.
  • Existing files are served directly, while all other requests reach index.php.
  • baseUrl is configured only when there is an actual URL prefix.
  • After changes, the configuration has been validated and the web server has been reloaded.
  • Custom rules are restored after /site/index has been tested successfully.