Install Nginx + PHP-FPM + MariaDB + SSL at Debian 12

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