Chapter 4 of 5

Serve a Laravel application with Apache on Debian 13

verified on 7 September 2026 · 4 min

Quick answer

Three conditions to serve Laravel with Apache: DocumentRoot on the public/ directory, sudo a2enmod rewrite, and AllowOverride All on that directory. Without the last directive, Apache ignores the .htaccess shipped by Laravel: the home page shows up but every other route returns 404.

Apache is still the most widespread web server on shared hosting and on servers that have been running for years. Serving a Laravel application behind Apache takes three things: a virtual host whose document root points at public/, the rewrite module enabled, and AllowOverride All so that the .htaccess file shipped by Laravel is actually read.

This chapter belongs to installing Laravel on a Debian server, part of the Web development path. Missing that third point is the near-systematic reason routes come back as 404. Steps verified on Debian 13 with Apache 2.4.68 and Laravel 13.30.1.

Install Apache and the PHP module

bash
sudo apt update
sudo apt install -y apache2 libapache2-mod-php
apache2 -v
code
Server version: Apache/2.4.68 (Debian)

The libapache2-mod-php package enables PHP inside Apache. Check it:

bash
a2query -m | grep php
code
php8.4 (enabled by maintainer script)

Then enable the rewrite module, which is not active by default:

bash
sudo a2enmod rewrite

Put the project in place

Create the application with Composer, under an unprivileged account:

bash
su - deploy
composer create-project laravel/laravel /home/deploy/app --no-interaction
cd /home/deploy/app
php artisan --version   # Laravel Framework 13.30.1

Then give write permissions to the only three folders that need them, database/ included as long as the application uses the SQLite database created at install time:

bash
sudo chown -R deploy:www-data /home/deploy/app/storage /home/deploy/app/bootstrap/cache /home/deploy/app/database
sudo chmod -R 775 /home/deploy/app/storage /home/deploy/app/bootstrap/cache /home/deploy/app/database
sudo chmod o+x /home/deploy   # Apache must be able to traverse the home directory

Create the virtual host

/etc/apache2/sites-available/laravel.conf
<VirtualHost *:80>
    ServerName exemple.com
    DocumentRoot /home/deploy/app/public

    <Directory /home/deploy/app/public>
        AllowOverride All
        Require all granted
        Options -Indexes +FollowSymLinks
    </Directory>

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

Enable the site, disable the default one, check the syntax:

bash
sudo a2ensite laravel
sudo a2dissite 000-default
sudo apache2ctl configtest
sudo systemctl reload apache2
code
Syntax OK

AllowOverride All: the line that decides everything

Laravel ships a public/.htaccess file that sends every request to index.php. Apache only reads that file if the AllowOverride directive lets it. Without that directive the home page still shows up, but no other route answers.

The behaviour was measured on the /up health route, present in every recent installation:

Configuration / /up
AllowOverride All and rewrite enabled 200 200
AllowOverride None 200 404

That is the symptom to recognise: the home page works, everything else returns 404. The problem is neither in the routes nor in the code, but in the Apache configuration.

The beginning of the .htaccess shipped by Laravel, which this whole mechanism depends on:

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

    RewriteEngine On

    # Handle X-XSRF-Token Header
    RewriteCond %{HTTP:x-xsrf-token} .
    RewriteRule .* - [E=HTTP_X_XSRF_TOKEN:%{HTTP:X-XSRF-Token}]

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

Check the installation

bash
curl -s -o /dev/null -w "accueil : %{http_code}\n" http://127.0.0.1/
curl -s -o /dev/null -w "route   : %{http_code}\n" http://127.0.0.1/up
curl -s -o /dev/null -w ".env    : %{http_code}\n" http://127.0.0.1/.env
code
accueil : 200
route   : 200
.env    : 404

The 404 on /.env is the expected result: since the site root is public/, the file sits outside the served tree and is simply not reachable. If you get a 200, then DocumentRoot points at the project root instead of public/, and your database credentials are readable by anyone.

Move to HTTPS

Certbot edits the virtual host itself and sets up automatic renewal:

bash
sudo apt install -y certbot python3-certbot-apache
sudo certbot --apache -d exemple.com

Remember to turn debug mode off and to line APP_URL up with the HTTPS address, otherwise the links and assets generated by Laravel will carry on pointing at HTTP:

.env
APP_ENV=production
APP_DEBUG=false
APP_URL=https://exemple.com
bash
php artisan config:cache
php artisan route:cache
php artisan view:cache

Apache or nginx

Apache nginx
Running PHP built-in module or PHP-FPM PHP-FPM only
Per-directory configuration yes, through .htaccess no, everything in the site configuration
Laravel rewriting shipped with Laravel to be written in the location block
Shared hosting very common rare

The .htaccess file is Apache’s decisive advantage on shared hosting: it lets you set up rewriting without access to the server configuration. On a machine you administer yourself, either one will do, and the choice comes down to what you know how to run.

Common errors

AllowOverride missing or set to None Apache ignores the Laravel .htaccess. The home page answers, every other route returns 404. Symptom measured on the /up route.
Forgetting a2enmod rewrite The rewrite module is not enabled by default on Debian. Same effect as above.
DocumentRoot on the project root The .env file becomes downloadable. It must return 404, which proves the root really is public/.
Home directory not traversable A project in /home/deploy needs chmod o+x /home/deploy, otherwise Apache returns a permission error.
APP_URL left on HTTP after Certbot The links and assets generated by Laravel carry on pointing at HTTP.
Newsletter

New tests, tutorials and projects, by e-mail.

Reproducible tests, versioned code, dated results. Never any spam.