Point Apache at Laravel’s public/ directory, enable URL rewriting, grant the PHP process write access to storage/ and bootstrap/cache/, then verify DNS and HTTPS in that order. Never use the Laravel project root as Apache’s document root: it contains .env, Composer files, and application code that should not be downloadable.
Antihost offers Linux VPS plans with full root access, unlimited traffic on a 1 Gbps port and a 14-day free trial.
The procedure below targets a self-managed Ubuntu VPS running Apache. Laravel 13 requires PHP 8.3 or newer and the extensions listed in the compatibility table; an existing application’s composer.json and composer.lock remain the final authority if it uses an older Laravel major.
As an Amazon Associate I earn from qualifying purchases.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11What the finished setup should look like
A browser request should pass through these layers:
- DNS resolves the requested hostname to the VPS.
- Apache selects the virtual host whose
ServerNameorServerAliasmatches that hostname. - The virtual host maps the site to
/var/www/example.com/public, not/var/www/example.com. - Apache serves existing assets such as CSS, JavaScript, and images directly.
- Laravel’s shipped
public/.htaccesssends other paths topublic/index.php. - PHP loads the framework, reads the environment and configuration, and returns the response.
The project root remains outside the web-exposed directory. Files such as .env, composer.json, composer.lock, source code, and cached secrets are therefore not addressable as public URLs.
#1 Best Overall
Check PHP, extensions, and server prerequisites
Laravel 13’s current deployment documentation lists PHP 8.3 or newer and these extensions:
| Requirement | Why it matters |
|---|---|
| PHP >= 8.3 | Laravel 13’s supported PHP baseline. |
| Ctype | Character-type checks used by framework and application code. |
| cURL | Outbound HTTP and API requests. |
| DOM | XML and HTML document handling. |
| Fileinfo | MIME-type detection for uploaded and generated files. |
| Filter | Input filtering functions. |
| Hash | Password and data hashing. |
| Mbstring | Multibyte string operations. |
| OpenSSL | Encryption and secure transport support. |
| PCRE | Regular-expression processing. |
| PDO | Database abstraction and drivers. |
| Session | PHP session support where the application uses it. |
| Tokenizer | PHP source-token processing. |
| XML | XML parsing and related framework features. |
Install the PHP version and database driver required by the project rather than blindly installing a newer runtime. A Laravel application on an older major can have a lower PHP baseline. Check the lock file and package constraints before changing production PHP.
Verify the runtime before deployment
php -v
php -m
composer --version
apache2ctl -v
Compare the output of php -m with the project’s requirements. A command-line PHP binary and Apache’s PHP handler can load different configuration files, so also create a temporary, protected diagnostic endpoint or inspect the active handler configuration when a module appears present in the shell but missing from web requests. Remove any diagnostic endpoint immediately after testing.
Prepare the application directory and release user
Use a path such as /var/www/example.com for the complete release. Deploy through a non-root administrative account and reserve root for package installation, service management, and protected configuration changes.
Install the release
Place the repository checkout or release archive in the application directory. Keep .env server-side and do not commit it. If you deploy from a repository, make the release user the owner of the checkout and use a repeatable release process rather than editing files in production.
sudo mkdir -p /var/www/example.com
sudo chown -R deploy:deploy /var/www/example.com
cd /var/www/example.com
composer install --no-dev --prefer-dist --optimize-autoloader
The Composer command installs the versions recorded in composer.lock, omits development packages, and builds an optimized autoloader. Run the project’s documented frontend production build as part of the release if it has JavaScript or CSS assets. Do not assume a Node.js version; read the project’s package files and build documentation.
Keep releases separate when you need rollbacks
For a larger application, keep immutable release directories and point a stable path, such as current, at the active release. Ensure the Apache virtual host ultimately resolves to that release’s public/ directory. Shared .env, user uploads, and cache directories must be managed deliberately when switching releases; a symlink alone does not solve ownership or persistence.
Rank #2
Create a safe production environment
Laravel expects .env at the application root. Create it from the project’s example file or from a secret-management process, then set values for the production environment, canonical URL, application key, database, cache, session and queue drivers, mail transport, and application-specific credentials.
cd /var/www/example.com
cp .env.example .env
chmod 640 .env
Set APP_DEBUG=false in production. Debug output can disclose stack traces, paths, SQL details, and configuration data. Generate an application key only for a new installation:
php artisan key:generate
Do not rotate an existing key casually. Previously encrypted values, cookies, and other ciphertext may become unreadable after a key change. Plan a key rotation as a migration with backups and application-specific re-encryption steps.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteKeep secrets out of the Apache virtual-host file whenever possible. Apache configuration is read by administrators and may be copied into diagnostics or backups. Environment variables supplied by the process manager or a protected deployment mechanism can override values, but document which source is authoritative.
Configure Apache to expose only Laravel’s public directory
Apache’s DocumentRoot is the directory used to map URL paths to files. For Laravel, it must end in /public.
Create the HTTP virtual host
Save the following as /etc/apache2/sites-available/example.com.conf, replacing the hostname and path with your values:
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com/public
<Directory /var/www/example.com/public>
AllowOverride All
Require all granted
Options FollowSymLinks
</Directory>
ErrorLog ${APACHE_LOG_DIR}/example-error.log
CustomLog ${APACHE_LOG_DIR}/example-access.log combined
</VirtualHost>
ServerName should be the canonical hostname. Include ServerAlias only for names that should serve the same application, such as www. DNS records for every listed name must point to this VPS; an alias in Apache does not create DNS.
Enable the site and rewrite support
sudo a2enmod rewrite
sudo a2ensite example.com.conf
sudo a2dissite 000-default.conf
sudo apachectl configtest
sudo systemctl reload apache2
Only disable the default site if it would otherwise answer requests intended for your application. apachectl configtest must report a successful syntax check before you reload. On a new server, inspect the parsed virtual hosts with:
sudo apachectl -S
The public/.htaccess file supplied by Laravel contains the front-controller rewrite rules. AllowOverride All permits those directives. A hardened configuration can replace it with a narrower AllowOverride policy after you have identified the exact override classes needed by the shipped rules, but disabling overrides entirely will commonly produce 404 responses for routes that are not physical files.
Check parent-directory traversal
Apache needs execute permission on every parent directory in the path, not just on public/. A restrictive home-directory mode or a parent owned by another account can cause a 403 even when the virtual host looks correct. Check each component from /var through the release directory and grant only the traversal access required by the web process.
Set ownership and write permissions safely
Laravel must be able to write to storage/ and bootstrap/cache/. The web process account is commonly www-data on Ubuntu, but confirm the account used by the installed Apache/PHP handler before changing ownership.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →A group-based permission pattern
Keep deployment ownership with the release user, share a group with the web process, and grant group write access only to Laravel’s required directories:
sudo usermod -aG www-data deploy
sudo chgrp -R www-data /var/www/example.com/storage /var/www/example.com/bootstrap/cache
sudo chmod -R ug+rwX,o-rwx /var/www/example.com/storage /var/www/example.com/bootstrap/cache
The deploying user may need to start a new login session before the supplementary group is active. If your release process replaces directories, reapply group ownership and modes as part of deployment or use a filesystem default ACL designed by your administrator.
Do not run chmod -R 777. It makes every local account able to modify application data and often masks the real owner, group, or handler mismatch. Keep source files, Composer metadata, and .env more restrictive than runtime directories.
Rank #4
Publish user-uploaded files
If the application uses Laravel’s public filesystem disk, create the documented link from public/storage to the storage location:
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →cd /var/www/example.com
php artisan storage:link
The link exposes only files intended for the public disk. Private uploads should remain outside the public path and be delivered through an authorization-controlled application response or a separate private-storage mechanism.
Run deployment commands in the right order
Once the environment, dependencies, Apache mapping, and permissions are correct, execute the release tasks required by the application.
- Run database migrations only when the project’s release policy permits them. Take a backup and understand whether migrations are backward-compatible with the currently running code.
- Build frontend assets using the project’s documented production command.
- Cache Laravel configuration and framework metadata where appropriate.
- Restart long-running workers and reload other processes that retain old code or configuration.
php artisan config:cache
php artisan event:cache
php artisan route:cache
php artisan view:cache
These commands create production caches. Validate that the application boots successfully before enabling them on a new deployment.
Understand the env() limitation
After php artisan config:cache, Laravel does not load the .env file directly during ordinary runtime calls. Use env() inside configuration files, then read the resulting configuration with config() from application code. If code calls env() directly in controllers, jobs, or services, it can appear to ignore a changed value after configuration is cached.
When an environment value looks stale, clear and rebuild the cache through the deployment process rather than deleting arbitrary files while requests are running. Coordinate this with queue workers, schedulers, WebSocket processes, or other services that may have loaded the old configuration into memory.
Add HTTPS only after HTTP and DNS work
TLS troubleshooting is meaningful only after the hostname resolves publicly and the HTTP virtual host serves the intended application. Confirm http://example.com first, then obtain a certificate with an ACME client such as Certbot.
Best Value
Use a dedicated port-80 redirect host
After certificate issuance, a simple redirect virtual host can be used for the canonical name:
Recommended Free Tools
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
Redirect permanent / https://example.com/
</VirtualHost>
ACME HTTP-01 validation still needs access to /.well-known/acme-challenge/. Configure the chosen ACME client and its validation method so the challenge is reachable; do not add an unconditional rule that blocks it.
Let the certificate tool manage certificate paths
Use the certificate paths and renewal hooks generated for this server. Do not copy hard-coded paths from another machine, because file locations, permissions, and renewal integration vary. After the tool updates Apache:
sudo apachectl configtest
sudo systemctl reload apache2
Test both the bare domain and any www alias, confirm that the certificate names match the requested host, and verify that application-generated links use the intended HTTPS canonical URL.
Verify the deployment before calling it finished
- DNS A and, where applicable, AAAA records point to the VPS.
apachectl -Sshows the expected enabled virtual host and hostname.- The virtual host’s
DocumentRootends in/public. mod_rewriteis enabled andpublic/.htaccessis present.- The home page returns the application, not Ubuntu’s default page.
- A non-root Laravel route works after a direct refresh, not only after navigating from the home page.
- Static assets return the expected content type and status.
- Apache’s error and access logs show the request reaching the intended vhost.
- The PHP handler reports the required version and extensions.
storage/andbootstrap/cache/are writable by the active PHP process.APP_DEBUG=falseis active and sensitive files cannot be downloaded.- HTTPS presents a valid certificate, redirects HTTP as intended, and leaves the ACME challenge reachable during renewal.
Troubleshoot common failures by symptom
| Symptom | Likely cause | Checks and fix |
|---|---|---|
| Apache shows its default page | DNS, hostname matching, or site enablement is wrong. | Check DNS, ServerName, enabled sites, and sudo apachectl -S. Disable the default site only when it is taking precedence. |
Only / works; other Laravel routes return 404 |
Apache is not using Laravel’s front controller. | Confirm DocumentRoot ends in /public, enable rewrite, ensure public/.htaccess exists, and permit overrides in the matching <Directory> block. |
| 403 Forbidden | Apache cannot traverse a parent directory or authorization rules deny access. | Inspect execute permission on every parent, Require all granted, and the Apache error log. Avoid making the whole tree world-writable. |
| 500 error or “failed to open stream” | PHP startup failure, missing extension, or unwritable runtime directory. | Read the Apache error log, compare web PHP modules with the project requirements, and test write access to storage and bootstrap/cache. |
| Environment changes do not appear | Configuration cache or a long-running worker still contains old values. | Rebuild Laravel’s configuration cache through deployment and restart workers or other persistent processes. Keep runtime env() calls out of application code. |
| Uploaded images or files return 404 | The public storage link is missing or points to an incorrect release. | Run php artisan storage:link, inspect the link target, and verify that the public disk and directory permissions are correct. |
| Certificate issuance fails | DNS, port 80, vhost selection, or challenge access is incorrect. | Resolve the hostname publicly, confirm port 80 reaches this VPS and the intended vhost, and allow /.well-known/acme-challenge/ through any redirect or access rule. |
Production security and operational details
Protect files by architecture, not by hope
Using public/ as the document root is the primary boundary. Do not rely on Apache rules to hide a project root that is already exposed. Keep backups, deployment archives, database dumps, private uploads, and secret files outside the public directory.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Separate deployment and runtime responsibilities
The deploy user should own releases and run Composer and Artisan commands. The PHP process should have write access only where Laravel needs runtime writes. This separation makes an accidental request-time file modification less damaging and makes permission errors easier to diagnose.
Plan worker restarts
Queue workers, schedulers, WebSocket servers, and application servers can retain old classes or configuration after a release. Use the project’s supervisor and restart procedure after deploying code or changing cached configuration. A successful Apache reload alone does not refresh those processes.
Use logs as the first diagnostic source
Keep separate access and error logs for the virtual host. A 404 in Laravel’s response is different from an Apache 404, and the logs reveal which layer generated it. Avoid placing credentials or full request bodies into verbose production logging.
Choose an operating model deliberately
A self-managed Apache VPS is not the only way to run Laravel. The practical distinction is how much infrastructure work remains yours.
Free tools Windows power users keep installed
One-click scans. No signup required.
| Concern | Self-managed Apache VPS | Managed Laravel infrastructure |
|---|---|---|
| OS and Apache configuration | You control packages, virtual hosts, PHP handlers, firewall, and upgrades. | The provider supplies supported defaults and limits low-level control. |
| Scaling | You design vertical or horizontal scaling and configure load balancing. | Managed services may automate capacity changes, subject to their supported architecture. |
| Queues and processes | You install and supervise workers, schedulers, and reloads. | Process management may be integrated, but supported worker types and limits vary. |
| Backups | You choose schedules, retention, off-site copies, and restore tests. | Backups may be offered as a service; confirm retention, scope, and restore responsibility. |
| Observability | You configure logs, metrics, alerts, and retention. | Dashboards and alerts may be included, with provider-specific visibility. |
| Cost model | You pay for the VPS and operate it directly. | You pay for managed convenience and any usage-based infrastructure. |
Choose the VPS path when you need OS-level control and can own patching, monitoring, backups, certificate renewal, and incident response. A managed option can reduce routine server work, but it does not remove the need to understand application configuration, migrations, queues, secrets, or recovery.
Quick Recap
A repeatable deployment checklist
- Confirm the project’s Laravel and PHP constraints from
composer.jsonandcomposer.lock. - Provision Apache, the correct PHP handler and extensions, Composer, and the required database connectivity.
- Deploy the release under a non-root account at a path such as
/var/www/example.com. - Create a protected
.env; set production values and disable debug output. - Install locked dependencies with
composer install --no-dev --prefer-dist --optimize-autoloader. - Build frontend assets using the application’s documented production toolchain.
- Set Apache’s
DocumentRootto/var/www/example.com/public. - Enable
mod_rewrite, permit the shipped rewrite rules, and reload only afterapachectl configtestsucceeds. - Grant the PHP process write access to
storage/andbootstrap/cache/, not the entire tree. - Run required migrations, create the storage link when needed, and build Laravel caches deliberately.
- Test DNS, the selected vhost, clean route refreshes, assets, logs, and sensitive-file protection.
- Issue the certificate, configure HTTPS and renewal, then test the redirect and ACME challenge path.
- Restart persistent workers and record the release, migration, cache, and rollback steps.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




