Deploying a Laravel application on an Apache server can be tricky if you’re not familiar with proper configuration. A common mistake developers make is moving all files from the public/ directory into the web root. While this may make the app work temporarily, it’s insecure and against Laravel’s architecture.
In this post, we’ll walk through the secure and proper way to deploy your Laravel app on Apache without compromising the structure or security of your application.
✅ Prerequisites
- Apache installed (sudo apt install apache2)
- PHP 8.x, Composer, and Laravel installed
- Your Laravel app codebase (either cloned from Git or uploaded)
- A domain name or server IP
📁 Recommended Laravel Folder Structure
Keep your Laravel app as-is, typically like this:
/var/www/laravel-app/
├── app/
├── bootstrap/
├── config/
├── database/
├── public/ ← Only this folder should be accessible via the web
├── resources/
├── routes/
├── storage/
└── vendor/
🛠️ Step 1: Configure Apache Virtual Host
Create a new Apache config file:
sudo nano /etc/apache2/sites-available/laravel-app.conf
Assuming you’ve already installed your SSL certificate (e.g. via Let’s Encrypt using certbot), here’s how your Apache config should look:
<VirtualHost *:80>
ServerName your-domain.com
Redirect permanent / https://your-domain.com/
</VirtualHost>
<VirtualHost *:443>
ServerName your-domain.com
DocumentRoot /var/www/laravel-app/public
<Directory /var/www/laravel-app/public>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/your-domain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/your-domain.com/privkey.pem
ErrorLog ${APACHE_LOG_DIR}/laravel-ssl-error.log
CustomLog ${APACHE_LOG_DIR}/laravel-ssl-access.log combined
</VirtualHost>
🔁 Replace your-domain.com with your actual domain name.
📁 The SSL paths are for Let’s Encrypt (Certbot). If you’re using a different certificate provider (such as GoDaddy or DigiCert), update the file paths accordingly.
🔁 Step 2: Enable Site and Rewrite Module
Run the following commands:
sudo a2ensite laravel-app.conf
sudo a2enmod rewrite
sudo systemctl restart apache2
🔐 Step 3: Set Proper Permissions
Laravel needs write access to some directories. Set them like this:
sudo chown -R www-data:www-data /var/www/laravel-app
sudo chmod -R 775 /var/www/laravel-app/storage
sudo chmod -R 775 /var/www/laravel-app/bootstrap/cache
📜 Step 4: Ensure .htaccess Exists in /public
Laravel includes this file by default in the public/ folder. Make sure it looks like this:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [L]
</IfModule>
This enables clean URLs (/dashboard instead of /index.php?route=dashboard).
🌐 Step 5: Access Your Application
- Navigate to
http://your-domain.com/orhttp://your-server-ip/ - You should see your Laravel home page
- Routes and views should now work as expected
💡 Tips for SSL Deployment
If you’re using Let’s Encrypt, install Certbot:
sudo apt install certbot python3-certbot-apache
sudo certbot --apache
Certbot will automatically configure SSL with renewal.
You can test the renewal with:
sudo certbot renew --dry-run
🧪 Bonus: Useful Laravel Deployment Commands
Run these once you’re live:
# Cache routes and configs
php artisan config:cache
php artisan route:cache
php artisan view:cache
# Set correct file permissions again if needed
sudo chown -R www-data:www-data .
🚫 Common Mistake: Moving public/ Contents to Web Root
Some developers do this:
# ❌ Don’t do this!
cp -r public/* /var/www/html/
Why it’s bad:
- Exposes core folders like
/vendor,/routes,/app - Breaks Laravel’s internal path references
- Reduces portability and maintainability
Always point Apache to the /public directory instead.