DEV Community

Cover image for Deploying Laravel with Nginx on Ubuntu 24.04
Sanskriti Harmukh for Vultr

Posted on with Aashish Chaurasiya • Originally published at docs.vultr.com

Deploying Laravel with Nginx on Ubuntu 24.04

Laravel is a popular PHP framework with routing, authentication, and database management built in. This guide deploys a Laravel app behind Nginx on Ubuntu 24.04, wires it to MySQL, secures it with Let's Encrypt, and builds a small dashboard that queries live data.

Prerequisites: Ubuntu 24.04 with Nginx and MySQL installed, a non-root sudo user, a domain A record (e.g. app.example.com).


Create the Database

$ sudo mysql
Enter fullscreen mode Exit fullscreen mode
mysql> CREATE DATABASE laravel_demo;
mysql> CREATE USER 'laravel_user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'secure_password';
mysql> GRANT ALL ON laravel_demo.* TO 'laravel_user'@'localhost';
mysql> FLUSH PRIVILEGES;
mysql> EXIT;
Enter fullscreen mode Exit fullscreen mode

Seed a demo table to query later:

$ mysql -u laravel_user -p
Enter fullscreen mode Exit fullscreen mode
mysql> USE laravel_demo;
mysql> CREATE TABLE server_stats (
            id INT AUTO_INCREMENT,
            server_name VARCHAR(255),
            region VARCHAR(255),
            cpu_usage DECIMAL(5,2),
            memory_usage DECIMAL(5,2),
            status ENUM('active', 'maintenance', 'offline'),
            last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            PRIMARY KEY(id)
        );
mysql> INSERT INTO server_stats (
           server_name, region, cpu_usage, memory_usage, status
       )
       VALUES
           ('app-01', 'us-east', 24.50, 45.30, 'active'),
           ('db-01',  'eu-west', 12.75, 78.20, 'active'),
           ('web-01', 'ap-south', 65.80, 89.50, 'active');
mysql> EXIT;
Enter fullscreen mode Exit fullscreen mode

Install Composer and PHP Extensions

$ sudo apt update
$ sudo apt install composer php php-curl php-fpm php-bcmath php-json php-mysql php-mbstring php-xml php-tokenizer php-zip -y
$ composer --version
$ php --version
$ sudo systemctl restart php8.3-fpm
Enter fullscreen mode Exit fullscreen mode

php-fpm runs PHP as a service Nginx can talk to; php-mysql/php-mbstring/php-xml/php-tokenizer/php-zip cover Laravel's runtime requirements.


Create the Laravel Project

$ cd ~
$ composer create-project --prefer-dist laravel/laravel laravel-demo
$ cd laravel-demo
$ php artisan key:generate
Enter fullscreen mode Exit fullscreen mode

Edit .env:

$ nano .env
Enter fullscreen mode Exit fullscreen mode
APP_NAME=laravel-demo
APP_ENV=development
APP_KEY=base64:APPLICATION_UNIQUE_KEY
APP_DEBUG=true
APP_URL=http://app.example.com

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_demo
DB_USERNAME=laravel_user
DB_PASSWORD=secure_password

SESSION_DRIVER=file
Enter fullscreen mode Exit fullscreen mode

Move it to the web root and set permissions:

$ sudo mv ~/laravel-demo /var/www/laravel-demo
$ sudo chown -R www-data:www-data /var/www/laravel-demo
$ sudo chmod -R 755 /var/www/laravel-demo/storage
$ sudo chmod -R 755 /var/www/laravel-demo/bootstrap/cache
$ cd /var/www/laravel-demo
$ php artisan migrate
Enter fullscreen mode Exit fullscreen mode

Configure Nginx

$ sudo nano /etc/nginx/sites-available/laravel-demo.conf
Enter fullscreen mode Exit fullscreen mode
server {
    listen 80;
    server_name app.example.com;
    root /var/www/laravel-demo/public;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    index index.php;
    charset utf-8;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}
Enter fullscreen mode Exit fullscreen mode
$ sudo ln -s /etc/nginx/sites-available/laravel-demo.conf /etc/nginx/sites-enabled/
$ sudo nginx -t
$ sudo systemctl restart nginx
$ sudo ufw allow 80/tcp
$ sudo ufw reload
Enter fullscreen mode Exit fullscreen mode

Visit http://app.example.com — you should see the default Laravel welcome page.


Secure with Let's Encrypt

$ sudo apt install certbot python3-certbot-nginx -y
$ sudo certbot --nginx --redirect -d app.example.com -m admin@app.example.com --agree-tos
$ sudo certbot renew --dry-run
$ sudo systemctl restart nginx
$ sudo ufw allow 443/tcp
$ sudo ufw reload
Enter fullscreen mode Exit fullscreen mode

Build a Demo Dashboard

Replace the default route to query server_stats and render it.

$ sudo mv /var/www/laravel-demo/routes/web.php /var/www/laravel-demo/routes/web.php.ORIG
$ sudo nano /var/www/laravel-demo/routes/web.php
Enter fullscreen mode Exit fullscreen mode
<?php

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    $servers = DB::table('server_stats')
                ->orderBy('status')
                ->orderBy('cpu_usage', 'desc')
                ->get();

    return view('dashboard', ['servers' => $servers]);
});
Enter fullscreen mode Exit fullscreen mode

Create the Blade view:

$ sudo nano /var/www/laravel-demo/resources/views/dashboard.blade.php
Enter fullscreen mode Exit fullscreen mode
<!DOCTYPE html>
<html>
<head>
    <title>Server Dashboard</title>
    <style>
        body { font-family: 'Segoe UI', sans-serif; margin: 2rem; }
        .server-card {
            padding: 1rem;
            margin-bottom: 1rem;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        .active {
            border-left: 4px solid #10B981;
            background: #F0FDF4;
        }
        .maintenance {
            border-left: 4px solid #F59E0B;
            background: #FFFBEB;
        }
        .offline {
            border-left: 4px solid #EF4444;
            background: #FEF2F2;
        }
        .metric {
            font-weight: 600;
            color: #1F2937;
        }
    </style>
</head>
<body>
    <h1>Server Status Dashboard</h1>
    <p>Live metrics from your infrastructure</p>

    @foreach($servers as $server)
    <div class="server-card {{ $server->status }}">
        <h3>{{ $server->server_name }} <small>({{ $server->region }})</small></h3>
        <p class="metric">Status: {{ ucfirst($server->status) }}</p>

        @if($server->status != 'offline')
            <p class="metric">CPU: {{ $server->cpu_usage }}%</p>
            <p class="metric">Memory: {{ $server->memory_usage }}%</p>
        @endif

        <p>Last updated: {{ $server->last_updated }}</p>
    </div>
    @endforeach
</body>
</html>
Enter fullscreen mode Exit fullscreen mode
$ sudo systemctl restart nginx
Enter fullscreen mode Exit fullscreen mode

Visit https://app.example.com — the dashboard should render live rows from server_stats.


Next Steps

Laravel is deployed behind Nginx with TLS and a working database-backed view. From here:

  • Add Eloquent models and migrations instead of raw DB::table() queries for larger apps
  • Switch APP_ENV to production and APP_DEBUG to false before going live
  • Set up a queue worker (php artisan queue:work) as a systemd service for background jobs

For the full guide, visit the original article on Vultr Docs.

Top comments (0)