LEMP stack for a Forge-like Ubuntu server

Quynh NguyenQuynh Nguyen
4 min read

After getting a fresh Ubuntu server from here, I often install the LEMP stack to run my PHP/Laravel applications with these simple scripts.

Nginx Setup

Install Nginx and use h5bp configs.

wget -O nginx-setup.sh https://raw.githubusercontent.com/confetticode/forge-like-setup/main/scripts/nginx-setup.sh

bash nginx-setup.sh

When finishing, verify if nginx is running.

systemctl status nginx

PHP Setup

Install PHP 8.3 with Composer. It currently supports PHP 8.3 only.

wget -O php-setup.sh https://raw.githubusercontent.com/confetticode/forge-like-setup/main/scripts/php-setup.sh

bash php-setup.sh 8.3

When finishing, verity PHP and Composer.

forge@server-host:~$ php -v
PHP 8.3.13 (cli) (built: Oct 30 2024 11:28:41) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.3.13, Copyright (c) Zend Technologies
    with Zend OPcache v8.3.13, Copyright (c), by Zend Technologies
forge@server-host:~$ composer --version
Composer version 2.8.2 2024-10-29 16:12:11
PHP version 8.3.13 (/usr/bin/php8.3)
Run the "diagnose" command to get more detailed diagnostics output.

Allow forge to reload|restart|status php*-fpm services by creating /etc/sudoers.d/forge file with the following content.

forge ALL=(ALL) NOPASSWD: /usr/bin/systemctl reload php*-fpm
forge ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart php*-fpm
forge ALL=(ALL) NOPASSWD: /usr/bin/systemctl status php*-fpm

Change PHP FPM pool name by opening /etc/php/8.3/fpm/pool.d/www.conf and replacing [www] with [PHP 8.3]

; Start a new pool named 'www'.
; the variable $pool can be used in any directive and will be replaced by the
; pool name ('www' here)
; [www] -> [PHP 8.3]
[PHP 8.3]

Check PHP process names

ps aux | grep php

Restart PHP FPM service and check it status

systemctl restart php8.3-fpm

systemctl status php8.3-fpm

MySQL Setup

The default root password is “secret”. I’ll use mysql_secure_installation command to change it.

wget -O mysql-setup.sh https://raw.githubusercontent.com/confetticode/forge-like-setup/main/scripts/mysql-setup.sh

bash mysql-setup.sh

When finishing, verify if MySQL is running.

systemctl status nginx

Configure a PHP site

Replace laravel-demo with your domain.

Create a specific log directory

mkdir -p /var/log/nginx/laravel-demo.com

Create a vhost file at /etc/nginx/conf.d/laravel-demo.com.conf

server {
    listen [::]:80;
    listen 80;

    # The host name to respond to
    server_name laravel-demo.com;

    # The root directory
    root /home/forge/laravel-demo.com/public;

    # Write logs to specific files
    access_log  /var/log/nginx/laravel-demo.com/access.log;
    error_log  /var/log/nginx/laravel-demo.com/error.log;

    # Run index.php with a specific PHP-FPM version.
    location ~ \.php$ {
        include extra/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    }

    # The file should be served by default
    index index.html index.htm index.php;

    # Let index.php handle 404 error.
    error_page 404 /index.php;

     # Include the basic h5bp config set
     include h5bp/basic.conf;

    # Ignore /favicon.ico and /robots.txt requests
    location = /favicon.ico { log_not_found off; access_log off; }
    location = /robots.txt  { log_not_found off; access_log off; }

    # Deny requests to .ht files.
    location ~ /\.ht {
        deny all;
    }

    # If a directory or file exists, serve it.
    # Else, try to run index.php.
    # Otherwise, fail with 404 status code.
    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }
}

Ensure Nginx configuration is OK

nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Reload the Nginx service

systemctl reload nginx

Install Laravel

Clone the Laravel repository

pwd
/home/forge

git clone https://github.com/laravel/laravel.git laravel-demo.com

Cloning into 'laravel-demo.com'...
remote: Enumerating objects: 34591, done.
remote: Counting objects: 100% (75/75), done.
remote: Compressing objects: 100% (58/58), done.
remote: Total 34591 (delta 30), reused 38 (delta 12), pack-reused 34516 (from 1)
Receiving objects: 100% (34591/34591), 10.51 MiB | 14.82 MiB/s, done.
Resolving deltas: 100% (20457/20457), done.

cd laravel-demo.com

Copy .env from .env.example

cp .env.example .env

Install Composer packages

composer install --prefer-dist --no-dev

Generate an application key

php artisan key:generate

Run database migrations

php artisan migrate --forge

Setup DNS

Point the domain to the server IP address. Wait for a while and then visit http://laravel-demo.com to verify it works.

Clean setup files

I place *-setup.sh in /root directory. So I need to go there to delete them.

cd ~ # Go to /root directory

rm *-setup.sh

Summary

Here are steps, scripts or commands I use to set up the LEMP for a Forge-like Ubuntu server. They are installing Nginx, PHP, MySQL and configuring things. It’s a really helpful note for me. I’ll try to update and make more automation stuff later.

0
Subscribe to my newsletter

Read articles from Quynh Nguyen directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Quynh Nguyen
Quynh Nguyen

Full Stack Web Developer