How7o
  • Home
  • Tools
  • Prank Screens
  • Contact
  • Blog
Reading: Fix “403 Forbidden” on Laravel Shared Hosting
Share
Subscribe Now
How7oHow7o
Font ResizerAa
  • Marketing
  • OS
  • Features
  • Guide
  • Complaint
  • Advertise
Search
  • Home
  • Tools
  • Prank Screens
  • Contact
  • Blog
Follow US
Copyright © 2014-2023 Ruby Theme Ltd. All Rights Reserved.
How7o > Blog > Web Development > Fix “403 Forbidden” on Laravel Shared Hosting
Web Development

Fix “403 Forbidden” on Laravel Shared Hosting

how7o
By how7o
Last updated: May 10, 2026
8 Min Read
Laravel 403 forbidden on shared hosting — root htaccess rewrite into public folder
SHARE

The laravel 403 forbidden error right after uploading to shared hosting isn’t a permissions problem — it’s that Apache is serving your project root instead of the public/ folder. Laravel’s actual document root is public/, and on shared hosts the web server looks at public_html/ or www/, finds no index.html, and refuses to list the directory. The fix is either a root-level .htaccess rewrite or, if your host allows it, changing the document root to point at public/ directly.

Contents
  • TL;DR
  • Why the error happens
  • Fix 1 — Root .htaccess rewrite (quick, works on any shared host)
  • Fix 2 — Change the document root (cleaner, if your host allows)
  • After the fix — clear caches and set permissions
  • Frequently asked questions
  • Related guides
  • References

Last verified: 2026-04-23 on Laravel 11 with PHP 8.3 and Apache 2.4 on cPanel. Originally published 2022-07-06, rewritten and updated 2026-04-23.

TL;DR

Create .htaccess in the Laravel project root with the rewrite below. It forwards every request into public/, where Laravel’s own .htaccess takes over.

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_URI} !^public
    RewriteRule ^(.*)$ public/$1 [L]
</IfModule>

Why the error happens

Laravel ships with two relevant entry points:

  • artisan serve — for local dev, with PHP’s built-in server pointed at public/.
  • public/index.php — the real entry point Apache/Nginx should serve in production.

When you SFTP the whole project into public_html/, Apache treats the project root as the document root. It looks for an index.html or index.php there, finds only the artisan script and a bunch of directories, and — because shared hosts disable Options +Indexes — returns:

Forbidden
You don't have permission to access / on this server.

The permissions message is misleading — the files are readable, the server just doesn’t know which file to send.

Fix 1 — Root .htaccess rewrite (quick, works on any shared host)

Drop this file at the project root (the same folder that contains artisan, composer.json, and the public/ directory):

# .htaccess (Laravel project root)
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_URI} !^public
    RewriteRule ^(.*)$ public/$1 [L]
</IfModule>

What each line does:

  • <IfModule mod_rewrite.c> — only run the rules if Apache’s mod_rewrite is loaded. Almost always is on shared hosts, but the guard prevents a 500 if it isn’t.
  • RewriteEngine On — turn the rewriting engine on for this directory.
  • RewriteCond %{REQUEST_URI} !^public — only rewrite when the URL doesn’t already start with public. Prevents an infinite loop.
  • RewriteRule ^(.*)$ public/$1 [L] — capture whatever came in (^(.*)$) and rewrite it as public/<capture>. [L] stops further rewrites in this .htaccess.

Laravel’s stock public/.htaccess then takes the rewritten path and dispatches it to index.php. The router handles the URL from there.

laravel 403 forbidden on shared hosting — root htaccess rewrite flows requests into public

Fix 2 — Change the document root (cleaner, if your host allows)

A better long-term layout is to keep the Laravel app outside public_html/ entirely and point the hosting document root at the public/ subfolder inside it:

/home/user/
├── app/                     (Laravel project — not web-accessible)
│   ├── app/
│   ├── bootstrap/
│   ├── config/
│   ├── public/              ← document root points here
│   └── ...
└── public_html/             (empty or symlinked to ../app/public)

Most hosting panels expose this setting:

  • cPanel → Domains → Document Root → /home/user/app/public.
  • Plesk → Hosting Settings → Document Root.
  • aaPanel → Site → Site Directory (set to the public subfolder).

This keeps .env, storage/, and vendor/ outside the web-reachable tree, which is the layout Laravel is designed for.

After the fix — clear caches and set permissions

If the 403 is gone but you now see 500 errors, two usual causes:

# 1. storage/ and bootstrap/cache/ must be writable by the web user
chmod -R 775 storage bootstrap/cache

# 2. Rebuild the config/route caches after moving files
php artisan config:clear
php artisan route:clear
php artisan view:clear

Run those from SSH on the host. If SSH isn’t available, chmod via the file manager’s permissions dialog and delete bootstrap/cache/config.php manually.

Frequently asked questions

Why do I get laravel 403 forbidden after uploading to shared hosting?

Because Laravel’s actual document root is the public/ folder, but most shared-hosting accounts serve from /home/user/public_html/ or www/. Apache looks in your project root for an index.html or index.php, doesn’t find one (you didn’t upload those, you uploaded a Laravel app), and returns 403 because directory listings are disabled. The fix is an .htaccess file that rewrites all requests into public/ — or, better, pointing the host’s document root directly at the public/ folder.

What’s the cleanest fix — .htaccess rewrite or document-root change?

Changing the document root to /home/user/project/public in the hosting control panel (cPanel → Domains → Document Root, Plesk → Hosting Settings, etc.). That’s what Laravel expects and what the framework’s docs recommend. The .htaccess rewrite is a workaround for hosts that won’t let you change the document root — it works, but every request pays a rewrite cost and you have two .htaccess files (root and public/) to keep in sync.

Is it safe to put my whole Laravel app inside public_html?

Not ideally. When the app lives inside public_html, Apache can serve any file in the project tree — .env, storage/logs/, vendor/ — as long as someone guesses the URL. The .htaccess rewrite does block direct hits to the project root, but it’s safer to keep the Laravel app outside the web root and point the document root at only the public/ subfolder. On hosts where that’s impossible, at minimum make sure .env is protected (most default Apache configs already block hidden files).

Why does RewriteCond %{REQUEST_URI} !^public need that exact form?

The condition says “only apply this rewrite when the request URI does NOT start with public.” Without it, the rewrite would re-fire on the already-rewritten request (/foo → public/foo → public/public/foo → …) and either loop or 500 out. The leading ! is the negation; ^public is a regex for “starts with public”.

Will this break the Laravel public/.htaccess that’s already there?

No — the two files work in sequence. Your new root-level .htaccess rewrites the request URL into public/. Laravel’s stock public/.htaccess then handles the further rewrite into index.php?... so the router can match it. Keep both files; they do different jobs.

Related guides

  • How to Exclude .well-known from Redirection for Let’s Encrypt with .htaccess in Laravel — the companion rule that lets ACME challenges reach /.well-known/.
  • How to Install Laravel on Ubuntu — a fresh Laravel 11 install with the correct folder layout.
  • How to Run a Laravel Project from GitHub — the clone + deploy flow that lands you on shared hosting.
  • How to Fix cURL Error 60 SSL Certificate Problem in Laravel — another post-deploy-to-shared-hosting problem worth knowing.

References

Apache mod_rewrite docs: httpd.apache.org/docs/current/mod/mod_rewrite. Laravel deployment: laravel.com/docs/deployment.

TAGGED:ApachecPanelLaravelphptroubleshooting

Sign Up For Daily Newsletter

Be keep up! Get the latest breaking news delivered straight to your inbox.
By signing up, you agree to our Terms of Use and acknowledge the data practices in our Privacy Policy. You may unsubscribe at any time.
Share This Article
Facebook Copy Link Print
Previous Article Laravel global variable for views — View::share in AppServiceProvider and View::composer wildcard patterns How to Set a Global Variable for Laravel Views
Next Article Laravel cURL error 60 SSL certificate problem — CA bundle wiring in php.ini How to Fix cURL Error 60 SSL Certificate Problem in Laravel
Leave a Comment

Leave a Reply Cancel reply

You must be logged in to post a comment.

FacebookLike
XFollow
PinterestPin
InstagramFollow

Subscribe Now

Subscribe to our newsletter to get our newest articles instantly!
Most Popular
Display PHP errors — ini_set + php.ini configuration
How to Display PHP Errors
May 10, 2026
PHP convert string to uppercase — strtoupper and mb_strtoupper
How to Convert a String to Uppercase in PHP
May 10, 2026
PHP string to float conversion with cast, regex cleanup, NumberFormatter
How to Convert a String to Float in PHP
May 10, 2026
PHP merge arrays without duplicates — union operator and array_unique
How to Combine Two Arrays Without Duplicates in PHP
May 10, 2026
PHP delete array element — unset, array_splice, array_filter, array_search
How to Delete an Element from a PHP Array
May 10, 2026

You Might Also Like

MySQL combine columns into string — CONCAT and CONCAT_WS
Web Development

How to Combine Multiple Columns into One String in MySQL

6 Min Read
Return or throw an error in Laravel (JSON response vs exception)
Web Development

How to Manually Return or Throw an Error Exception in Laravel

6 Min Read
Laravel call controller from another controller — app() and constructor injection patterns
Web Development

How to Call a Controller Method from Another Controller in Laravel

8 Min Read
Laravel Carbon not found error — namespace import fix
Web Development

Fix “Class Carbon not found” in Laravel

6 Min Read
How7o

We provide tips, tricks, and advice for improving websites and doing better search.

Latest News

  • SEO Audit Tool
  • Client ReferralsNew
  • Execution of SEO
  • Reporting Tool

Resouce

  • Google Search Console
  • Google Keyword Planner
  • Google OptimiseHot
  • SEO Spider

Get the Top 10 in Search!

Looking for a trustworthy service to optimize the company website?
Request a Quote
Welcome Back!

Sign in to your account

Username or Email Address
Password

Lost your password?