Remove index.php from the URL in Laravel

Want to help support this blog? Try out Oh Dear, the best all-in-one monitoring tool for your entire website, co-founded by me (the guy that wrote this blogpost). Start with a 10-day trial, no strings attached.

We offer uptime monitoring, SSL checks, broken links checking, performance & cronjob monitoring, branded status pages & so much more. Try us out today!

Profile image of Mattias Geniar

Mattias Geniar, November 21, 2019

Follow me on Twitter as @mattiasgeniar

If you have a Laravel project, you might be surprised to find your routes are probably available on a number of different URLs.

Imagine the following example from your routes file:

<?php

Route::view('/feature/uptime-monitoring', 'front/feature/uptime-monitoring');

This creates a route at yourdomain.tld/feature/uptime-monitoring, which you’d expect.

But in most webserver configs, this means the following URLs are all valid and will all return an HTTP/1.1 200 OK with the same page:

https://ohdear.app/feature/uptime-monitoring
https://ohdear.app/index.php/feature/uptime-monitoring

What’s that index.php doing in there? It’s needed for some hosting environments that don’t support pretty-printed URLs.

But you might not need/want it, so let’s get rid of it!

Removing index.php from within your Laravel code

One way to get rid of it, is to check the route in Laravel and issue a redirect there if needed.

Here’s one way to do this in app/Providers/RouteServiceProvider.php.

<?php

use Illuminate\Support\Str;

class RouteServiceProvider extends ServiceProvider
{
    public function map(Router $router)
    {
        $this->removeIndexPhpFromUrl();
    }

    protected function removeIndexPhpFromUrl()
    {
        if (Str::contains(request()->getRequestUri(), '/index.php/')) {
            $url = str_replace('index.php/', '', request()->getRequestUri());

            if (strlen($url) > 0) {
                header("Location: $url", true, 301);
                exit;
            }
        }
    }
}

This will redirect any URL with index.php in it.

$ curl -I "http://ohdear.app.test/index.php/pricing"
HTTP/1.1 301 Moved Permanently
Location: /pricing

$ curl -i "http://ohdear.app.test/index.php/feature/uptime-monitoring"
HTTP/1.1 301 Moved Permanently
Location: /feature/uptime-monitoring

There are some alternative ways to get the same result, by redirecting on the webserver itself.

Redirecting index.php in Nginx

You can redirect if index.php is in the URL like this.

if ($request_uri ~* "^/index\.php(/?)(.*)") {
    return 301 $2;
}

You might have to repeat this if you have different location {} blocks in your Nginx config.

Redirecting index.php in Apache

You can add an additional line in your .htaccess.

$ cat .htaccess
<IfModule mod_rewrite.c>
    RewriteEngine On

    # Redirect if index.php is in the URL
    RewriteRule ^index.php/(.+) /$1 [R=301,L]
</IfModule>

At least that’s an easy regex/fix. :-)

Redirecting index.php in Caddy

It’s a bit cumbersome, but this seems to work in Caddy.

$ cat Caddyfile
https:// {

	tls {
		ask https://ohdear.app/caddy/allowed-domain
	}

	rewrite {
	 	regexp ^/index.php/(.*)
	    	to /{1}
	}

	redir {
	    	if {uri} not {rewrite_uri}
	    	/ {rewrite_uri}
	}
}

It requires an internal rewrite to match the index.php and then a redir to redirect the actual request.



Want to subscribe to the cron.weekly newsletter?

I write a weekly-ish newsletter on Linux, open source & webdevelopment called cron.weekly.

It features the latest news, guides & tutorials and new open source projects. You can sign up via email below.

No spam. Just some good, practical Linux & open source content.