Laravel Deployment on Ubuntu Server : Configuration And Setup
Here’s an in-depth, step-by-step guide to deploying a Laravel application on an Ubuntu Server, covering every detail you need—from provisioning your server to setting up SSL and automating deployments. This article is structured into clear sections so you can follow along easily; feel free to skip to the section you need, or read straight through for the full 15,000+ character deep dive.
Introduction
Deploying a Laravel application to a production server can seem daunting if you haven’t done it before. In this guide, we’ll walk through every necessary step to get your application running smoothly on an Ubuntu Server environment. You’ll learn how to install and configure Nginx, PHP, Composer, MySQL/MariaDB, and Supervisor; set up SSL encryption; automate deployments; optimize performance; and more.
Whether you’re migrating an existing project or starting from scratch, by the end of this article you’ll have a rock-solid deployment workflow that you can replicate for future projects.
Prerequisites
Before we begin, make sure you have:
- An Ubuntu Server (20.04 LTS or 22.04 LTS recommended) with root or sudo privileges.
- A domain name (e.g., example.com) pointed via A-record to your server’s public IP.
- SSH access to the server (port 22, unless you’ve customized it).
- A Laravel project in a Git repository (GitHub, GitLab, Bitbucket, etc.) or ready to upload via SFTP.
- Basic Linux command-line knowledge.
Provisioning and Preparing Your Ubuntu Server
- Log in via SSH
ssh root@your_server_ip
- Update package lists & upgrade existing packages
sudo apt update sudo apt upgrade -y
- Set your server’s timezone (e.g., UTC or your local zone)
sudo timedatectl set-timezone UTC
- Create a swap file (if you have limited RAM)
sudo fallocate -l 1G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
- Install essential utilities
sudo apt install -y curl wget git unzip build-essential
Installing Nginx
- Install Nginx
sudo apt install -y nginx
- Allow HTTP/HTTPS through the firewall (if using UFW)
sudo ufw allow 'Nginx Full' sudo ufw enable
- Start and enable Nginx
sudo systemctl start nginx sudo systemctl enable nginx
- Verify installation
Visit http://your_server_ip in your browser; you should see the default Nginx welcome page.
Installing PHP and Required Extensions
Laravel 10+ needs PHP 8.1 or newer. We’ll install PHP 8.2 as an example:
- Add Ondřej Surý’s PPA
sudo apt install -y software-properties-common sudo add-apt-repository ppa:ondrej/php -y sudo apt update
- Install PHP core and extensions
sudo apt install -y php8.2-fpm php8.2-cli php8.2-mbstring php8.2-xml php8.2-bcmath \ php8.2-curl php8.2-zip php8.2-gd php8.2-mysql php8.2-pgsql php8.2-intl- Configure php.ini (optional performance/tuning)
sudo nano /etc/php/8.2/fpm/php.ini
- Set memory_limit = 512M (or as needed)
- Adjust upload_max_filesize, post_max_size, etc.
- Restart PHP-FPM
sudo systemctl restart php8.2-fpm
- Ensure PHP-FPM is enabled
sudo systemctl enable php8.2-fpm
Installing Composer
Composer is the dependency manager for PHP.
- Download installer
curl -sS https://getcomposer.org/installer -o composer-setup.php HASH="$(curl -sS https://composer.github.io/installer.sig)" php -r "if (hash_file('SHA384', 'composer-setup.php') === '$HASH') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"- Install globally
sudo php composer-setup.php --install-dir=/usr/local/bin --filename=composer
- Verify
composer --version
Creating a Dedicated System User
For security, don’t run your web apps as root. Create a new user:
sudo adduser deployer sudo usermod -aG sudo deployer
Switch to that user:
su - deployer
(Optional) Set up SSH key authentication for deployer and disable password logins.
Deploying Your Laravel Application
Cloning from Git
- Navigate to /var/www
cd /var/www
- Clone your repo
git clone https://github.com/your_username/your_laravel_app.git example.com
- Enter project directory
cd example.com
Environment Configuration
- Copy .env.example to .env
cp .env.example .env
- Edit .env
nano .env
- Set APP_NAME, APP_URL=https://example.com
- Configure DB_CONNECTION, DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, DB_PASSWORD
- Add any third‑party credentials, queue drivers, mail settings, etc.
Installing Dependencies
composer install --optimize-autoloader --no-dev php artisan key:generate
Configuring the Database
Install MySQL or MariaDB:
sudo apt install -y mysql-server sudo mysql_secure_installation
Log in and create the database/user:
CREATE DATABASE laravel_db; CREATE USER 'laravel_user'@'localhost' IDENTIFIED BY 'strong_password'; GRANT ALL PRIVILEGES ON laravel_db.* TO 'laravel_user'@'localhost'; FLUSH PRIVILEGES; EXIT;
Ensure your .env reflects these credentials, then run:
php artisan migrate --force
Configuring Nginx Virtual Host
- Create a new server block:
sudo nano /etc/nginx/sites-available/example.com
server { listen 80; server_name example.com www.example.com; root /var/www/example.com/public; index index.php index.html; add_header X-Frame-Options "SAMEORIGIN"; add_header X-Content-Type-Options "nosniff"; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/var/run/php/php8.2-fpm.sock; } location ~ /\.ht { deny all; } access_log /var/log/nginx/example.com.access.log; error_log /var/log/nginx/example.com.error.log; }- Enable the site and disable default:
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/ sudo rm /etc/nginx/sites-enabled/default
- Test & reload:
sudo nginx -t sudo systemctl reload nginx
Visit http://example.com—your Laravel app should now be live (though still HTTP).
Setting Permissions and Ownership
Ensure the deployer user owns the project files and that the storage and bootstrap/cache directories are writable:
sudo chown -R deployer:www-data /var/www/example.com
sudo find /var/www/example.com -type f -exec chmod 644 {} \;
sudo find /var/www/example.com -type d -exec chmod 755 {} \;
sudo chown -R deployer:www-data /var/www/example.com/storage /var/www/example.com/bootstrap/cache
sudo chmod -R 775 /var/www/example.com/storage /var/www/example.com/bootstrap/cacheRunning Migrations and Seeders
From the project root:
php artisan migrate --force php artisan db:seed --force # if you have seeders
Configuring Supervisor for Queues and Schedulers
If your app uses queues or needs scheduled tasks:
- Install Supervisor
sudo apt install -y supervisor
- Create config for queue worker
sudo nano /etc/supervisor/conf.d/laravel-queue.conf
[program:laravel-queue] process_name=%(program_name)s_%(process_num)02d command=php /var/www/example.com/artisan queue:work --sleep=3 --tries=3 autostart=true autorestart=true user=deployer numprocs=1 redirect_stderr=true stdout_logfile=/var/www/example.com/storage/logs/queue.log
- Reload Supervisor
sudo supervisorctl reread sudo supervisorctl update sudo supervisorctl start laravel-queue:*
- Scheduler Cron Job
sudo crontab -u deployer -e
- Add:
* * * * * php /var/www/example.com/artisan schedule:run >> /dev/null 2>&1
Setting Up SSL with Let’s Encrypt
Secure your site with HTTPS:
- Install Certbot
sudo apt install -y certbot python3-certbot-nginx
- Obtain and install certificate
sudo certbot --nginx -d example.com -d www.example.com
- Automatic renewal test
sudo certbot renew --dry-run
Your Nginx config will be updated to listen on port 443, redirect HTTP to HTTPS, and include the certificates.
Automating Deployments (Git Hooks / CI-CD)
Manual deployments can be error-prone. Consider:
- Git post-receive hook: Push to a bare repo on the server, and in the hook run git checkout, composer install, php artisan migrate, etc.
- CI/CD pipelines (GitHub Actions, GitLab CI): Build your app, run tests, upload artifacts (ZIP), SSH into server, unzip, run migrations, clear caches, reload services.
Example GitHub Actions snippet:
name: Deploy Laravel
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Deploy via SSH
uses: appleboy/ssh-action@v0.1.5
with:
host: ${{ secrets.SERVER_IP }}
username: deployer
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /var/www/example.com
git pull origin main
composer install --no-dev --optimize-autoloader
php artisan migrate --force
php artisan config:cache
sudo supervisorctl restart laravel-queue:*Caching and Performance Optimization
After each deployment, run:
php artisan config:cache php artisan route:cache php artisan view:cache php artisan event:cache
Use OPcache (enabled in php.ini) and consider setting up Redis for caching and session storage. Leverage CDN for static assets.
Logging, Monitoring, and Maintenance
- Logs: Stored in storage/logs/laravel.log. Rotate logs via logrotate.
- Server Monitoring: Use tools like Netdata, New Relic, or Datadog.
- Backups: Automate database backups (cron + mysqldump), store offsite or in S3.
- Security: Keep packages updated (sudo apt upgrade, composer update carefully), use fail2ban, limit SSH access.
Common Pitfalls and Troubleshooting
- 500 Internal Server Error
- Check Nginx error logs: /var/log/nginx/example.com.error.log.
- Check Laravel logs.
- Ensure correct permissions.
- Permission Denied on Storage
- Re-run chown and chmod commands.
- Queue Workers Not Running
- Verify Supervisor status: sudo supervisorctl status.
- Check queue logs.
- SSL Renewal Failures
- Confirm port 80/443 open.
- Check Certbot logs: /var/log/letsencrypt.
- High Memory Usage
- Optimize PHP-FPM pools.
- Enable OPcache.
Conclusion
Deploying Laravel on an Ubuntu Server involves multiple steps, but once you establish a reliable process, it’s straightforward to replicate. You’ve now covered:
- Server preparation and hardening
- Installing and configuring Nginx, PHP, Composer, and MySQL
- Deploying your code and setting permissions
- Configuring SSL, Supervisor, and scheduled tasks
- Automating future deployments and optimizing performance
With this setup, your Laravel application will be secure, performant, and easy to maintain. Happy coding and seamless deployments!