Deploying Laravel on a VPS: A Practical Checklist
Deploying a Laravel application to a Virtual Private Server (VPS) involves more than copying files to a server. You need the correct PHP environment, a secure web server configuration, protected application credentials, a working database and reliable background processing.
Many deployment failures are predictable: the wrong PHP extension, an exposed environment file, an outdated queue worker or a migration that was never executed.
A repeatable deployment process helps prevent these problems and makes releases easier to verify and reverse when something goes wrong.
This guide provides a practical checklist for deploying Laravel on a single VPS, from initial server preparation to production verification and rollback.
1. Prepare the VPS Environment
Start by confirming that the server supports the requirements of your Laravel application.
Before installing packages, check your Laravel version's PHP requirements and the versions supported by your application's dependencies. Do not assume every Laravel project requires the same PHP version.
Your server will typically need:
A supported PHP version.
Required PHP extensions.
Composer for PHP dependency management.
Nginx or Apache.
PHP-FPM when using Nginx with PHP.
A compatible database server or access to an external database.
Git for retrieving application code.
A process manager for persistent queue workers, if the application uses queues.
A scheduler configuration for scheduled tasks, if required.
Common PHP extensions include Ctype, cURL, DOM, Fileinfo, Mbstring, OpenSSL, PDO, Tokenizer and XML. The exact requirements depend on your Laravel version, database driver and application dependencies.
Verify the PHP installation
Run:
php -v
php -m
composer --versionCheck that the command-line PHP version matches the version expected by the application.
If your server uses PHP-FPM, verify its version separately. The CLI and web-server PHP environments can differ, which may cause an application to work in the terminal but fail when accessed through a browser.
Prepare the database
Install a compatible database server or configure access to a managed database.
Before deploying, confirm:
The database exists.
The application has a dedicated database user.
The credentials are correct.
The user has only the permissions required by the application.
The database can be reached from the application server.
Backups and recovery procedures are in place.
Avoid exposing the database port publicly unless there is a specific, secured operational requirement.
2. Configure SSH and Deployment Access
Production deployment access should be limited to authorised users.
Create a dedicated deployment account where appropriate, configure SSH key authentication and avoid using the root account for routine application deployments.
Recommended practices include:
Use SSH keys rather than shared passwords.
Protect private keys with appropriate permissions and passphrases.
Limit deployment users' permissions.
Keep administrative access separate from routine deployments.
Remove access when developers or contractors no longer need it.
Apply firewall rules that expose only the services required.
Before disabling SSH password authentication, verify that key-based access works in a separate session and that you have a recovery route if configuration changes lock you out.
Important: Do not make SSH hardening changes on a remote production server without testing access and understanding your provider's recovery options.
3. Configure Nginx and PHP-FPM Correctly
One of the most important Laravel deployment rules is to expose only the application's public directory through the web server.
A typical project structure looks like this:
/var/www/myapp/
├── app/
├── bootstrap/
├── config/
├── database/
├── public/
├── resources/
├── routes/
├── storage/
├── vendor/
├── .env
└── artisanThe web server's document root should point to:
/var/www/myapp/publicIt should not point to the project root. Exposing the root can put sensitive files, application source code or configuration within reach of web requests if other safeguards fail.
Example Nginx configuration
The following is a starting example, not a complete production configuration. Replace the domain, PHP-FPM socket and filesystem paths with the values used on your server.
server {
listen 80;
server_name example.com www.example.com;
root /var/www/myapp/current/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php-fpm.sock;
}
location ~ /\.(?!well-known).* {
deny all;
}
}The PHP-FPM socket shown is illustrative. Confirm the correct socket path for your installed PHP version and distribution.
Before enabling the configuration, validate it using the appropriate Nginx test command:
sudo nginx -tThen reload Nginx if the test succeeds and your deployment procedure permits it.
For a production site, configure HTTPS using a valid certificate and verify that the HTTP-to-HTTPS redirect behaves as intended.
4. Structure Releases for Safer Deployments
A release-based deployment layout keeps the active application separate from previous releases. This makes it easier to deploy new code and switch back to an earlier release when necessary.
For example:
/var/www/myapp/
├── releases/
│ ├── 20261014-090000/
│ └── 20261014-110000/
├── shared/
│ ├── .env
│ └── storage/
└── current -> releases/20261014-110000/The current symlink points to the release currently served by the web server.
The shared directory holds configuration and persistent files that must survive a code release.
Why use this structure?
Previous releases remain available for recovery.
New code can be prepared before it becomes active.
Environment configuration does not need to be copied into every release.
Persistent uploads can be retained across deployments.
Switching the active release can be faster than restoring an entire application directory.
Make sure the storage directory is shared only where appropriate and that its permissions allow the application to operate securely.
Do not share every application directory indiscriminately. Some files, caches and generated artefacts should be managed according to Laravel's deployment requirements.
Retrieve the application code
Clone your Git repository into a new release directory and check out the intended branch or commit.
Keep production deployments reproducible by recording the commit or release identifier used.
SteboHost's Git deployment guide covers deployment workflows that can help teams organise releases. Automated push-to-deploy hooks should include validation and safeguards rather than blindly activating every incoming change.
5. Protect the Environment File and Application Secrets
Laravel's .env file commonly contains database credentials, API keys and other sensitive configuration.
It should never be committed to a public repository or exposed through the web server.
Follow these practices:
Store production secrets outside version control.
Use a separate production environment file.
Restrict file permissions to the required users.
Never paste production secrets into logs or deployment output.
Keep development and production credentials separate.
Rotate credentials if they are exposed.
Avoid copying secrets into shared release directories without access controls.
A .gitignore entry is useful, but it is not sufficient protection if a secret was already committed. Remove exposed credentials from active use and rotate them.
Configure Laravel's application key
Laravel uses an application key for cryptographic operations.
For a new installation, generate the key according to Laravel's setup instructions. For an existing production application, preserve the established key when deploying new releases.
Do not generate a fresh production key during every deployment. Changing it can invalidate encrypted data and affect sessions or other application functionality.
6. Install Production Dependencies and Optimise the Application
Once the release code is available, install the required production dependencies.
A common Composer command is:
composer install --no-dev --prefer-dist --optimize-autoloaderRun this from the release directory with the appropriate PHP and Composer versions. If your deployment process builds dependencies elsewhere, ensure the production artefacts are compatible with the target server.
Do not use composer update as a routine production deployment command. It can change dependency versions and make releases less predictable.
Clear and rebuild Laravel caches
Laravel supports configuration, route and view caching to reduce work at runtime.
A typical deployment step may include:
php artisan optimize:clear
php artisan config:cache
php artisan route:cache
php artisan view:cacheRun these commands after the intended release configuration is available.
Not every application is compatible with every cache operation. For example, route caching can fail if routes use unsupported patterns or closures. Test the commands in a staging environment or during a controlled release before relying on them in production.
Be careful with configuration caching: Laravel will use the cached configuration until it is rebuilt or cleared. Ensure the correct environment values are present before creating the cache.
7. Run Database Migrations Safely
Database migrations update the database structure as your application evolves.
In production, migrations should be an explicit part of the deployment procedure rather than an unplanned manual step.
A typical command is:
php artisan migrate --forceThe --force flag permits the migration command to run in production without the interactive confirmation that Laravel normally requires.
It does not make a migration safe by itself.
Before executing migrations:
Confirm that the target database is correct.
Review the migrations included in the release.
Take a recoverable backup where appropriate.
Consider whether the migration can run without interrupting the existing application.
Plan for failures and database restoration if required.
Record the migration outcome.
For applications that must remain available during deployments, consider backward-compatible database changes. For example, adding a nullable column before deploying code that depends on it can be safer than renaming or deleting a column immediately.
Remember: Reverting the application symlink does not reverse database migrations. Database changes need their own recovery plan.
8. Configure Queue Workers and Scheduled Tasks
Laravel applications may rely on background jobs for email, notifications, imports, payment processing and other work.
These processes must be configured independently of normal web requests.
Keep queue workers running
Laravel queue workers are long-running processes. They do not automatically restart just because new code has been deployed.
Use a process manager such as Supervisor or a suitable service manager to keep workers running and restart them when necessary.
A typical deployment sequence may include:
php artisan queue:restartThis tells Laravel queue workers to restart gracefully after finishing their current job, provided the queue workers use the expected Laravel mechanism and have access to the correct cache configuration.
Your deployment process must also ensure that workers start against the new release and that the process manager can restart them if they exit.
If you use Laravel Horizon, follow its deployment and process-management instructions instead of treating it as an ordinary queue worker.
Configure the Laravel scheduler
If your application uses Laravel's task scheduler, configure the server to run the scheduler regularly.
A common cron entry is:
* * * * * cd /var/www/myapp/current && php artisan schedule:run >> /dev/null 2>&1Adjust the application path and PHP executable as required by your environment.
Use a single appropriate scheduler entry for the application unless your architecture deliberately implements a different arrangement. If multiple servers run the same scheduled tasks, consider Laravel's supported mechanisms for preventing duplicate execution where applicable.
Test the scheduled tasks and confirm that expected jobs execute.
9. Set Up Logging, Monitoring and Backups
A deployment is not complete merely because the homepage loads. You need to know whether the application is healthy after real requests arrive.
Check the following:
Laravel application logs.
Web server error logs.
PHP-FPM logs.
Database health.
Queue worker status.
Disk space and memory usage.
Website availability and response times.
Backup completion and restoration procedures.
Laravel logs are commonly stored under the application's storage/logs directory, subject to your logging configuration.
Avoid logging passwords, access tokens, payment credentials or unnecessary personal data.
Backups should include the relevant database and persistent application data. Keep recoverable copies separate from the VPS where practical, and test restoration rather than assuming that a successful backup job guarantees recovery.
For more information, explore SteboHost's monitoring service and backup service.
10. Verify the Deployment Before Declaring Success
Use a release verification checklist after each deployment.
The intended release is active.
The web server document root points to
public.HTTPS works and the certificate is valid.
The application responds successfully.
Database connectivity works.
Required migrations completed.
Configuration and route caches were built successfully where appropriate.
File and directory permissions are correct.
Queue workers are running against the new release.
A test background job completes successfully.
Scheduled tasks are configured.
Application and server logs are being written.
A backup and recovery path is available.
Critical workflows, such as login, checkout or form submission, work correctly.
Where possible, use a dedicated health endpoint that checks only the services appropriate for that endpoint. Avoid exposing sensitive diagnostic information to unauthenticated visitors.
A successful homepage response alone does not prove that payments, queues, database operations or scheduled tasks are working.
11. Prepare a Rollback Procedure
A release-based deployment makes application rollback easier, but rollback must be planned before a failure occurs.
A basic rollback involves:
Identify the last known-good release.
Confirm that the previous release is compatible with the current database structure.
Point the
currentsymlink back to the earlier release.Reload or restart relevant processes if your configuration requires it.
Restart queue workers so they use the intended code.
Verify the application's critical workflows.
Investigate the failed release before attempting another deployment.
For example, a symlink change may look like this:
ln -sfn /var/www/myapp/releases/20261014-090000 \
/var/www/myapp/currentReplace the example path with the actual previous release.
The command should be run with the correct permissions and tested against your deployment layout. Confirm that your web server and PHP-FPM configuration resolve the symlink as expected.
Critical limitation: Rolling back code does not automatically restore database data or undo schema changes. If a migration is incompatible with the old code, a simple symlink rollback may not restore service. Plan database compatibility and recovery separately.
12. Laravel VPS Deployment Checklist
Use this compact checklist for every production release.
Server preparation
Supported PHP version and required extensions installed.
Composer and Git available.
Database connectivity tested.
SSH access secured.
Application setup
Release created from the intended commit.
Production dependencies installed.
.envand secrets protected.APP_KEYpreserved for existing applications.Document root points to
public.Permissions and persistent storage configured.
Deployment
Caches rebuilt successfully.
Migrations reviewed and executed as required.
Queue workers restarted or reloaded.
Scheduler configured.
HTTPS verified.
Post-deployment
Application and critical workflows tested.
Logs and monitoring checked.
Background job verified.
Backup and rollback options confirmed.
Frequently Asked Questions
Can I deploy Laravel on a VPS without a control panel?
Yes. Laravel can run on a VPS configured directly with Linux, PHP, a web server, a database and the required supporting services. This offers flexibility but also makes you responsible for server administration and maintenance unless those responsibilities are covered by a service agreement.
Should I use Nginx or Apache for Laravel?
Both can serve Laravel applications when configured correctly. Nginx with PHP-FPM is a common setup, while Apache is also suitable for supported configurations. Choose the server your team can configure, secure and maintain effectively.
Why must the web root point to Laravel's public directory?
The public directory contains the intended web entry point and public assets. Exposing the project root can make application files or configuration accessible if the server is misconfigured.
Do queue workers need restarting after deployment?
Usually, yes. Laravel queue workers are long-running processes and may continue using previously loaded code. Use Laravel's documented restart mechanism and ensure the process manager starts workers against the new release.
Can I roll back Laravel by changing a symlink?
You can switch the active code release by repointing the symlink, provided the release layout supports it. However, database migrations, persistent files, cached state and queued jobs require separate consideration.
Should I run php artisan migrate --force on every deployment?
Run migrations when the release requires them, as part of a controlled deployment procedure. Review changes, back up important data and consider compatibility before executing the command. The --force flag bypasses interactive production confirmation; it does not remove the need for safeguards.
How do I avoid downtime during Laravel deployments?
Use a repeatable release process, prepare the new release before activation, configure health checks and consider atomic release switching. Database compatibility, queue behaviour, web server configuration and the hosting environment all affect whether a deployment can be performed without interruption.
Conclusion
Reliable Laravel deployment comes from a repeatable process, not memory or last-minute commands.
Prepare the server, secure SSH access, expose only the public directory, protect environment secrets, install production dependencies and handle migrations deliberately. Configure queue workers and scheduled tasks, verify the complete application and prepare a rollback strategy before you need one.
If you prefer to focus on application development rather than server administration, explore SteboHost Developer Hosting and compare the available hosting plans. Confirm the exact management, patching and monitoring responsibilities included with your chosen plan before deployment.
A documented runbook makes every release more predictable and gives your team a clearer path to recovery when something goes wrong.
Frequently asked questions
- How much RAM does a small Laravel VPS need?
- A modest Laravel application with a queue worker runs comfortably on 2 GB of RAM. Below 1 GB you will fight the database and PHP-FPM for memory during deploys.
- Should I run Laravel queue workers under Supervisor?
- Yes. Queue workers must restart after deployment and restart themselves after failure. Supervisor or systemd with automatic restart is the standard approach.
Written by Denis Makokha
SteboHost engineering and operations team. We write practical guides on hosting, domains, email and security for African businesses — based on what we see in the field, not marketing copy.
Ready to get started?
Browse our hosting plans or contact our team for help choosing the right one.