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.
- Move the
.htaccess
file in public/.htaccess
in the main root
- 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]