Table of Contents
- What is LEMP
- Prerequisites
- 1. Installing PHP 8.3
- 2. Installing NGINX
- 3. Enable Firewall
- 4. Install MySQL and PHPMyAdmin
- 5. NGINX Configuration
- 6. Install Free SSL via CertBot
- 7. Install Composer
- 8. Install Node + NPM via NVM
- Conclusion
If you’re an old school developer like me, you probably prefer setting up server yourself. LEMP Stack is my go-to stack for a Web Server. And we all love the good old PHPMyAdmin for database administration.
What is LEMP
A LEMP stack is a popular open-source web server setup used to host dynamic websites and apps. The acronym stands for Linux, Nginx (pronounced “Engine-X”), MySQL (or MariaDB), and PHP. Together, they form a fast, reliable environment for serving modern PHP applications. When people refer to a LEMP server, they usually mean a VPS or cloud instance running all four components, configured to serve web traffic efficiently.
In this comprehensive guide, you’ll install:
- PHP 8.3 (with PHP-FPM)
- NGINX
- MySQL Server
- PHPMyAdmin
- Composer
- Node + NPM
- And finally a free SSL from Let’s Encrypt via CertBot
If you’re looking for commands or codes ONLY and don’t have time to read this article, you can find it on this secret gist I made. You're welcome :)
Prerequisites
The first thing is to make sure your package repos are up to date, for that run this:
apt update
This will update your VPS’ packages list.
Next, upgrade your packages that are pre-installed:
apt upgrade
If you’re running Ubuntu 24.04 LTS or later, you can skip this step. For Ubuntu 22.04 LTS or older, you also need to add Odrej’s PHP repository with this:
apt-get install ca-certificates apt-transport-https software-properties-common add-apt-repository ppa:ondrej/php apt update
The second command would ask you to hit “Enter” twice for confirmation.
1. Installing PHP 8.3
Run this command to install PHP 8.3-fpm module:
apt install php8.3-fpm
Also install some essential packages we’ll need:
apt install php-mbstring php-zip php-gd php-json php-curl php-intl unzip curl npm
2. Installing NGINX
Once you install php 8.3-FPM, install NGINX:
apt install nginx
3. Enable Firewall
On most VPS, and on all the droplets of DigitalOcean, UFW (or Uncomplicated Firewall) is pre-installed. You just need to configure and enable it. Since our server will only be running a web server (port 80 and 433) and we’ll need SSH access to it as well (port 22), you need to allow these ports by running the following commands:
ufw allow 80
ufw allow 443
ufw allow 22
These will allow traffic on port 80, 443 and 22. Optional, but if you have a static IP you can restrict SSH so only your workstation/VPN can connect (replace 131.5.13.44 with your actual IP):
sudo ufw allow from 131.5.13.44 to any port 22 proto tcp
Next, run this command to enable the firewall:
ufw enable
4. Install MySQL and PHPMyAdmin
Run this command to install MySQL server:
apt install mysql-server
Once the MySQL server is installed, it’ll ask you to run mysql_secure_installation
but you shouldn’t right away. Securing MySQL Installation can lead to password validation issues when installing PHPMyAdmin, so once the MySQL Server is installed you should install PHPMyAdmin:
apt install phpmyadmin
During installation it’ll ask you to select your web server and the list would contain “Apache2” and “lighttpd”. Since we’re using NGINX, you can skip this step by just hitting “enter”.
Next, it’ll ask you to “Configure database for phpmyadmin with dbconfig-common?”. Here you need to select “Yes”. And on the next screen, where it’ll ask you to enter a password, just hit “enter” with empty password, the installation will generate a password on it’s own.
Now you can run this command to secure installation:
mysql_secure_installation
The mysql_secure_installation
command will ask you a series of questions:
Prompt | Reply With | Why |
---|---|---|
Enable VALIDATE PASSWORD component? | Y , level 2 (strong) |
Enforces long, mixed-case passwords |
Remove anonymous users? | Y |
Closes guest accounts |
Disallow root login remotely? | Y |
Forces you to SSH into the box first |
Remove test database? | Y |
Deletes the default world-readable DB |
Reload privilege tables now? | Y |
Applies changes instantly |
These choices shut down the two easiest attack vectors: remote‐root logins and weak passwords.
Need to automatically restart when MySQL crashes? Check out my MySQL auto-restart tutorial
Now link the phpmyadmin directory to root of the web server (we’ll configure NGINX in the next step):
ln -s /usr/share/phpmyadmin /var/www/html/phpmyadmin
5. NGINX Configuration
Delete the default NGINX site:
rm /etc/nginx/sites-enabled/default /etc/nginx/sites-available/default
Create a new NGINX Site config with nano:
nano /etc/nginx/sites-available/yourwebsite.com
You can paste the following config and edit to your requirement:
server {
listen 80;
server_name yourwebsite.com www.yourwebsite.com;
root /var/www/html;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
}
location ~ /\. {
deny all;
}
# auth_basic "Restricted Content";
# auth_basic_user_file /etc/nginx/.htpasswd;
}
If this is a staging/test server, you might want to uncomment the
auth_basic
code from line 21 and 22. And make sure the auth user file exists, by running this command:sh -c 'printf "username:%s\n" "$(openssl passwd -6)" > /etc/nginx/.htpasswd'
This will ask you to enter password, then confirm password and then save the .htpasswd
file.
Once you save the site config in /etc/nginx/sites-available/yourwebsite.com
you’ll now link it to Enabled Sites:
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
Run this command to check for any errors in NGINX config:
sudo nginx -t
If it’s all good, run this to restart NGINX server:
sudo systemctl restart nginx
6. Install Free SSL via CertBot
Install packages for Certbot and and Certbot NGINX plugin:
apt install certbot python3-certbot-nginx
Once installed, run Certbot and follow on screen instructions:
certbot
7. Install Composer
Run these commands to install composer:
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;"
php composer-setup.php --install-dir=/usr/local/bin --filename=composer
Now confirm if the composer is installed with this command:
composer --version
8. Install Node + NPM via NVM
Run this command to install NVM (Node Version Manager):
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
Now run nvm to install stable Node + NPM:
nvm install stable
If nvm
doesn’t work, run these and try nvm install stable
again:
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
Conclusion
Setting up a server yourself can be daunting, especially if you’re new to DevOps. You can run into PHPMyAdmin not installing due to “Password does not satisfy the current policy requirements”, Conflicting Node/NPM versions etc. or so many other errors. So, over the years, I’ve perfected the solution that I wrote in this article. We installed PHP 8.3, NGINX, MySQL, PHPMyAdmin, SSL, Composer and NPM using the leanest way possible.
If you have any questions or run into issues, feel free to reach out. Happy coding!