296

I want to remove the /public/ fragment from my Laravel 5 URLs.

I don't want to run a VM, this just seems awkward when switching between projects.

I don't want to set my document root to the public folder, this is also awkward when switching between projects.

I've tried the .htaccess mod_rewrite method:

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteRule ^(.*)$ public/$1 [L]
</IfModule>

but this gives me a Laravel NotFoundHttpException in compiled.php line 7610.

In Laravel 4 I could move the contents of the public folder into the root. The structure of Laravel 5 is quite different and following the same steps completely broke Laravel (the server would only return a blank page).

Is there a method of removing 'public' in a development environment that allows me to switch between projects with ease (I'm usually working on 2 or 3 at any one time)?

I'm using MAMP and PHP 5.6.2

TylerH
  • 20,799
  • 66
  • 75
  • 101
user1537360
  • 4,751
  • 6
  • 26
  • 22
  • 1
    It seems to work by just modifying the paths in the index.php file, but I'm new to Laravel so obviously can't comment on whether this is stable / safe. – user1537360 Feb 06 '15 at 13:06
  • The other folders/files are supposed to be underneath your document root. – Mike Rockétt Feb 07 '15 at 18:04
  • [laravel remove public from url](https://sdtuts.com/laravel-remove-public-htaccess/) – user3151197 Sep 27 '17 at 16:30
  • 4
    Most of the responses on this page are incredibly bad practice. The ONLY secure solution is to change the _document root_ of your web host to be the public folder. If you are on a server that only publishes the public_html folder, then delete this and create a new public_html symlink that points to and aliases the Laravel public folder. – Snapey Mar 22 '22 at 22:32
  • 2
    A `public` folder is there to be exposed at the document root and nothing else. Not doing so opens you to security issues between the private storage being accessible, the env file and other sensible files. **Change your document root!**, there is no valid reason not to do this elsewhere than a local environment, it's like not hashing a password in the database – Tofandel Aug 31 '22 at 10:25
  • And even trying that on a local environment is weird when laravel provides you with a `serve` command – Tofandel Aug 31 '22 at 10:32
  • @Snapey sorry, you're wrong. ***All*** of the responses on this page are incredibly bad practice. – miken32 Jun 09 '23 at 22:26

30 Answers30

445

Note: This introduces very significant security issues and is not recommended.

For Laravel 5:

  1. Rename server.php in your Laravel root folder to index.php
  2. Copy the .htaccess file from /public directory to your Laravel root folder.
TylerH
  • 20,799
  • 66
  • 75
  • 101
Asfaq Tamim
  • 5,677
  • 5
  • 22
  • 29
282


PLEASE NOTE when serving a Laravel project with Docker: you won't need to do any of this. Only use this option when your root (or more commonly: public_html) directory of your website is your Laravel project (this is not the case when you're using Docker).

DON'T!

YOU REALLY SHOULD NOT rename server.php in your Laravel root folder to index.php and copy the .htaccess file from the /public directory to your Laravel root folder!!!

This way everyone can access some of your files (.env for example). Try it yourself. You don't want that!


DO

Instead, you should create an .htaccess file in your root like this:

RewriteEngine On
RewriteCond %{REQUEST_URI} !^/public/
RewriteRule ^(.*)$ /public/$1 [L,QSA]

This will silently rewrite all your base URIs to the /public folder. Even all Headers, for example the HTTP Authorization Header, and all optional URI parameters will silently be passed on to the /public folder as well.

TylerH
  • 20,799
  • 66
  • 75
  • 101
Derk Jan Speelman
  • 11,291
  • 4
  • 29
  • 45
  • @HaritsinhGohil join this room https://chat.stackoverflow.com/rooms/196804/laravel-and-htaccess to continue our conversation – Derk Jan Speelman Jul 22 '19 at 11:16
  • 1
    Hello, @DerkJanSpeelman I'm trying to upload my laravel files inside a subfolder in my hosting like: (example.com/projects/laravel/blog) in that case, visitors have to visit example.com/projects/laravel/blog/public, so that I put a .htaccess file with your code in the blog folder root and want it to redirect to the public folder. But it's not working. Here is the Error occurring: The requested URL /public/ was not found on this server. How can i solve this ? – Shovan Aug 21 '19 at 06:36
  • 1
    @ShovonDas If you want to make your users go to `example.com/projects/laravel/blog/`. First, create the laravel project inside the `blog` folder. Replace `RewriteCond %{REQUEST_URI} !^/public/` with `RewriteCond %{REQUEST_URI} !^/projects/laravel/blog/public/` and `RewriteRule ^(.*)$ /public/$1 [L,QSA]` with `RewriteRule ^projects/laravel/blog/(.*)$ /projects/laravel/blog/public/$1 [L,QSA]` I *think* that works. Let me know. The `RewriteRule` works like: `RewriteRule pattern target [Flag1,Flag2,Flag3]` [Apache RewriteRule documentation](https://httpd.apache.org/docs/2.4/rewrite/flags.html) – Derk Jan Speelman Aug 21 '19 at 08:36
  • 1
    @RaitisKupce and Riosant https://medium.com/@crocodile2u/docker-setup-for-a-laravel-vue-project-90e4fd3acc7a – Derk Jan Speelman Dec 28 '20 at 14:01
  • This works but I am unable to access any file on the website directly ... like www.test.com/sitemap.xml or www.test.com/images/test.jpg – Loganathan Natarajan Aug 27 '21 at 17:08
  • 1
    @logudotcom if you want to access certain static files on your website, you need to give access to them. You can do this with htaccess. I strongly suggest to look at the htaccess docs https://developer.mozilla.org/en-US/docs/Learn/Server-side/Apache_Configuration_htaccess – Derk Jan Speelman Dec 02 '21 at 09:47
  • 1
    Why even rewrite everything to public and not use the `DocumentRoot` pointing to public which is clearly how it's supposed to be, to avoid possible security issues. I don't get why would anyone willingly expose what's not public to the public ‍♂️ – Tofandel Aug 31 '22 at 10:20
  • 2
    @Tofandel The _goal_ is not to "expose what's not public to the public", it is to remove `/public/` from the URL. One of the easiest and most shared methods to accomplish that just happens to be a way that's not secure, and people tend to do what's easiest/most common because they don't know any better. – TylerH Apr 11 '23 at 15:27
139

Note: This introduces very significant security issues and is not recommended.

I have solved the issue using 2 answers:

  1. Renaming the server.php to index.php (no modifications)

  2. Copy the .htaccess from public folder to root folder (like rimon.ekjon said below)

  3. Changing .htaccess it a bit as follows for statics:

    RewriteEngine On
    
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)/$ /$1 [L,R=301]
    
    RewriteCond %{REQUEST_URI} !(\.css|\.js|\.png|\.jpg|\.gif|robots\.txt)$ [NC]
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]
    
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_URI} !^/public/
    RewriteRule ^(css|js|images)/(.*)$ public/$1/$2 [L,NC]
    

If there are any other static files needed just add the extension to the previous declared list

miken32
  • 42,008
  • 16
  • 111
  • 154
ka_lin
  • 9,329
  • 6
  • 35
  • 56
  • 1
    This for me worked like a bang! It basically solves the problem where no routes work except homepage and then if you try the solution by Derk, it would then work, but not for all the assets and images. This, fixed the routes, and also fixed the assets and images. Thanks a lot. :) – Leutecia Jan 02 '23 at 16:35
  • 3
    Congratulations, now the world can access your app's configuration files. – miken32 Jun 09 '23 at 22:17
136

In Laravel 5.5 create .htacess file in your root directory and placed the following code:- Reference Link

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews
    </IfModule>

    RewriteEngine On

    RewriteCond %{REQUEST_FILENAME} -d [OR]
    RewriteCond %{REQUEST_FILENAME} -f
    RewriteRule ^ ^$1 [N]

    RewriteCond %{REQUEST_URI} (\.\w+$) [NC]
    RewriteRule ^(.*)$ public/$1 

    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ server.php

</IfModule>
Raham
  • 4,781
  • 3
  • 24
  • 27
54

Create an .htaccess file in root directory and place code something like below. However, this will still allow your .env file to be accessible via URL, so it is not secure.

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews
    </IfModule>

    RewriteEngine On

    RewriteCond %{REQUEST_FILENAME} -d [OR]
    RewriteCond %{REQUEST_FILENAME} -f
    RewriteRule ^ ^$1 [N]

    RewriteCond %{REQUEST_URI} (\.\w+$) [NC]
    RewriteRule ^(.*)$ public/$1 

    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ server.php
</IfModule>
TylerH
  • 20,799
  • 66
  • 75
  • 101
Pallav Nagar
  • 627
  • 6
  • 5
45

Easy way to remove public from laravel 5 url. You just need to cut index.php and .htaccess from public directory and paste it in the root directory,thats all and replace two lines in index.php as

require __DIR__.'/bootstrap/autoload.php';
$app = require_once __DIR__.'/bootstrap/app.php';

Note: The above method is just for the beginners as they might be facing problem in setting up virtual host and The best solution is to setup virtual host on local machine and point it to the public directory of the project.

Muhammad Sadiq
  • 1,147
  • 11
  • 13
  • 1
    After that css not load, bcoz all css are in public and the public is removed from url – Mr. Tomar Oct 01 '16 at 05:04
  • 2
    You can put "public/" before the js or css files while loading, eg Html::script("public/js/....."); --But the best solution would be virtual host... – Muhammad Sadiq Oct 03 '16 at 07:07
39

This answer is not recommended because it edits vendor-provided files. Instead, handling it via a change to your .htaccess file is recommended.


rimon ekjon said:

Rename the server.php in your Laravel root folder to index.php and copy the .htaccess file from /public directory to your Laravel root folder.

This worked, but when I made this change, all resource files in the /public directory couldn't be found, and request URLs didn't work, because I used an asset() helper.

I changed the /Illuminate/Foundation/helpers.php/asset() function as follows:

function asset($path, $secure = null)
{
    return app('url')->asset("public/".$path, $secure);
}

Now everything works again.

TylerH
  • 20,799
  • 66
  • 75
  • 101
Miron
  • 1,007
  • 2
  • 17
  • 31
  • 4
    This is not a good way to resolve this problem, as you are trying to update in vendors directory which is not good practice. – Shadman Jan 25 '18 at 06:56
  • 1
    you only need to add `RewriteRule ^(.*)$ public/$1 [L]` in your .htaccess file which you have copied from public directory, by removing this line `RewriteRule ^(.*)/$ /$1 [L,R=301]` – Shadman Jan 25 '18 at 07:17
  • Who is Rimon Ekjon and where did you see them say this quote? – TylerH Apr 11 '23 at 14:29
34

Just create .htaccess file at root and add these lines to it

<IfModule mod_rewrite.c>
    RewriteEngine On

    RewriteRule ^(.*)$ public/$1 [L]
</IfModule>

The above code works on the root public_html folder. Having said that your core laravel file should be inside the public_html folder, if your directory looks like public_html/laravelapp/public and if you put the above code inside laravelapp it won't work. Therefore you must copy all your core files into public_html and put the .htaccess file there.

If you want to keep the code in a subdirectory then you can create a subdomain then this code will work for that also.

TylerH
  • 20,799
  • 66
  • 75
  • 101
Abhinav Saraswat
  • 739
  • 6
  • 13
  • What's the flaws with using this method? – Script47 Oct 10 '18 at 23:40
  • @DeepeshThapa If you want that to work, you simply need to modify the `.htaccess` file so it works with subdirectories. – Derk Jan Speelman May 08 '19 at 06:16
  • I have this in my .htaccess folder in my root public_html folder but I am still getting /public at the end of my url. ## Redirect to public folder RewriteEngine on RewriteRule ^$ public/ [L] RewriteRule (.*) public/$1 [L] ##SSL Code from STO RewriteCond %{HTTPS} off RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] Any ideas? – CodeConnoisseur Jul 04 '19 at 16:14
23

1) I haven't found a working method for moving the public directory in L5. While you can modify some things in the bootstrap index.php, it appears several helper functions are based on the assumption of that public directory being there. In all honestly you really shouldn't be moving the public directory.

2) If your using MAMP then you should be creating new vhosts for each project, each serving that projects public directory. Once created you access each project by your defined server name like this :

http://project1.dev
http://project2.dev
Jignesh Joisar
  • 13,720
  • 5
  • 57
  • 57
Jeremy Schaffer
  • 428
  • 4
  • 9
14

It's possible to remove public url in laravel5. Follow these steps:

step 1.copy all file from public and paste on root directory

step 2.open index.php file replace with

 require __DIR__.'/../bootstrap/autoload.php';

to

 require __DIR__.'/bootstrap/autoload.php';

and

$app = require_once __DIR__.'/../bootstrap/app.php';

to

$app = require_once __DIR__.'/bootstrap/app.php';

And remove all cache and cookies.

Jignesh Joisar
  • 13,720
  • 5
  • 57
  • 57
piyush patel
  • 191
  • 7
  • Hi, I have tried your method, performed the above steps but it shows the following errors: Warning: require_once(D:\Projects\laravel/public/index.php): failed to open stream: No such file or directory in D:\Projects\laravel\server.php on line 21 Fatal error: require_once(): Failed opening required 'D:\Projects\laravel/public/index.php' (include_path='.;C:\xampp\php\PEAR') in D:\Projects\laravel\server.php on line 21 – Ali Shahzad Mar 08 '15 at 07:26
  • 1
    This is not a perfect answer, rather it is a much unsecure way. –  Dec 20 '19 at 13:11
  • 1
    This is incredibly bad advice – Snapey Mar 22 '22 at 22:26
13

Here is the Best and shortest solution that works for me as of may, 2018 for Laravel 5.5

  1. just cut your .htaccess file from the /public directory to the root directory and replace it content with the following code:

    <IfModule mod_rewrite.c>
        <IfModule mod_negotiation.c>
           Options -MultiViews
        </IfModule>
    
        RewriteEngine On
    
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule ^(.*)/$ /$1 [L,R=301]
    
        RewriteCond %{REQUEST_URI} !(\.css|\.js|\.png|\.jpg|\.gif|robots\.txt)$ [NC]
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteRule ^ server.php [L]
    
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_URI} !^/public/
        RewriteRule ^(css|js|images)/(.*)$ public/$1/$2 [L,NC]
    </IfModule>
    
  2. Just save the .htaccess file and that is all.

  3. Rename your server.php file to index.php. that is all enjoy!

Udhav Sarvaiya
  • 9,380
  • 13
  • 53
  • 64
tony pro
  • 405
  • 3
  • 12
11

Let's say you placed all the other files and directories in a folder named 'locale'.

enter image description here

Just go to index.php and find these two lines:

require __DIR__.'/../bootstrap/autoload.php';

$app = require_once __DIR__.'/../bootstrap/app.php';

and change them to this:

require __DIR__.'/locale/bootstrap/autoload.php';

$app = require_once __DIR__.'/locale/bootstrap/app.php';
10

BEST Approach: I will not recommend removing public, instead on local computer create a virtual host point to public directory and on remote hosting change public to public_html and point your domain to this directory. Reason, your whole laravel code will be secure because its one level down to your public directory :)

METHOD 1:

I just rename server.php to index.php and it works

METHOD 2:

This work well for all laravel version...

Here is my Directory Structure,

/laravel/
... app
... bootstrap
... public
... etc

Follow these easy steps

  1. move all files from public directory to root /laravel/
  2. now, no need of public directory, so optionally you can remove it now
  3. now open index.php and make following replacements

require DIR.'/../bootstrap/autoload.php';

to

require DIR.'/bootstrap/autoload.php';

and

$app = require_once DIR.'/../bootstrap/start.php';

to

$app = require_once DIR.'/bootstrap/start.php';

  1. now open bootstrap/paths.php and change public directory path:

'public' => DIR.'/../public',

to

'public' => DIR.'/..',

and that's it, now try http:// localhost/laravel/

Wasim A.
  • 9,660
  • 22
  • 90
  • 120
  • Its ok for everything. but artisan command is not working, just it show "Could not open input file: artisan" . Is there any suggestion ? – Kabir Hossain Jan 29 '17 at 05:45
  • 1
    This method worked, If you are OK to expose your database credentials to users. http://localhost/laravel/.env – MasoodRehman Dec 23 '17 at 14:43
8

I would like to add to @Humble Learner and note that the proper location to "fix" the url path for assets is /Illuminate/Routing/UrlGenerator.php/asset().

Update the method to match:

public function asset($path, $secure = null)
{
    if ($this->isValidUrl($path)) return $path;
    $root = $this->getRootUrl($this->getScheme($secure));
    return $this->removeIndex($root).'/public/'.trim($path, '/');
}

This will fix scripts, styles and image paths. Anything for asset paths.

Sean Perkins
  • 541
  • 3
  • 10
6

For XAMPP user to remove public from url without touching laravel default filesystem is to set a Virtual Host for your application to do this jsut follow these steps

  1. Open the XAMPP control panel application and stop Apache. Be aware that late Windows machines might run it as a service, so check the box to the left of the Apache module.

  2. Navigate to C:/xampp/apache/conf/extra or wherever your XAMPP files are located.

  3. Open the file named httpd-vhosts.conf with a text editor.

  4. Around line 19 find # NameVirtualHost *:80 and uncomment or remove the hash.

  5. At the very bottom of the file paste the following code:

<VirtualHost *>
    ServerAdmin admin@localhost.com
    DocumentRoot "C:/xampp/htdocs" # change this line with your htdocs folder
    ServerName localhost
    ServerAlias localhost
    <Directory "C:/xampp/htdocs">
        Options Indexes FollowSymLinks Includes ExecCGI
        Order allow,deny
        Allow from all
    </Directory>
</VirtualHost>
  1. Now you can copy and paste the code above below to add your Virtual Host directories. For example I’m working on a site called Eatery Engine so the following snippet will allow me to work with sub-domains on my local install:
<VirtualHost eateryengine.dev>
    ServerAdmin admin@localhost.com
    DocumentRoot "C:/xampp/htdocs/eateryengine" # change this line with your htdocs folder
    ServerName eateryengine.dev
    ServerAlias eateryengine.dev
    <Directory "C:/xampp/htdocs/eateryengine">
        Order allow,deny
        Allow from all
    </Directory>
</VirtualHost>
  1. Next head over to your Windows host file to edit your HOSTS. the file will be located at C:/Windows/System32/drivers/etc/hosts, where hosts is the file. Open it with notepad.
  2. Look for #localhost name resolution is handled within DNS itself.

127.0.0.1 localhost

localhost name resolution is handled within DNS itself.

127.0.0.1       localhost
127.0.0.1       eateryengine.dev #change to match your Virtual Host.
127.0.0.1       demo.eateryengine.dev #manually add new sub-domains.
  1. Restart Apache and test everything.

The original article can be found here

pirho
  • 11,565
  • 12
  • 43
  • 70
sunny kashyap
  • 2,193
  • 2
  • 19
  • 29
5

There is always a reason to have a public folder in the Laravel setup, all public related stuffs should be present inside the public folder,

Don't Point your ip address/domain to the Laravel's root folder but point it to the public folder. It is unsafe pointing the server Ip to the root folder., because unless you write restrictions in .htaccess, one can easily access the other files.,

Just write rewrite condition in the .htaccess file and install rewrite module and enable the rewrite module, the problem which adds public in the route will get solved.

Reiah Paul Sam
  • 555
  • 6
  • 16
5

Create new file called .htaccess in root project folder and place the below code inside it :

<IfModule mod_rewrite.c>
 #Session timeout

<IfModule mod_negotiation.c>
    Options -MultiViews
</IfModule>

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ ^$1 [N]

RewriteCond %{REQUEST_URI} (\.\w+$) [NC]
RewriteRule ^(.*)$ public/$1

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ server.php

</IfModule>

Note: If you changed server.php to index.php you also should rename it in above code

Abd Abughazaleh
  • 4,615
  • 3
  • 44
  • 53
3
<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews -Indexes
    </IfModule>

    RewriteEngine On

    # Handle Authorization Header
    RewriteRule ^(.*)$ public/$1 [L]
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

    # Redirect Trailing Slashes If Not A Folder...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} (.+)/$
    RewriteRule ^ %1 [L,R=301]

    # Handle Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]
</IfModule>

Activate the mod_rewrite module with

sudo a2enmod rewrite

and restart the apache

sudo service apache2 restart

To use mod_rewrite from within .htaccess files (which is a very common use case), edit the default VirtualHost with

sudo nano /etc/apache2/sites-available/000-default.conf

Below "DocumentRoot /var/www/html" add the following lines:

<Directory "/var/www/html">
AllowOverride All
</Directory>

Restart the server again:

sudo service apache2 restart
mujuonly
  • 11,370
  • 5
  • 45
  • 75
3

Problem is if you type /public and it will still be available in the url, therefor i created a fix which should be placed in the public/index.php

  $uri = urldecode(
     parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)
  );

  if(stristr($uri, '/public/') == TRUE) {

    if(file_exists(__DIR__.'/public'.$uri)){

    }else{

      $actual_link = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}";
      $actual_link = str_replace('public/', '',$actual_link);
      header("HTTP/1.0 404 Not Found");
      header("Location: ".$actual_link."");
      exit();
      return false;
   }}

this peace of code will remove public from the url and will give a 404 and then redirects to the url without the public

3

I know that are are a lot of solution for this issue. The best and the easiest solution is to add .htaccess file in the root directory.

I tried the answers that we provided for this issue however I faced some issues with auth:api guard in Laravel.

Here's the updated solution:

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews
    </IfModule>

    RewriteEngine On
    RewriteCond %{HTTP:Authorization} ^(.*)
    RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]

    RewriteCond %{REQUEST_FILENAME} -d [OR]
    RewriteCond %{REQUEST_FILENAME} -f
    RewriteRule ^ ^$1 [N]

    RewriteCond %{REQUEST_URI} (\.\w+$) [NC]
    RewriteRule ^(.*)$ public/$1

    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ server.php
</IfModule>

Create the .htaccess file in your root directory and add this code. And everything goes right

3

Create .htaccess file in root directory and place code something like below.

<IfModule mod_rewrite.c>
 #Session timeout

<IfModule mod_negotiation.c>
    Options -MultiViews
</IfModule>

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ ^$1 [N]

RewriteCond %{REQUEST_URI} (\.\w+$) [NC]
RewriteRule ^(.*)$ public/$1

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ server.php

</IfModule>

Create .htaccess file in /public directory and place code something like below.

<IfModule mod_rewrite.c>
  <IfModule mod_negotiation.c>
    Options -MultiViews -Indexes
  </IfModule>

RewriteEngine On

# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]

# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
Ghanshyam Nakiya
  • 1,602
  • 17
  • 24
3

Create an .htaccess file in your root DIR and paste the below code.

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ ^$1 [N]

RewriteCond %{REQUEST_URI} (\.\w+$) [NC]
RewriteRule ^(.*)$ public/$1 

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ server.php
TylerH
  • 20,799
  • 66
  • 75
  • 101
newbdeveloper
  • 394
  • 3
  • 11
2

Even if i do not recommend putting Laravel on the root folder there are some cases when it could not be avoided; for those cases the above methods do not work for assets so i made a quick fix changing the htaccess: after copying server.php to index.php edit the .htaccess file like so:

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews
    </IfModule>

    RewriteEngine On

    ### fix file rewrites on root path ###
    #select file url
    RewriteCond %{REQUEST_URI} ^(.*)$
    #if file exists in /public/<filename>
    RewriteCond %{DOCUMENT_ROOT}/public/$1 -f
    #redirect to /public/<filename>
    RewriteRule ^(.*)$ public/$1 [L]
    ###############

    # Redirect Trailing Slashes If Not A Folder...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)/$ /$1 [L,R=301]

    # Handle Front Controller...

    #RewriteCond %{REQUEST_FILENAME} -d # comment this rules or the user will read non-public file and folders!
    #RewriteCond %{REQUEST_FILENAME} -f #
    RewriteRule ^ index.php [L]
</IfModule>

This was a quick fix i had to make so anyone is welcome to upgrade it.

Plokko
  • 723
  • 2
  • 10
  • 23
2

I used this solution for Laravel 5.5.

  • Don't have public word in the URI
  • Protect the .env file against curious people

Everything can be done just editing the .htaccess using mod_rewrite and four simple rules.

  1. Move the .htaccess file in public/.htaccess in the main root
  2. Edit it as below

I commented everything, so it should be clear (I hope) also to those who have never used mod_rewrite (not that I'm an expert, all the opposite). Also, to understand the rules, it must be clear that, in Laravel, if Bill connects to https://example.com, https://example.com/index.php is loaded. This file just contains the command header("refresh: 5; https://example.com/public/"), which sends the request to https://example.com/public/index.php. This second index.php is responsible to load the controller and other stuff.

# IfModule prevents the server error if the app is moved in an environment which doesn’t support mod_rewrite
<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews
    </IfModule>

    RewriteEngine On

    # RULES ORIGINALLY IN public/.htaccess ---
    # Redirect Trailing Slashes If Not A Folder...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} (.+)/$
    RewriteRule ^ %1 [L,R=301]

    # Handle Front Controller...
#    RewriteCond %{REQUEST_FILENAME} !-d
#    RewriteCond %{REQUEST_FILENAME} !-f
#    RewriteRule ^ index.php [L]

    # Handle Authorization Header
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
    # --- END

    # PERSONAL RULES ---
    # All the requests on port 80 are redirected on HTTPS
    RewriteCond %{SERVER_PORT} ^80$
    RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [R,L]

    # When .env file is requested, server redirects to 404
    RewriteRule ^\.env$ - [R=404,L,NC]

    # If the REQUEST_URI is empty (means: http://example.com), it loads /public/index.php
    # N.B.: REQUEST_URI is *never* actually empty, it contains a slash that must be set as match as below
    # .* means: anything can go here at least 0 times (= accepts any sequence of characters, including an empty string)
    RewriteCond %{REQUEST_URI} ^/$
    RewriteRule ^(.*) /public/index.php [L]

    # If the current request is asking for a REQUEST_FILENAME that:
    # a) !== existent directory
    # b) !== existent file
    # => if URI !== css||js||images/whatever => server loads /public/index.php, which is responsible to load the app and the related controller
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule !^(css|js|images|media)/(.*)$ /public/index.php [L,NC]

    # If the current request is asking for a REQUEST_FILENAME that:
    # a) !== existent directory
    # b) !== existent file
    # => if URI == css||js||images[=$1]/whatever[=$2] => server loads the resource at public/$1/$2
    # If R flag is added, the server not only loads the resource at public/$1/$2 but redirects to it
    # e.g.: bamboo.jpg resides in example.com/public/media/bamboo.jpg
    #       Client asks for example.com/media/bamboo.jpg
    #       Without R flag: the URI remains example.com/media/bamboo.jpg and loads the image
    #       With R flag: the server redirects the client to example.com/public/media/bamboo.jpg and loads the image
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(css|js|images|media)/(.*)$ /public/$1/$2 [L,NC]
    # --- END

</IfModule>

The following rule (originally in public/.htaccess) can be deleted. The same rule, in fact, is explicit in a more detailed way in the last two rules.

# Handle Front Controller...
#    RewriteCond %{REQUEST_FILENAME} !-d
#    RewriteCond %{REQUEST_FILENAME} !-f
#    RewriteRule ^ index.php [L]
TylerH
  • 20,799
  • 66
  • 75
  • 101
Brigo
  • 1,086
  • 1
  • 12
  • 36
0

Another method that I use is to create a symbolic link (in Linux, don't know about Win) using the ln command in htdocs or www i.e. ln projectname/public project The site is thus accessible via localhost/project

Eli Makumba
  • 89
  • 1
  • 1
0

I have read some article before and it's working fine but really don't know is safe or not

  1. Create new folder local.
  2. Move all project into the local folder expect public folder.
  3. Move all the content of public folder to project root.
  4. Delete the blank public folder
  5. Edit the index file.

Edit the index.php

require __DIR__.'/../bootstrap/autoload.php';
$app = require_once __DIR__.'/../bootstrap/app.php';

to

require __DIR__.'/local/bootstrap/autoload.php';
$app = require_once __DIR__.'/local/bootstrap/app.php';
TylerH
  • 20,799
  • 66
  • 75
  • 101
Yousef Altaf
  • 2,631
  • 4
  • 46
  • 71
0

You can make minor change the helpers::asset function.

  1. open vendor\laravel\framework\src\Illuminate\Foundation\helpers.php

  2. goto line 130

  3. write "public/".$path instead of $path,

    function asset($path, $secure = null){
       return app('url')->asset("public/".$path, $secure);
    }
    
TylerH
  • 20,799
  • 66
  • 75
  • 101
Ferhat KOÇER
  • 3,890
  • 1
  • 26
  • 26
0

You can remove public keyword from url using various methods.

1) If you are using dedicated hosting and you have root access then You can remove public keyword from url using Virtual Host. You should give DocumentRoot path with public. So this will start index from public directory and remove it from url.

<VirtualHost *:80>
    ServerAdmin info@example.com
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/html/{yoursourcedirectory}/public

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

2) If you dont have root access of your hosting then you should genarate a new .htaccess file in your root directory and put the code as below

<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
    Options -MultiViews
</IfModule>

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ ^$1 [N]

RewriteCond %{REQUEST_URI} (\.\w+$) [NC]
RewriteRule ^(.*)$ public/$1 

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ server.php
</IfModule>

You can get more reference here.

Vinod Joshi
  • 176
  • 1
  • 8
-1

I found the most working solution to this problem.

Just edit your .htaccess in the root folder and write the following code. Nothing else required

RewriteEngine on
RewriteCond %{REQUEST_URI} !^public
RewriteRule ^(.*)$ public/$1 [L]

<IfModule php7_module>
   php_flag display_errors Off
   php_value max_execution_time 30
   php_value max_input_time 60
   php_value max_input_vars 1000
   php_value memory_limit -1
   php_value post_max_size 8M
   php_value session.gc_maxlifetime 1440
   php_value session.save_path "/var/cpanel/php/sessions/ea-php71"
   php_value upload_max_filesize 2M
   php_flag zlib.output_compression Off
</IfModule>
Udhav Sarvaiya
  • 9,380
  • 13
  • 53
  • 64
AKHIL RAJ
  • 39
  • 5
-1

add .htaccess file to you root folder and paste the following code and replace yourdomainname with your own domain name

RewriteEngine on RewriteCond %{HTTP_HOST} ^(www.)?yourdomainname$ RewriteCond %{REQUEST_URI} !^/public/

RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule ^(.*)$ /public/$1

RewriteCond %{HTTP_HOST} ^(www.)?yourdomainname$ RewriteRule ^(/)?$ /public/index.php [L]

Khem Raj Regmi
  • 2,130
  • 19
  • 21