Skip to content

Everything for WordPress, web development — and beyond

🚀 How to remove index.php and index.html from URL: 301 redirect to the site root

🚀 How to remove index.php and index.html from URL: 301 redirect to the site root

You open Google Search Console and see the homepage indexed twice: as site.ru/ and as site.ru/index.php. Or site.ru/index.html. For a search engine, these are two different URLs with identical content. The result: the page's authority is split in half between the duplicates, rankings drop, and crawl budget goes to waste.

The problem is as old as the web. The mechanics are simple: by default, the server returns index.html or index.php when requesting the root via the DirectoryIndex directive, but it doesn't block direct access to site.ru/index.php. From Apache's perspective, both addresses are legitimate. But the search engine sees two different pages with identical content and starts guessing which one to rank.

Below are three ways to set up a 301 redirect from index files to the root: from the universal .htaccess to Cloudflare and Nginx. Plus a verification method that takes two minutes.

💡 Quick overview:

  • Add mod_rewrite rules to .htaccess to intercept requests to index.html and index.php
  • For WordPress and CMS, use a PHP redirect in the entry index.php (it survives permalink updates)
  • Verify the result via curl -I or redirectchecker.com (the response should be 301 Moved Permanently)
  • Go through internal site links and replace /index.php with / in menus, logos, and widgets

Why index file duplicates harm your site

When a visitor types site.ru in the address bar, Apache silently substitutes index.html or index.php according to DirectoryIndex. The browser displays the page, the address stays clean, and the user doesn't notice the substitution.

But if a link to the full path site.ru/index.php already exists somewhere out there, the search crawler follows it, sees the same content as on site.ru/, and records a duplicate. Where does such a link come from? There are plenty of options: an old post on a third-party site, a partner who listed the wrong URL, a social sharing plugin that generated a share with index.php in the tail, or even the developer who added href="/index.html" in the navigation during layout.

What we get in practice:

  • Split link equity. Backlinks are distributed between / and /index.php instead of accumulating on a single canonical page.
  • Wasted crawl budget. The bot spends time crawling duplicates instead of useful sections of the site.
  • Diluted relevance. The search engine doesn't understand which of the two pages to show in results and may alternate between them, user behavior statistics get skewed, and rankings become unstable.

The situation is fully manageable. It's solved by setting up a permanent 301 redirect from index.html and index.php to the root /. Let's explore the available methods.

Method 1: Redirect via.htaccess on Apache

The .htaccess file is located in the site root. If it doesn't exist, create a text file with a dot at the beginning of the name; any FTP client or hosting file manager can handle this.

Open .htaccess and find the line RewriteEngine On. If it's not there, add it as the very first line after any comments. It enables the mod_rewrite module responsible for all redirects.

Below RewriteEngine On, add the rules. Here's a minimal working set:

1RewriteEngine On
2
3RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\.php\ HTTP/
4RewriteRule ^index\.php$ https://%{HTTP_HOST}/ [R=301,L]
5
6RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\.html\ HTTP/
7RewriteRule ^index\.html$ https://%{HTTP_HOST}/ [R=301,L]

How this works line by line:

  • RewriteCond %{THE_REQUEST} checks the original request string sent by the browser to the server. It explicitly contains /index.php or /index.html, which is exactly what we're catching.
  • RewriteRule redirects the request to the domain root with a 301 code (permanent redirect). The L flag (last) stops further rule processing.
  • %{HTTP_HOST} automatically substitutes the site domain; you don't need to type it manually. The protocol is explicitly specified as https://.

Critical note: do not use the simplified construct Redirect 301 /index.php /. The Redirect directive from mod_alias loops on index files. After redirecting to /, Apache again substitutes index.php via DirectoryIndex, the rule triggers again, and the browser throws an infinite loop error. The RewriteCond + RewriteRule combination via mod_rewrite analyzes specifically the original request (%{THE_REQUEST}), not the one rewritten by internal rules, so no looping occurs.

Changes in .htaccess take effect instantly; Apache rereads the file with each request, and no server restart is required.

Method 2: PHP redirect for WordPress and CMS

On sites running WordPress, Joomla, Drupal, and other CMS platforms, editing .htaccess is risky: the CMS rewrites it when updating permalinks, changing URL structure, or activating SEO plugins. Your rules may disappear on the next settings save.

For WordPress, there's a more resilient approach: a redirect directly in the entry file index.php. It's located in the CMS installation root and executes with every request, before the core loads.

Open the WordPress index.php and add at the very beginning, right after the opening <?php tag:

1<?php
2// 301 redirect from index.php to root
3if ($_SERVER['REQUEST_URI'] === '/index.php') {
4 header('Location: /', true, 301);
5 exit();
6}
7
8// Standard WordPress code follows
9define('WP_USE_THEMES', true);
10// ...

For sites on pure PHP without a CMS, the logic is the same: place the code in the entry index.php in the public directory root. If your site uses both index files (index.php and index.html), add a similar check for index.html at the beginning of the same script.

Why this method is more reliable than editing .htaccess for CMS:

  • The code lives inside a PHP file that the CMS doesn't touch when updating permalink settings.
  • The $_SERVER['REQUEST_URI'] check catches specifically the requested URL, not the one rewritten by WordPress internal rules.
  • exit() guarantees execution stops; not a single line beyond it will run.

On high-traffic projects, the PHP redirect is slightly faster than the .htaccess variant: mod_rewrite doesn't spin up to parse regular expressions, saving milliseconds on each request.

Method 3: Cloudflare, Nginx, and other servers

Cloudflare. If your site runs through Cloudflare, you can set up the redirect at the CDN level without touching server files at all. Go to Rules → Redirect Rules and create a rule:

  • Field: URI Path
  • Operator: equals
  • Value: /index.php
  • Redirect URL: https://yourdomain.com/
  • Status code: 301

Add a similar rule for /index.html. The advantage: the redirect fires on Cloudflare edge servers, and the request never even reaches your hosting. The downside: the domain must be delegated to Cloudflare NS.

Nginx. Sites on Nginx don't use .htaccess. Rules are added to the server configuration file, usually /etc/nginx/sites-available/yourdomain:

1location = /index.php {
2 return 301 https://yourdomain.com/;
3}
4
5location = /index.html {
6 return 301 https://yourdomain.com/;
7}

After editing, check the syntax with nginx -t and apply the changes: systemctl reload nginx.

LiteSpeed / OpenLiteSpeed. The server supports .htaccess with the same mod_rewrite rules as Apache; method 1 works without changes. Additionally, you can use the built-in redirect mechanism in the LiteSpeed WebAdmin panel.

IIS (Windows Server). For sites on IIS, the redirect is configured via the URL Rewrite module in web.config:

1<rule name="Redirect index.php to root" stopProcessing="true">
2 <match url="^index\.php$" />
3 <action type="Redirect" url="/" redirectType="Permanent" />
4</rule>

Add a similar rule for index.html.

How to verify the redirect works

The most reliable method is the command line. Run:

1curl -I https://yourdomain.com/index.php

The first line of the response should be HTTP/1.1 301 Moved Permanently, and the Location header should show the site root. Repeat for index.html. The homepage at root / should respond with code 200.

Alternative verification tools:

  • Redirect Checker (redirectchecker.com) shows the full redirect chain with response codes, convenient for quick diagnostics without a terminal.
  • Google Search Console → URL Inspection (the inspect and test tool): shows how Googlebot sees the page after the redirect and whether it's available for indexing.

After setting up the redirect, it's critical to check your site's internal links. Make sure menus, the logo (which usually links to the homepage), breadcrumbs, and related posts blocks point to /, not /index.php. A single broken internal link can recreate the duplicate you just removed. Do a source code search across the site: open any page, press Ctrl+U, and search for href="/index.php" or href="/index.html". Replace each occurrence with href="/".

Video: a short explanation of 301 redirects from Google

A four-minute video from Google Search Central, essential viewing if you're setting up redirects for the first time. John Mueller explains how the search engine processes permanent redirects and whether there's a limit on their number:

⁉️🤔 Frequently asked questions

What happens if I don't set up a redirect from index.php at all?

The search engine will choose a canonical version on its own, but not necessarily the one you need. Part of the link equity will go to the duplicate, and both URLs may alternate in search results. There's no direct threat of penalties, but rankings will be lower than they could be with a clean structure. John Mueller from Google has repeatedly emphasized that canonicalization via rel="canonical" is a hint to the search engine, not a directive. Google may ignore the canonical and choose a different page if it considers it more relevant. A 301 redirect is a directive: it guarantees weight transfer and excludes the duplicate from the index.

Can I use Redirect 301 /index.php / instead of mod_rewrite?

Technically yes, but for index files this is dangerous. After redirecting to /, Apache again substitutes index.php via DirectoryIndex, the Redirect rule triggers again, resulting in an infinite loop, and the browser cuts it off with an ERR_TOO_MANY_REDIRECTS error. RewriteCond with the %{THE_REQUEST} check doesn't have this problem: it analyzes the original request from the browser, not the one rewritten by the server's internal rules.

Do I need to set up a redirect if the site only works over HTTPS?

Yes. HTTPS and index duplicates are two independent issues. Even with an HTTP→HTTPS redirect set up and correct rel="canonical", a direct request to https://site.ru/index.php will return a 200 code without a redirect. The rules from method 1 cover both protocols: RewriteRule explicitly specifies https:// in the target URL.

How do I verify the redirect hasn't broken the site?

Three checkpoints: 1) the homepage opens at root / without redirects (curl -I should return 200); 2) URLs with index.php and index.html return 301 and lead to /; 3) the WordPress admin (/wp-admin/) works without loops. The last point is critical: a poorly written rule in .htaccess can intercept requests to index.php inside the admin and break login. The construct from method 1 is safe: it checks for an exact URI match and doesn't touch /wp-admin/index.php.

What about other index files like index.aspx or index.py?

The mechanics are the same: copy the RewriteCond + RewriteRule block, replace the extension, and add it to .htaccess. For non-standard extensions, make sure the file physically exists in the root and is listed in DirectoryIndex; otherwise the server won't be able to serve it as an index file anyway, and no redirect will be needed.

Dealing with index file duplicates: final checklist

Setting up a 301 redirect from index.html and index.php to the root is a "five minutes of work, years of protection" task. The rule lives in .htaccess or index.php transparently and requires no maintenance when you change designs or move to a different hosting.

Steps to take after making the changes:

  • Verify the redirect via curl -I or redirectchecker.com; the response should be 301.
  • Make sure the homepage opens at root with a 200 code.
  • Search for href="/index.php" and href="/index.html" in the page source code; replace each occurrence with href="/".
  • In Google Search Console, run an inspection of the homepage; the bot should see a 200 and the canonical URL without /index.php.

After this, duplicates will gradually disappear from the "Coverage" report in Search Console, and backlink equity will concentrate on a single canonical page. The result isn't instant (the search engine needs time to recrawl), but it's inevitable.