Installing the L(EMP) Stack

Complete Guide to Setting Up Nginx, MariaDB, and PHP on Ubuntu Server

πŸ“‹ Introduction

The L(EMP) stack is a powerful combination of open-source software used to serve dynamic web applications and websites. The acronym stands for Linux (operating system), Nginx (web server, pronounced "Engine-X"), MariaDB (database management system), and PHP (server-side scripting language).

L(EMP) Stack Architecture

Linux (Ubuntu 24.04)
↓
Nginx (Web Server)
↓
MariaDB (Database)
↓
PHP 8.3 (Scripting)

πŸ’‘ Stack Components Overview

  • Nginx: High-performance web server that handles HTTP requests and serves static content
  • MariaDB: Relational database management system (MySQL fork) for data storage
  • PHP 8.3: Server-side scripting language for generating dynamic page content

πŸ“¦ Understanding Repositories and Package Management

Repository Types

Ubuntu uses two main types of repositories for software distribution:

βœ… Official Repositories

  • Tested by Ubuntu developers
  • Guaranteed malware-free
  • Full compatibility assured
  • Slightly older versions
  • Prioritize stability over features
  • Recommended for production servers

⚠️ Unofficial Repositories (PPAs)

  • Newer package versions
  • Maintained by developers/communities
  • Regular security updates
  • Support multiple PHP versions
  • Use with caution
  • OndΕ™ej PPA is trusted and safe
⚠️ Important Note: For server environments, stability and security take priority over having the latest features. Only add trusted unofficial repositories like the OndΕ™ej PPA.

APT Package Manager Commands

The Advanced Package Tool (APT) is Ubuntu's package management system. Here are the essential commands:

Command Purpose Example
apt update Update package list sudo apt update
apt upgrade Upgrade installed packages sudo apt upgrade
apt install Install new package(s) sudo apt install nginx
apt remove Remove package (keep config) sudo apt remove nginx
apt purge Remove package + config files sudo apt purge nginx
apt-cache search Search for packages apt-cache search nginx
apt-cache show Show package information apt-cache show nginx

πŸ’‘ Remove vs Purge

Remove: Uninstalls the package but preserves configuration files for future reinstallation.

Purge: Completely removes the package including all configuration files.

Searching for Packages

Search for a package:

apt-cache search nginx

View package details:

apt-cache show nginx

🌐 Installing Nginx Web Server

Nginx is a high-performance web server known for its stability, rich feature set, simple configuration, and low resource consumption. We'll install Nginx along with several useful modules.

Step 1: Update System

sudo apt update
sudo apt upgrade
⚠️ Configuration File Conflict: During upgrade, if you see a prompt about modified configuration files (like sshd_config), always choose "Keep the local version currently installed" unless you're certain about the changes.

Step 2: Add OndΕ™ej Nginx Repository

Note: The repository name has changed from nginx/mainline to just nginx.

sudo add-apt-repository ppa:ondrej/nginx

Step 3: Install Nginx and Modules

sudo apt install nginx \
  libnginx-mod-http-cache-purge \
  libnginx-mod-http-headers-more-filter \
  libnginx-mod-http-brotli-filter \
  libnginx-mod-http-brotli-static

Nginx Modules Explained

Module Purpose
nginx Core web server package
http-cache-purge Selective FastCGI cache purging
headers-more-filter Advanced header manipulation
http-brotli-filter Brotli compression for dynamic content
http-brotli-static Pre-compressed static file serving

Step 4: Check Nginx Status

sudo systemctl status nginx
sudo systemctl status nginx --no-pager -l

⚠️ Troubleshooting IPv6 Binding Error

If you disabled IPv6 for security and Nginx fails to start with an "address family not supported" error, you need to disable IPv6 listening in Nginx configuration:

sudo nano /etc/nginx/sites-available/default

Find the line:

listen [::]:80 default_server;

Comment it out by adding # at the beginning:

# listen [::]:80 default_server;

Save and restart Nginx:

sudo systemctl start nginx

Step 5: Verify Nginx is Running

# Check if enabled for auto-start
sudo systemctl is-enabled nginx

# Check status
sudo systemctl status nginx --no-pager -l

βœ… You should see "active (running)" status and "enabled" for auto-start.

Step 6: Test Nginx in Browser

Open your browser and navigate to:

http://your_server_ip_address/

Or test using curl:

# View HTTP headers
curl -I http://your_server_ip_address/

# View page content
curl -i http://your_server_ip_address/

The default welcome page is located at: /var/www/html/index.nginx-debian.html

Step 7: Check Nginx Version

nginx -v

πŸ—„οΈ Installing MariaDB Database Server

MariaDB is a community-developed, commercially supported fork of MySQL. Ubuntu 24.04 ships with MariaDB 10.11, which is a Long-Term Support (LTS) release maintained until February 2028.

Step 1: Install MariaDB

sudo apt update
sudo apt install mariadb-server

πŸ’‘ No need to run apt update if you just ran it for Nginx installation (within the same session).

Step 2: Check MariaDB Status

sudo systemctl status mariadb
sudo systemctl status mariadb --no-pager -l

Step 3: Verify Auto-Start Configuration

sudo systemctl is-enabled mariadb

βœ… MariaDB should show "active (running)" and "enabled" status.

MariaDB Communication Flow

πŸ“± Client Request

↓

🌐 Nginx (Web Server)

↓

🐘 PHP-FPM (Processes PHP)

↓

πŸ—„οΈ MariaDB (Fetches Data)

↓

πŸ“„ Dynamic HTML Response

πŸ”’ Security Note

After installation, you should run the MariaDB security script to improve security (covered in later sections):

sudo mysql_secure_installation

🐘 Installing PHP 8.3

PHP 8.3 is the latest stable version with significant performance improvements. We'll install it from the OndΕ™ej repository along with essential extensions.

Why Use OndΕ™ej's PHP Repository?

  • βœ… Easy version upgrades
  • βœ… Multiple PHP versions on same server
  • βœ… Regular security updates
  • βœ… Comprehensive extension support
  • βœ… Maintained by trusted Debian developer

Step 1: Add OndΕ™ej PHP Repository

sudo add-apt-repository ppa:ondrej/php

Step 2: Install PHP 8.3 with Extensions

πŸ’‘ Brace Expansion Method

Instead of typing each package separately, use brace expansion for efficiency:

sudo apt install php8.3-{fpm,gd,mbstring,mysql,xml,xmlrpc,opcache,cli,zip,soap,intl,bcmath,curl,imagick,ssh2}

PHP Extensions Explained

Extension Purpose
fpm FastCGI Process Manager - Processes PHP requests from Nginx via FastCGI protocol over Unix sockets
gd Graphics Draw - Image manipulation library for creating and editing images
mbstring Multibyte String - Handles non-ASCII strings and character encoding conversions
mysql MySQL/MariaDB Driver - Enables PHP to communicate with MySQL/MariaDB databases
xml XML Parser - Reads and processes XML data from strings
xmlrpc XML-RPC - Allows remote updates to WordPress and other applications
opcache Opcode Cache - Dramatically improves PHP performance by caching precompiled scripts
cli Command Line Interface - Executes PHP commands from the terminal
zip ZIP Archive - Creates, reads, and extracts ZIP files
soap SOAP Protocol - Enables web service creation and consumption
intl Internationalization - Provides localization support for dates, numbers, and currencies
bcmath Binary Calculator - Arbitrary precision mathematics for financial calculations
curl Client URL Library - Makes HTTP requests to external APIs and services
imagick ImageMagick - Advanced image processing using the ImageMagick library
ssh2 SSH2 Protocol - Secure remote server access via SSH

Step 3: Verify PHP-FPM Status

sudo systemctl status php8.3-fpm
sudo systemctl status php8.3-fpm --no-pager -l

Step 4: Check Auto-Start Configuration

sudo systemctl is-enabled php8.3-fpm

Step 5: Verify PHP Version

php -v

βœ… You should see PHP version 8.3.x displayed with Zend Engine information.

How Nginx and PHP-FPM Work Together

  1. πŸ“¨ Client sends HTTP request for a PHP file to Nginx
  2. πŸ”„ Nginx receives request and identifies it as PHP content
  3. πŸ“€ Nginx forwards request to PHP-FPM via FastCGI protocol (Unix socket)
  4. βš™οΈ PHP-FPM processes the PHP script (connects to MariaDB if needed)
  5. πŸ“₯ PHP-FPM returns the generated HTML to Nginx
  6. 🌐 Nginx sends response back to the client

βœ… Stack Installation Verification

Complete System Check

# Check all services
sudo systemctl status nginx
sudo systemctl status mariadb
sudo systemctl status php8.3-fpm

# Verify auto-start enabled
sudo systemctl is-enabled nginx
sudo systemctl is-enabled mariadb
sudo systemctl is-enabled php8.3-fpm

# Check versions
nginx -v
mysql --version
php -v

βœ… Installation Complete!

Your L(EMP) stack is now fully installed and configured. All services should be:

  • βœ“ Running (active)
  • βœ“ Enabled for auto-start on boot
  • βœ“ Displaying correct version numbers

Quick Reference Commands

Service Start Stop Restart Status
Nginx sudo systemctl start nginx sudo systemctl stop nginx sudo systemctl restart nginx sudo systemctl status nginx
MariaDB sudo systemctl start mariadb sudo systemctl stop mariadb sudo systemctl restart mariadb sudo systemctl status mariadb
PHP-FPM sudo systemctl start php8.3-fpm sudo systemctl stop php8.3-fpm sudo systemctl restart php8.3-fpm sudo systemctl status php8.3-fpm

πŸš€ Next Steps

What's Coming Next?

Now that your L(EMP) stack is installed, the next section will cover configuring your server to send emails directly without requiring SMTP plugins. This is essential for WordPress notifications, password resets, and other system emails.

Recommended Additional Configurations

  • πŸ” Secure MariaDB installation (mysql_secure_installation)
  • πŸ”§ Configure Nginx server blocks (virtual hosts)
  • ⚑ Optimize PHP-FPM settings for performance
  • πŸ”’ Set up SSL/TLS certificates (Let's Encrypt)
  • πŸ“Š Configure logging and monitoring
  • πŸ›‘οΈ Implement firewall rules (UFW)

πŸ”§ Common Troubleshooting

Issue: Nginx won't start after installation

Cause: IPv6 disabled but Nginx trying to bind to IPv6 address

Solution: Comment out the IPv6 listen directive in /etc/nginx/sites-available/default

Issue: Port 80 already in use

Cause: Another service using port 80

Check: sudo netstat -tulpn | grep :80

Solution: Stop conflicting service or configure Nginx to use different port

Issue: PHP files downloading instead of executing

Cause: Nginx not configured to pass PHP requests to PHP-FPM

Solution: Configure Nginx server block to process PHP files (covered in later sections)