Search code examples
laravel.htaccessurl-rewritinglaravel-8http-redirect

how to remove 'public' in url when redirecting http:// to https:// in laravel using htaccess?


when I open website using https://example.com it will open without public in the URL, but when I try to open http://example.com it will redirect to https://example.com/public, with public in the URL.

I want to redirect http:// to https:// but without public in the URL.

Folder Structure:

Folder structure

.htaccess file code which is in root directory

#disable directory browsing
Options -Indexes
<IfModule mod_rewrite.c>
   RewriteEngine On 
   RewriteRule ^(.*)$ public/$1 [L]
</IfModule>

#PROTECT ENV FILE
<Files .env>
order allow,deny
Deny from all
</Files>

#PROTECT ENV FILE
<Files .htaccess>
order allow,deny
Deny from all
</Files>

# BEGIN cPanel-generated php ini directives, do not edit
# Manual editing of this file may result in unexpected behavior.
# To make changes to this file, use the cPanel MultiPHP INI Editor (Home >> Software >> MultiPHP INI Editor)
# For more information, read our documentation (https://go.cpanel.net/EA4ModifyINI)
<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-php74"
   php_value upload_max_filesize 2M
   php_flag zlib.output_compression Off
</IfModule>
<IfModule lsapi_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-php74"
   php_value upload_max_filesize 2M
   php_flag zlib.output_compression Off
</IfModule>
# END cPanel-generated php ini directives, do not edit

# php -- BEGIN cPanel-generated handler, do not edit
# Set the “ea-php74” package as the default “PHP” programming language.
<IfModule mime_module>
  AddHandler application/x-httpd-ea-php74 .php .php7 .phtml
</IfModule>
# php -- END cPanel-generated handler, do not edit

.htaccess file code which is in public directory

<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]

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



Solution

  • There is no HTTP to HTTPS redirect in the code you posted. If this is being performed earlier in the server config then it will need to be corrected in the server config. However, if it is being performed (incorrectly) later in your application then you can correct this by redirecting early in .htaccess. This will need to go at the top of your /public/.htaccess file:

    RewriteCond %{HTTPS} !on
    RewriteRule (.*) https://example.com/$1 [R=301,L]
    

    (This does assume the SSL cert is installed directly on your application server and you are not using a proxy to manage your SSL connection. If so, then the condition will need to be adjusted.)

    Since this is in the /public/.htaccess file, the captured backreference $1 will naturally exclude the /public/ subdirectory, so this is excluded from the redirect.

    You should test first with a 302 (temporary) redirect to avoid potential caching issues. And make sure you've cleared your browser cache before testing.

    However, the following rule is problematic and will also expose the /public subdirectory should you request a URL with a trailing slash:

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

    This rule would be OK if it was in the root .htaccess file, however, with it being in the /public/.htaccess file (which it needs to be) then the REQUEST_URI server variable contains the /public/ directory (after the request is internally rewritten). And you are capturing the URL-path from the variable.

    This rule should be written like this instead:

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

    This is also marginally more efficient and works regardless of which .htaccess file it is placed in (although it should be in the /public/.htaccess file, not the root .htaccess). Aside: If the /public subdirectory was not hidden from the URL then this would not work, but that is not the case here.