Step by step install Nginx + PHP-FPM + MariaDB + SSL at Debian 12
1. Clean & uninstall Apache2 on Debian 12
#systemctl stop apache2 #systemctl disable apache2 #apt purge apache2 apache2-utils apache2-bin apache2.2-common -y #apt autoremove --purge -y
#sudo apt autoclean
2. Update, Upgrade, Install Zip Unzip Vim, Hostname
$sudo apt-get update -y && sudo apt-get upgrade -y $sudo nano /etc/hostname $sudo apt-get install zip -y && sudo apt-get install unzip -y $sudo apt-get install vim -y
- Enable Vim Copy Paste with mouse
Enable vim cut paste Debian 9
3. Install Nginx + PHP-FPM + MariaDB
$sudo apt install nginx -y $sudo systemctl enable nginx $sudo systemctl start nginx
4. Install PHP, then PHP-FPM and extensions
$apt install php -y $sudo php -v PHP 8.2.29 (cli) (built: Jul 3 2025 16:16:05) (NTS)
$apt install php8.2 php8.2-fpm php8.2-mysql php8.2-cli php8.2-curl php8.2-mbstring php8.2-xml php8.2-zip unzip -y php8.2-gd
- Enable and start PHP-FPM:
$sudo systemctl enable php8.2-fpm $sudo systemctl start php8.2-fpm
- Increase PHP Upload and Post Size
edit /etc/nginx/nginx.conf and add code client_max_body_size 50M; inside the http {
#vim /etc/nginx/nginx.conf
add code below inside the http {
client_max_body_size 50M;
Find php.ini file by create phpinfo() file at /var/www/html then access http://website/phpinfo.php
<?php phpinfo();?>
Edit php.ini, check location by create phpinfo.php at http://website/phpinfo.php
#vim /etc/php/8.2/fpm/php.ini
Search for upload_max_filesize variable and specify with size below
upload_max_filesize = 50M
Search for post_max_size variable and specify same size
post_max_size = 50M
Once done, save the modified php.ini file and restart the php / server.
sudo systemctl restart php8.2-fpm
- Enable NGINX default (symlink to /etc/nginx/sites-enabled/)
#ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default
#nginx -t && nginx -s reload
- Configure NGINX to Use PHP 8.2-FPM
In your NGINX config paste the PHP Handling:
#cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default-backup #vim /etc/nginx/sites-available/default
# PHP handling
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
include fastcgi_params;
fastcgi_index index.php;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
- Restart NGINX AND PHP 8.2-FPM
$sudo systemctl restart php8.2-fpm
$sudo nginx -t && nginx -s reload
- Add test file:
$sudo echo "<?php phpinfo(); ?>" | sudo tee /var/www/html/info.php
- Visit: http://ipaddress/info.php and look for
Server API → FPM/FastCGI
5. Install MariaDB
$sudo apt install mariadb-server mariadb-client -y $sudo systemctl enable mariadb $sudo systemctl start mariadb $sudo mysql_secure_installation
- Create mySQL User Grant PRIVILEGES to Database
Create mySQL User Grant PRIVILEGES to Database
- Import Export MySQL Dumpfile MySQL Server
Import Export MySQL Dumpfile MySQL Server on Terminal
6. Nginx Seo Friendly URL/Permalinks for WordPress
$sudo vim /etc/nginx/sites-available/default
Find this block
location / {
try_files $uri $uri/ /index.php?$args;
}
- Nginx Seo Friendly URL migrated from .htaccess
# Serve existing files or route to @rewrite
location / {
try_files $uri $uri/ @rewrite;
}
- Restart NGINX AND PHP 8.2-FPM
$sudo systemctl restart php8.2-fpm $sudo systemctl restart nginx
7. Configure NGINX real default for domain, SSL has been installed correctly
#vim /etc/nginx/sites-available/default
server {
listen 80;
listen [::]:80;
server_name mywebsite.com www.mywebsite.com;
# Force HTTPS + non-www
return 301 https://mywebsite.com$request_uri;
}
# 2) HTTPS REAL
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name mywebsite.com www.mywebsite.com;
root /var/www/html;
index index.php index.html;
ssl_certificate /etc/nginx/ssl/mywebsite.com.fullchain.crt;
ssl_certificate_key /etc/nginx/ssl/mywebsite.com.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# Default charset
charset utf-8;
# Disable directory listing
autoindex off;
# Serve existing files or route to @rewrite
location / {
try_files $uri $uri/ @rewrite;
}
# PHP handling
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
include fastcgi_params;
fastcgi_index index.php;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location @rewrite {
rewrite ^/contact-us/?$ /contact-us.php last;
rewrite ^/sitemap\.xml$ /sitemap.php last;
#rewrite ^/404/?$ /404.php last;
return 404;
}
error_page 404 /404.php;
location = /404.php {
internal;
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~* \.(css|js|jpg|jpeg|png|gif|svg|ico|webp|ttf|woff|woff2|eot)$ {
try_files $uri =404;
expires max;
access_log off;
}
location ~ /\.ht {
deny all;
}
}
8. Configure NGINX for multiple domains (virtual hosts) on one server
- Create Root Folders for Each Domain
$sudo mkdir -p /var/www/domain1.com $sudo mkdir -p /var/www/domain2.com $sudo mkdir -p /var/www/domain3.com $sudo chown -R www-data:www-data /var/www/domain1.com $sudo chown -R www-data:www-data /var/www/domain3.com $sudo chown -R www-data:www-data /var/www/domain3.com
$sudo find /var/www/domain1.com -type d -exec chmod 755 {} \; $sudo find /var/www/domain1.com -type f -exec chmod 644 {} \;
- Create Nginx Server Blocks (Virtual Host Configs)
#sudo vim sudo vim /etc/nginx/sites-available/domain1.com
# Virtual Host configuration for domain1.com
#
# You can move that to a different file under sites-available/ and symlink that to sites-enabled/ to enable it.
#
server {
listen 80;
listen [::]:80;
server_name domain1.com www.domain1.com;
root /var/www/domain1.com;
index index.php index.html;
#location / {
# try_files $uri $uri/ =404;
#}
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}
}
- Enable the Sites
$sudo ln -s /etc/nginx/sites-available/domain1.com /etc/nginx/sites-enabled/
- Test Nginx Configuration
$sudo nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
- Reload Nginx
$sudo systemctl reload nginx
- Test by add file then http://domain1.com/index.html
$sudo echo "It Works" | sudo tee /var/www/domain1.com/index.html
9. Install Certbot SSL HTTPS Using Snap
- Install snapd (if not already installed)
#sudo apt update #sudo apt install snapd -y
- Enable and start snap:
$sudo systemctl enable snapd $sudo systemctl start snapd
- Let the system link classic snaps:
$sudo snap install core $sudo snap refresh core
- Install Certbot
$sudo snap install --classic certbot
- Create symlink so certbot works globally:
$sudo ln -s /snap/bin/certbot /usr/bin/certbot
- Check Certbot version:
$sudo certbot --version certbot 2.x.x
- Obtain SSL certificate for Nginx, make sure your Nginx config for http is working at http://yourdomain.com, then run:
#certbot --nginx -d yourdomain.com -d www.yourdomain.com Certbot will: Auto-detect your Nginx config Request and install a certificate Ask if you want HTTP to HTTPS redirect (say yes)
- Test HTTPS https://yourdomain.com and You should see the lock icon
- Auto-renew is set up by Snap
You don’t need to manually configure cron jobs. Snap installs a systemd timer to auto-renew: Check it:
$sudo systemctl list-timers | grep certbot ✅ Done!
You now have: Fresh Certbot installed via Snap Nginx auto-configured for HTTPS Auto-renewals enabled
10. Delete Certbot SSL Certificate and Domain
- Show all certificate
$sudo certbot certificates Found the following certs: Certificate Name: mydomainname.com Serial Number: 6810f862e51702da43e0e1bc2f80f0d1123 Key Type: ECDSA
- Delete the SSL Certificate that you want
$sudo delete --cert-name mydomainname.com Are you sure you want to delete the above certificate(s)? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Y)es/(N)o: Y Deleted all files relating to certificate mydomainname.com.
11. If needed “Add Swap Memory”
https://terminal.ovh/2020/11/03/add-swap-memory-debian-10/
12. If needed “Increase SSH Connection Timeout”
#vim /etc/ssh/sshd_config ClientAliveInterval 1200 ClientAliveCountMax 3 #systemctl status sshd.service
13. Configure Iptables Firewall Rules
- Debian 11 12 go to this configuration
Iptables Debian 11 Bullseye configuration
- Configure UFW Firewall Rules
UFW Firewall Basic Rules and Commands
- Setup and Configure Fail2ban
Setup Fail2ban on Debian 9