How to Remove index.php from the URL in CodeIgniter 4 (Apache, Nginx, XAMPP and Shared Hosting)
By default, a CodeIgniter 4 site can show index.php in its links, such as example.com/index.php/about. Clean URLs such as example.com/about look better, are easier to share, and are better for SEO. To get them, you need two things: a small change in CodeIgniter’s configuration, and a web server that sends every request to the front controller (public/index.php). This guide shows the correct setup for Apache, Nginx, XAMPP and shared hosting, and explains why the popular “copy index.php to the project root” trick is a bad idea.
Quick answer
- Point your web server’s document root to the project’s public folder.
- In app/Config/App.php, set
$baseURL(with a trailing slash) and set$indexPage = ''. - Make sure the web server rewrites URLs: mod_rewrite and AllowOverride All on Apache, or try_files on Nginx.
This follows the official CodeIgniter 4 user guide (checked against version 4.7.5).
Why remove index.php?
- Cleaner URLs that are easier to read, remember and share
- Better SEO. Short, readable URLs are easier for search engines and users to understand
- No duplicate pages. If both /about and /index.php/about work, search engines can treat them as two pages, so you should keep only the clean version
How CodeIgniter 4 is organised (and why it matters)
In CodeIgniter 4, the file index.php lives inside the public folder, and the rest of your project is outside it:
myproject/
├── app/
├── vendor/ (or system/)
├── writable/
├── .env
└── public/
├── index.php
└── .htaccessThe web server should serve only the public folder. Then your code (app), your settings and secrets (.env), and your logs and cache (writable) cannot be requested from a browser. That is the reason why the document root must be public.
Step 1: Update app/Config/App.php
Open app/Config/App.php and change these values.
Setting | Before | After |
|---|---|---|
baseURL |
|
|
indexPage |
|
|
In older 4.0 and 4.1 projects, the lines look like public $baseURL = ... without a type.
Two things to remember:
- Always end the baseURL with a slash. A missing slash is a common cause of broken CSS and links.
- You can also set the base URL in your .env file, which is handy when your local and live addresses differ:
app.baseURL = 'http://myproject.local/'Setting $indexPage to an empty string makes CodeIgniter stop adding index.php when it builds links with functions such as site_url() and base_url(). It does not change how your web server works, so the next step is also needed.
You do not need to change $uriProtocol for this. The official guide does not ask for it, so leave the default (REQUEST_URI) unless your host tells you otherwise.
Step 2: Configure your web server
Apache (Linux, XAMPP, WAMP, cPanel)
1. Enable mod_rewrite. In httpd.conf, make sure this line is not commented out:
LoadModule rewrite_module modules/mod_rewrite.soOn Ubuntu or Debian, run:
sudo a2enmod rewrite
sudo systemctl restart apache22. Allow .htaccess files. The directory that holds your site needs AllowOverride All:
<Directory "/var/www/myproject/public">
AllowOverride All
Require all granted
</Directory>3. Use a virtual host that points to the public folder (the method that the CodeIgniter guide recommends):
<VirtualHost *:80>
DocumentRoot "/var/www/myproject/public"
ServerName myproject.local
<Directory "/var/www/myproject/public">
AllowOverride All
Require all granted
</Directory>
</VirtualHost>For local work, add a line to your hosts file so that the name points to your computer:
127.0.0.1 myproject.localThe hosts file is /etc/hosts on Linux and macOS, and C:\Windows\System32\drivers\etc\hosts on Windows. Restart Apache after you change its configuration.
4. Check the .htaccess file in public. A new CodeIgniter 4 project already contains public/.htaccess with the rewrite rules, so you normally do not have to write anything. The key part looks like this:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([\s\S]*)$ index.php/$1 [L,NC,QSA]It means: if the request is not for a real file or folder, send it to index.php. If your public/.htaccess is missing, copy it from a fresh CodeIgniter 4 installation.
XAMPP or WAMP on your computer
The simplest options:
- Quick development: run php spark serve in the project folder, and open http://localhost:8080. This already gives clean URLs.
- A closer match to a real server: create a virtual host as above, with the DocumentRoot set to your project’s public folder.
If you put your project in htdocs and open localhost/myproject/public/, then public is part of the address, and the setup is not correct. Use a virtual host, an Alias or a symbolic link instead. The CodeIgniter guide describes these under “Hosting with Subfolder”.
Nginx
Point root to the public folder, and send all other requests to index.php:
server {
listen 80;
server_name example.com;
root /var/www/example.com/public;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock; # use your PHP-FPM socket
}
# deny access to hidden files such as .htaccess and .env
location ~ /\. {
deny all;
}
}Then test and reload Nginx:
sudo nginx -t
sudo systemctl reload nginxNginx ignores .htaccess files, so the try_files line does the job of the rewrite rules.
Shared hosting (cPanel and similar)
Best option: change the document root. In cPanel, open the domain settings, and set the document root of your domain to the public folder of your project (for example public_html/myproject/public, or the folder where you uploaded the project). Then the site works with clean URLs, and your private files stay outside the web root.
If you cannot change the document root, the CodeIgniter guide gives a last-resort method. Put a .htaccess file in the project root that sends every request to the public folder:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^(.*)$ public/$1 [L]
</IfModule>
<FilesMatch "^\.">
Require all denied
Satisfy All
</FilesMatch>Then remove the redirect settings from public/.htaccess, as the official guide describes. The CodeIgniter guide does not recommend this, because your project folder sits inside the public web area. If you use it, test the setup carefully, as explained in the next section.
Step 3: Test it
- Open example.com/about (any route of your site). It should load without index.php.
- Check that your CSS, JavaScript and images load.
- Click the links of your site, and check that they have no index.php.
- Try to open example.com/.env, and example.com/app/Config/App.php. Both must fail (a 403 or 404 error). If either one opens, your private files are exposed, so fix the document root immediately.
Why you should not copy index.php to the project root
Some older tutorials, including an earlier version of this one, say that you should copy index.php and .htaccess from the public folder to the project root, and change the Paths.php line in index.php. It makes the URLs clean, but it is not a good setup:
- It puts your app, writable and .env folders inside the web root, so they may become reachable from a browser.
- It breaks the structure that CodeIgniter 4 and its updates expect.
- It is a common reason for sites that leak private files.
The CodeIgniter project recommends pointing the web server to the public folder, and calls anything else a poor practice. Use the document root method above.
Troubleshooting
What you see | Likely cause | Fix |
|---|---|---|
/about gives 404, but /index.php/about works | The rewrite rules are not working. mod_rewrite is off, AllowOverride is not All, or public/.htaccess is missing | Enable mod_rewrite, set AllowOverride All, restart Apache, and check the .htaccess file |
/public/about works, but /about does not | The document root is not the public folder | Point the document root (or the virtual host) to public |
Pages load without styles or images | baseURL is wrong or has no trailing slash | Fix baseURL, and end it with a slash |
Links on the page still contain index.php | indexPage is not an empty string | Set indexPage to an empty string, and clear the cache |
500 Internal Server Error | A mistake in .htaccess, or mod_rewrite is not available | Check the Apache error log, and restore the original public/.htaccess |
Every page except the home page gives 404 on Nginx | The try_files line is missing or wrong | Use the try_files line shown above, and reload Nginx |
502 Bad Gateway on Nginx | The fastcgi_pass path does not match your PHP-FPM socket | Use the correct socket path, for example php8.3-fpm.sock |
Works locally, 404 on the server | Different letter case in file names (Linux is case-sensitive) | Check the file and controller names |
SEO: avoid duplicate URLs after the change
After you remove index.php, your old links may still be in Google’s index and on other sites. Do three things:
- Redirect the old URLs to the clean ones with a 301. On Apache, add this at the top of public/.htaccess, right after RewriteEngine On, and test it:
RewriteCond %{THE_REQUEST} \s/+index\.php/(\S*) [NC]
RewriteRule ^ /%1 [R=301,L]- Use the URL helpers such as site_url() and base_url() for links in your views, so that all internal links use the clean version.
- Check Google Search Console. Submit your sitemap again, and look at the Pages report for old index.php URLs.
Common mistakes
- Forgetting the trailing slash in the base URL
- Leaving the document root on the project folder instead of public
- Enabling mod_rewrite but leaving AllowOverride on None
- Editing the wrong .htaccess file (the one that counts is in public)
- Forgetting to restart Apache or Nginx after a configuration change
- Changing settings in App.php while the .env file overrides them. The .env value wins
FAQs
Do I have to change the uriProtocol setting to PATH_INFO?
No. The official guide does not require it. Keep the default unless your host asks for another value.
How do I remove public from the URL?
Set the web server’s document root to the public folder. Then /public never appears in the address.
Why does the site still open with index.php after I removed it?
The front controller is still reachable at that address. Add the 301 redirect shown above so that old URLs go to the clean ones.
Does this work in all CodeIgniter 4 versions?
The steps are the same across CodeIgniter 4. The exact lines in App.php can look a little different in older releases, where properties have no types.
Is it safe to remove index.php?
Yes, as long as your document root is the public folder. Do not move the project files into the public web root.
Does this work on XAMPP?
Yes. Enable mod_rewrite (it is on by default in most XAMPP versions), set AllowOverride All, and preferably use a virtual host that points to the public folder.
Summary
- Point the document root to the public folder.
- Set the base URL (with a trailing slash), and set the index page to an empty string.
- On Apache, enable mod_rewrite and set AllowOverride All. On Nginx, use try_files.
- Test that your private files, such as .env cannot be opened.
- Redirect old index.php URLs with a 301.
Server settings vary by host. If you are unsure, ask your hosting provider how to change the document root.
