Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

mikefolsom's avatar

Redirect "legacy" .html and .php extensions in nginx

This is something I run into quite frequently: Say a client has previously had a site with URIs like "about.php" or "contact.html". Now they have migrated to Laravel/Forge and the analogous URIs are simply "about" or "contact". However, search engine indices, print materials, etc. still list those old URLs with file extensions.

What is the most elegant solution to perform 301 redirects where appropriate, and to avoid 404 errors? i.e. 301 redirect "about.php" to "about" if "about" exists, or 404 if "about" does not exist.

Bonus points: also the best way to remap URLs whose names have changed from, say, "our-locations.html" to "locations"?

0 likes
6 replies
kfirba's avatar

@mikefolsom You can just go with a simple, scalable laravel based solution and use the router for that:

// web.php
Route::get('our-locations.php`, 'RedirectsController@locations`);
// RedirectsController.php

public function locations()
{
   return redirect('locations', 301);
}

It sucks that we need to use an intermediate controller in order to achieve a simple redirect. Luckily, Laravel 5.5 has an easy way to do that:

// Laravel 5.5+ only:
Route::redirect('our-locations.php', 'locations', 301);
Cronix's avatar

Typically I put redirects like that directly in the nginx/apache config so it doesn't even touch the app. PITA if there are a lot of them, but you just have to do it once, it will work perfectly, and no code. I think you will run into some complexity trying to do it via code. But if you must, I'd use regex for the route for .html and .php and capture them that way instead of a route for each individual one.

mikefolsom's avatar

Thanks for the responses, everyone.

@jlrdw Ideally, I would like this in my nginx configuration, and I would like to use regex instead of explicitly redirecting every route.

@kfirba Thanks for the heads up on the 5.5 option.

@Cronix could you share the details of your approach?

--

This has been my solution in the past. It works, but stinks if there are a bunch of URLs to redirect.

// routes file

$routeMap = [
    'our-services.html' => 'services',
    'about-us.html' => 'about',
    // etc.
];

foreach ($routeMap as $old => $new) {
    Route::get($old, function () use ($new) {
        return redirect()->route($new);
    });
}
Cronix's avatar
Cronix
Best Answer
Level 67

In apache:

Redirect 301 /oldpage.html http://www.yoursite.com/correctpage

In Nginx:

location /oldpage.html {
   rewrite ^/.* http://$server_name/correctpage permanent;
}

Yes it's a pain to do with a lot of urls, but it keeps it from even hitting laravel and consuming resources. And you just have to do it once. Your scenario of "checking if it exists" could be problematic, unless you have individual routes for everything where you could check if the route existed.

mikefolsom's avatar

I ended up adding a bunch of lines like this:

rewrite ^/somepage.html$ /somepage permanent;

Not too painful, thanks to Sublime Text's shift-cmd-d and cmd-d. :)

Please or to participate in this conversation.