<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: M. K. Tanjin Sarker</title>
    <description>The latest articles on DEV Community by M. K. Tanjin Sarker (@tanjinsarker).</description>
    <link>https://dev.to/tanjinsarker</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1091067%2F048185dd-1ab1-4b09-be15-12baa575dcc2.jpeg</url>
      <title>DEV Community: M. K. Tanjin Sarker</title>
      <link>https://dev.to/tanjinsarker</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tanjinsarker"/>
    <language>en</language>
    <item>
      <title>Laravel Permission Hardening Script</title>
      <dc:creator>M. K. Tanjin Sarker</dc:creator>
      <pubDate>Wed, 11 Mar 2026 10:24:30 +0000</pubDate>
      <link>https://dev.to/tanjinsarker/laravel-permission-hardening-script-g0l</link>
      <guid>https://dev.to/tanjinsarker/laravel-permission-hardening-script-g0l</guid>
      <description>&lt;h2&gt;
  
  
  Laravel File Permission Hardening for Multi-Developer Production Server
&lt;/h2&gt;

&lt;p&gt;When multiple developers work on the same Laravel project on a production server, improper file permissions can cause several issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Git permission errors&lt;/li&gt;
&lt;li&gt;Laravel 419 Page Expired errors&lt;/li&gt;
&lt;li&gt;Storage write failures&lt;/li&gt;
&lt;li&gt;Cache permission issues&lt;/li&gt;
&lt;li&gt;Security risks from overly permissive access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This guide shows a &lt;strong&gt;safe and production-ready Laravel permission hardening setup&lt;/strong&gt; using a Bash script.&lt;/p&gt;




&lt;h2&gt;
  
  
  Project Structure
&lt;/h2&gt;

&lt;p&gt;Example Laravel project path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/var/www/html/laravel_application
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Developers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tanjin
rasel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Developer group:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;webdev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Web server runtime user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;www-data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Permission Strategy
&lt;/h2&gt;

&lt;p&gt;We will follow these security rules:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Owner&lt;/th&gt;
&lt;th&gt;Permission&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Project directory&lt;/td&gt;
&lt;td&gt;tanjin:webdev&lt;/td&gt;
&lt;td&gt;2775&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Application files&lt;/td&gt;
&lt;td&gt;tanjin:webdev&lt;/td&gt;
&lt;td&gt;664&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Directories&lt;/td&gt;
&lt;td&gt;tanjin:webdev&lt;/td&gt;
&lt;td&gt;2775&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;storage&lt;/td&gt;
&lt;td&gt;www-data:webdev&lt;/td&gt;
&lt;td&gt;775&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;bootstrap/cache&lt;/td&gt;
&lt;td&gt;www-data:webdev&lt;/td&gt;
&lt;td&gt;775&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.env&lt;/td&gt;
&lt;td&gt;tanjin:webdev&lt;/td&gt;
&lt;td&gt;640&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;public&lt;/td&gt;
&lt;td&gt;tanjin:webdev&lt;/td&gt;
&lt;td&gt;755&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This setup ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developers can modify project files&lt;/li&gt;
&lt;li&gt;Laravel runtime can write to storage and cache&lt;/li&gt;
&lt;li&gt;Sensitive environment variables remain protected&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why Use &lt;code&gt;2775&lt;/code&gt; Permissions?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2775
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Breakdown:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;setgid (new files inherit group)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;owner rwx&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;group rwx&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;others r-x&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;drwxrwsr-x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures all new files inherit the &lt;strong&gt;webdev group&lt;/strong&gt;, enabling safe multi-developer collaboration.&lt;/p&gt;




&lt;h2&gt;
  
  
  Laravel Permission Hardening Script
&lt;/h2&gt;

&lt;p&gt;Below is the complete Bash script to configure Laravel permissions safely.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;PROJECT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/html/laravel_application
&lt;span class="nv"&gt;MAINUSER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;tanjin
&lt;span class="nv"&gt;GROUP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;webdev
&lt;span class="nv"&gt;OTHERSUSER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"rasel"&lt;/span&gt;

&lt;span class="c"&gt;# create group if not exists&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;groupadd &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nv"&gt;$GROUP&lt;/span&gt;

&lt;span class="c"&gt;# add other developers to group&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;USER &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;$OTHERSUSER&lt;/span&gt;
&lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; &lt;span class="nv"&gt;$GROUP&lt;/span&gt; &lt;span class="nv"&gt;$USER&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;

&lt;span class="c"&gt;# set project ownership&lt;/span&gt;
&lt;span class="nb"&gt;sudo chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="nv"&gt;$MAINUSER&lt;/span&gt;:&lt;span class="nv"&gt;$GROUP&lt;/span&gt; &lt;span class="nv"&gt;$PROJECT&lt;/span&gt;

&lt;span class="c"&gt;# directory permissions&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;find &lt;span class="nv"&gt;$PROJECT&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; d &lt;span class="nt"&gt;-exec&lt;/span&gt; &lt;span class="nb"&gt;chmod &lt;/span&gt;2775 &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt;

&lt;span class="c"&gt;# file permissions&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;find &lt;span class="nv"&gt;$PROJECT&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-exec&lt;/span&gt; &lt;span class="nb"&gt;chmod &lt;/span&gt;664 &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt;

&lt;span class="c"&gt;# laravel writable directories&lt;/span&gt;
&lt;span class="nb"&gt;sudo chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; www-data:&lt;span class="nv"&gt;$GROUP&lt;/span&gt; &lt;span class="nv"&gt;$PROJECT&lt;/span&gt;/storage
&lt;span class="nb"&gt;sudo chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; www-data:&lt;span class="nv"&gt;$GROUP&lt;/span&gt; &lt;span class="nv"&gt;$PROJECT&lt;/span&gt;/bootstrap/cache

&lt;span class="nb"&gt;sudo chmod&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; 775 &lt;span class="nv"&gt;$PROJECT&lt;/span&gt;/storage
&lt;span class="nb"&gt;sudo chmod&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; 775 &lt;span class="nv"&gt;$PROJECT&lt;/span&gt;/bootstrap/cache

&lt;span class="c"&gt;# protect env file&lt;/span&gt;
&lt;span class="nb"&gt;sudo chown&lt;/span&gt; &lt;span class="nv"&gt;$MAINUSER&lt;/span&gt;:&lt;span class="nv"&gt;$GROUP&lt;/span&gt; &lt;span class="nv"&gt;$PROJECT&lt;/span&gt;/.env
&lt;span class="nb"&gt;sudo chmod &lt;/span&gt;640 &lt;span class="nv"&gt;$PROJECT&lt;/span&gt;/.env

&lt;span class="c"&gt;# secure public directory&lt;/span&gt;
&lt;span class="nb"&gt;sudo chmod&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; 755 &lt;span class="nv"&gt;$PROJECT&lt;/span&gt;/public

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Laravel permission hardening completed."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  How to Use the Script
&lt;/h2&gt;

&lt;p&gt;Create the script file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano laravel_permission_fix.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste the script and save.&lt;/p&gt;

&lt;p&gt;Make it executable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x laravel_permission_fix.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./laravel_permission_fix.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Important Git Rule
&lt;/h2&gt;

&lt;p&gt;Never run Git commands with &lt;code&gt;sudo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Incorrect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;git pull
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Correct:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git pull
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running Git with sudo can cause &lt;strong&gt;repository ownership issues&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Laravel Writable Directories
&lt;/h2&gt;

&lt;p&gt;Laravel requires write access to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;storage
bootstrap/cache
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without proper permissions, you may encounter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;419 Page Expired errors&lt;/li&gt;
&lt;li&gt;Failed cache writes&lt;/li&gt;
&lt;li&gt;Session storage errors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The script configures these directories for &lt;strong&gt;www-data runtime access&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Security Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Never commit &lt;code&gt;.env&lt;/code&gt; to Git&lt;/li&gt;
&lt;li&gt;Always protect &lt;code&gt;.env&lt;/code&gt; with restricted permissions&lt;/li&gt;
&lt;li&gt;Use group-based developer access instead of giving full ownership&lt;/li&gt;
&lt;li&gt;Avoid &lt;code&gt;777&lt;/code&gt; permissions on any Laravel directory&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final Recommended Structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/var/www/html/laravel_application
│
├── app
├── bootstrap
│   └── cache (www-data:webdev)
│
├── config
├── database
├── public (755)
│
├── resources
├── routes
├── storage (www-data:webdev)
│
├── vendor
├── artisan
├── composer.json
└── .env (640)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Result
&lt;/h2&gt;

&lt;p&gt;After running the script:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple developers can safely work on the project&lt;/li&gt;
&lt;li&gt;Laravel runtime can write to storage and cache&lt;/li&gt;
&lt;li&gt;Sensitive configuration files remain protected&lt;/li&gt;
&lt;li&gt;Git permission errors are avoided&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Correct Laravel file permissions are essential for both &lt;strong&gt;security and stability&lt;/strong&gt; in production environments.&lt;/p&gt;

&lt;p&gt;Using a &lt;strong&gt;group-based permission model with proper directory ownership&lt;/strong&gt; ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;secure collaboration&lt;/li&gt;
&lt;li&gt;predictable deployments&lt;/li&gt;
&lt;li&gt;fewer runtime errors&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you found this guide useful, feel free to adapt the script to your own Laravel infrastructure.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>permissions</category>
      <category>linux</category>
      <category>devops</category>
    </item>
    <item>
      <title>Ubuntu 24.04 Setup Script: Nginx/Apache, PHP-FPM, MySQL/MariaDB, Docker, UFW</title>
      <dc:creator>M. K. Tanjin Sarker</dc:creator>
      <pubDate>Wed, 21 Jan 2026 08:25:16 +0000</pubDate>
      <link>https://dev.to/tanjinsarker/ubuntu-2404-full-setup-lamp-stack-docker-docker-compose-one-script-2m56</link>
      <guid>https://dev.to/tanjinsarker/ubuntu-2404-full-setup-lamp-stack-docker-docker-compose-one-script-2m56</guid>
      <description>&lt;h2&gt;
  
  
  ✅ Ubuntu 24.04 Full Server Setup Script (Apache/Nginx + PHP-FPM Multi Version + MySQL/MariaDB + Docker + UFW + OpenSSH + Git + Composer)
&lt;/h2&gt;

&lt;p&gt;This post shares an &lt;strong&gt;All-in-One Bash Script&lt;/strong&gt; to quickly set up a production-ready environment on &lt;strong&gt;Ubuntu 24.04&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Web Server:&lt;/strong&gt; Apache2 &lt;strong&gt;or&lt;/strong&gt; Nginx (choose one)&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Database:&lt;/strong&gt; MySQL &lt;strong&gt;or&lt;/strong&gt; MariaDB (choose one)&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;PHP-FPM:&lt;/strong&gt; Default PHP + Multi PHP (7.4–8.3 optional)&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Apache (conf-available):&lt;/strong&gt; Creates all PHP version &lt;code&gt;.conf&lt;/code&gt; files automatically, but enables only the &lt;code&gt;DEFAULT_PHP_VERSION&lt;/code&gt;&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Docker + Docker Compose (Official Repo)&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;UFW Firewall (Optional)&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;OpenSSH Server (Optional)&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Git (Optional)&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Composer (Optional)&lt;/strong&gt;  &lt;/p&gt;


&lt;h2&gt;
  
  
  ✅ Features
&lt;/h2&gt;
&lt;h3&gt;
  
  
  ✅ Web Server (Choose One)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;INSTALL_APACHE2="yes/no"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;INSTALL_NGINX="yes/no"&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ If both are &lt;code&gt;yes&lt;/code&gt;, the script will stop (port 80/443 conflict).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  ✅ Database (Choose One)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;INSTALL_MYSQL="yes/no"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;INSTALL_MARIADB="yes/no"&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ If both are &lt;code&gt;yes&lt;/code&gt;, the script will stop to avoid conflicts.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  ✅ OpenSSH (Optional)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;INSTALL_OPENSSH="yes/no"&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Installs and enables &lt;code&gt;openssh-server&lt;/code&gt; (useful for fresh VPS setups).&lt;/p&gt;
&lt;h3&gt;
  
  
  ✅ Git (Optional)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;INSTALL_GIT="yes/no"&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Installs &lt;code&gt;git&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  ✅ Composer (Optional)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;INSTALL_COMPOSER="yes/no"&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Installs Composer globally as &lt;code&gt;/usr/local/bin/composer&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;✅ Composer requires PHP CLI to be available.&lt;br&gt;&lt;br&gt;
If you disable both Apache and Nginx, PHP might not be installed and Composer installation will be skipped.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  ✅ PHP-FPM Multi-Version Support
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DEFAULT_PHP_VERSION="8.4"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ENABLE_MULTI_PHP_FPM="yes/no"&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ For &lt;strong&gt;Apache&lt;/strong&gt;, the script auto-creates configs inside:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/etc/apache2/conf-available/php7.4-fpm.conf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/etc/apache2/conf-available/php8.0-fpm.conf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/etc/apache2/conf-available/php8.1-fpm.conf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/etc/apache2/conf-available/php8.2-fpm.conf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/etc/apache2/conf-available/php8.3-fpm.conf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/etc/apache2/conf-available/php8.4-fpm.conf&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ But enables only:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;a2enconf php8.4-fpm&lt;/code&gt; (or your selected default)&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  ✅ Recommended Default Setup (Example)
&lt;/h2&gt;
&lt;h3&gt;
  
  
  ✅ Nginx + MariaDB + Docker + OpenSSH + Git + Composer
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;INSTALL_APACHE2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"yes"&lt;/span&gt;
&lt;span class="nv"&gt;INSTALL_NGINX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"no"&lt;/span&gt;

&lt;span class="nv"&gt;INSTALL_MYSQL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"yes"&lt;/span&gt;
&lt;span class="nv"&gt;INSTALL_MARIADB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"no"&lt;/span&gt;

&lt;span class="nv"&gt;INSTALL_DOCKER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"yes"&lt;/span&gt;
&lt;span class="nv"&gt;INSTALL_OPENSSH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"yes"&lt;/span&gt;
&lt;span class="nv"&gt;INSTALL_GIT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"yes"&lt;/span&gt;
&lt;span class="nv"&gt;INSTALL_COMPOSER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"yes"&lt;/span&gt;
&lt;span class="nv"&gt;ENABLE_UFW&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"yes"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ⚠️ Security Note (Important)
&lt;/h2&gt;

&lt;p&gt;This script creates &lt;code&gt;/var/www/html/info.php&lt;/code&gt; for testing &lt;code&gt;phpinfo()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;✅ After testing, delete it immediately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo rm&lt;/span&gt; /var/www/html/info.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ✅ The Full Script (Copy &amp;amp; Run)
&lt;/h2&gt;

&lt;p&gt;✅ Save as: &lt;code&gt;full_setup_ubuntu24.sh&lt;/code&gt;&lt;br&gt;&lt;br&gt;
✅ Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;bash full_setup_ubuntu24.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="c"&gt;# CONFIG (EDIT THESE)&lt;/span&gt;
&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"8.4"&lt;/span&gt;            &lt;span class="c"&gt;# Default PHP-FPM version for Web Server&lt;/span&gt;
&lt;span class="nv"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"12345"&lt;/span&gt;          &lt;span class="c"&gt;# Change this&lt;/span&gt;

&lt;span class="nv"&gt;ENABLE_MULTI_PHP_FPM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"yes"&lt;/span&gt;           &lt;span class="c"&gt;# yes/no (install &amp;amp; enable multiple FPM versions)&lt;/span&gt;
&lt;span class="nv"&gt;INSTALL_PHPMYADMIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"no"&lt;/span&gt;              &lt;span class="c"&gt;# yes/no&lt;/span&gt;
&lt;span class="nv"&gt;ENABLE_UFW&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"yes"&lt;/span&gt;                     &lt;span class="c"&gt;# yes/no&lt;/span&gt;

&lt;span class="nv"&gt;INSTALL_OPENSSH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"yes"&lt;/span&gt;                &lt;span class="c"&gt;# yes/no&lt;/span&gt;
&lt;span class="nv"&gt;INSTALL_GIT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"yes"&lt;/span&gt;                    &lt;span class="c"&gt;# yes/no&lt;/span&gt;
&lt;span class="nv"&gt;INSTALL_COMPOSER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"yes"&lt;/span&gt;               &lt;span class="c"&gt;# yes/no&lt;/span&gt;

&lt;span class="nv"&gt;INSTALL_APACHE2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"yes"&lt;/span&gt;                 &lt;span class="c"&gt;# yes/no&lt;/span&gt;
&lt;span class="nv"&gt;INSTALL_NGINX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"no"&lt;/span&gt;                  &lt;span class="c"&gt;# yes/no&lt;/span&gt;

&lt;span class="nv"&gt;INSTALL_MYSQL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"yes"&lt;/span&gt;                   &lt;span class="c"&gt;# yes/no&lt;/span&gt;
&lt;span class="nv"&gt;INSTALL_MARIADB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"no"&lt;/span&gt;                &lt;span class="c"&gt;# yes/no&lt;/span&gt;
&lt;span class="nv"&gt;INSTALL_DOCKER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"yes"&lt;/span&gt;                 &lt;span class="c"&gt;# yes/no&lt;/span&gt;
&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"==========================================="&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;" Ubuntu 24.04 Full Setup Script"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;" OpenSSH Install: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_OPENSSH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;" Git Install:     &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_GIT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;" Composer Install:&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_COMPOSER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;" Apache Install:  &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_APACHE2&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;" Nginx Install:   &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_NGINX&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;" MySQL Install:   &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_MYSQL&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;" MariaDB Install: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_MARIADB&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;" Docker Install:  &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_DOCKER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;" Default PHP:     PHP &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"==========================================="&lt;/span&gt;

&lt;span class="c"&gt;# Check root&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$EUID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-ne&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"❌ Please run as root: sudo bash full_setup_ubuntu24.sh"&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Conflict checks&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_MYSQL&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_MARIADB&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"❌ ERROR: You cannot install both MySQL and MariaDB together."&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"   Set either INSTALL_MYSQL=yes OR INSTALL_MARIADB=yes"&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_APACHE2&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_NGINX&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"❌ ERROR: You cannot enable both Apache and Nginx together (port 80/443 conflict)."&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"   Set either INSTALL_APACHE2=yes OR INSTALL_NGINX=yes"&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Updating system..."&lt;/span&gt;
apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Installing basic tools..."&lt;/span&gt;
apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; software-properties-common curl ca-certificates gnupg lsb-release unzip

&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="c"&gt;# OpenSSH Install (Optional)&lt;/span&gt;
&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_OPENSSH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Installing OpenSSH Server..."&lt;/span&gt;
  apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; openssh-server
  systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; ssh
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"⏭️ Skipping OpenSSH installation..."&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="c"&gt;# Git Install (Optional)&lt;/span&gt;
&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_GIT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Installing Git..."&lt;/span&gt;
  apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; git
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"⏭️ Skipping Git installation..."&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="c"&gt;# Apache2 Install (Optional)&lt;/span&gt;
&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_APACHE2&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Installing Apache2..."&lt;/span&gt;
  apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; apache2
  systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; apache2

  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Enabling Apache modules for PHP-FPM..."&lt;/span&gt;
  apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; libapache2-mod-fcgid
  a2enmod proxy_fcgi setenvif
  systemctl restart apache2
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"⏭️ Skipping Apache2 installation..."&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="c"&gt;# Nginx Install (Optional)&lt;/span&gt;
&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_NGINX&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Installing Nginx..."&lt;/span&gt;
  apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; nginx
  systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; nginx
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"⏭️ Skipping Nginx installation..."&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="c"&gt;# MySQL Install (Optional)&lt;/span&gt;
&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_MYSQL&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Installing MySQL Server..."&lt;/span&gt;
  apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; mysql-server
  systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; mysql

  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Setting MySQL root password + mysql_native_password..."&lt;/span&gt;
  mysql &lt;span class="nt"&gt;-u&lt;/span&gt; root &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;MYSQL_SCRIPT&lt;/span&gt;&lt;span class="sh"&gt;
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;';
FLUSH PRIVILEGES;
&lt;/span&gt;&lt;span class="no"&gt;MYSQL_SCRIPT

&lt;/span&gt;  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Testing MySQL root login..."&lt;/span&gt;
  mysql &lt;span class="nt"&gt;-u&lt;/span&gt; root &lt;span class="nt"&gt;-p&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"SELECT 1;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"⏭️ Skipping MySQL installation..."&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="c"&gt;# MariaDB Install (Optional)&lt;/span&gt;
&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_MARIADB&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Installing MariaDB Server..."&lt;/span&gt;
  apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; mariadb-server
  systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; mariadb

  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Setting MariaDB root password..."&lt;/span&gt;
  mariadb &lt;span class="nt"&gt;-u&lt;/span&gt; root &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;MARIADB_SCRIPT&lt;/span&gt;&lt;span class="sh"&gt;
ALTER USER 'root'@'localhost' IDENTIFIED BY '&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;';
FLUSH PRIVILEGES;
&lt;/span&gt;&lt;span class="no"&gt;MARIADB_SCRIPT

&lt;/span&gt;  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Testing MariaDB root login..."&lt;/span&gt;
  mariadb &lt;span class="nt"&gt;-u&lt;/span&gt; root &lt;span class="nt"&gt;-p&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"SELECT 1;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"⏭️ Skipping MariaDB installation..."&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="c"&gt;# PHP Install (Ondrej PPA)&lt;/span&gt;
&lt;span class="c"&gt;# Only if Apache or Nginx is installed&lt;/span&gt;
&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="nv"&gt;PHP_INSTALLED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"no"&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_APACHE2&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_NGINX&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nv"&gt;PHP_INSTALLED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"yes"&lt;/span&gt;

  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Adding PHP PPA (ondrej/php)..."&lt;/span&gt;
  add-apt-repository ppa:ondrej/php &lt;span class="nt"&gt;-y&lt;/span&gt;
  apt update &lt;span class="nt"&gt;-y&lt;/span&gt;

  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Installing Default PHP &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (FPM + extensions + opcache)..."&lt;/span&gt;
  apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-fpm&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-cli&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-common&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-mysql&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-curl&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-mbstring&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-xml&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-zip&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-gd&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-intl&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-bcmath&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-opcache&lt;/span&gt;

  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Enabling PHP-FPM service for &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;..."&lt;/span&gt;
  systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-fpm&lt;/span&gt;

  &lt;span class="c"&gt;# Optional: Multi PHP-FPM&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ENABLE_MULTI_PHP_FPM&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Installing multiple PHP-FPM versions..."&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;v &lt;span class="k"&gt;in &lt;/span&gt;7.4 8.0 8.1 8.2 8.3&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
      &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"➡️ Installing PHP &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; FPM..."&lt;/span&gt;
      apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-fpm&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-cli&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-common&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-mysql&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-curl&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-mbstring&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-xml&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-zip&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-gd&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-intl&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-bcmath&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-opcache&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true

      &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-fpm&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
    &lt;/span&gt;&lt;span class="k"&gt;done
  fi&lt;/span&gt;

  &lt;span class="c"&gt;# Set CLI default PHP&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Setting CLI default PHP to &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;..."&lt;/span&gt;
  update-alternatives &lt;span class="nt"&gt;--set&lt;/span&gt; php /usr/bin/php&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
  &lt;/span&gt;update-alternatives &lt;span class="nt"&gt;--set&lt;/span&gt; phar /usr/bin/phar&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
  &lt;/span&gt;update-alternatives &lt;span class="nt"&gt;--set&lt;/span&gt; phar.phar /usr/bin/phar.phar&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
  &lt;/span&gt;update-alternatives &lt;span class="nt"&gt;--set&lt;/span&gt; phpize /usr/bin/phpize&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
  &lt;/span&gt;update-alternatives &lt;span class="nt"&gt;--set&lt;/span&gt; php-config /usr/bin/php-config&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
&lt;/span&gt;&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"⏭️ Skipping PHP installation because both Apache &amp;amp; Nginx are disabled..."&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="c"&gt;# Composer Install (Optional)&lt;/span&gt;
&lt;span class="c"&gt;# Requires PHP CLI&lt;/span&gt;
&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_COMPOSER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  if &lt;/span&gt;&lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; php &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Installing Composer..."&lt;/span&gt;

    &lt;span class="nv"&gt;EXPECTED_CHECKSUM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;php &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'copy("https://composer.github.io/installer.sig", "php://stdout");'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    php &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"copy('https://getcomposer.org/installer', 'composer-setup.php');"&lt;/span&gt;

    &lt;span class="nv"&gt;ACTUAL_CHECKSUM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;php &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"echo hash_file('sha384', 'composer-setup.php');"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$EXPECTED_CHECKSUM&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ACTUAL_CHECKSUM&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
      &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"❌ ERROR: Invalid Composer installer checksum"&lt;/span&gt;
      &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; composer-setup.php
      &lt;span class="nb"&gt;exit &lt;/span&gt;1
    &lt;span class="k"&gt;fi

    &lt;/span&gt;php composer-setup.php &lt;span class="nt"&gt;--quiet&lt;/span&gt; &lt;span class="nt"&gt;--install-dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/local/bin &lt;span class="nt"&gt;--filename&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;composer
    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; composer-setup.php

    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Composer installed: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;composer &lt;span class="nt"&gt;--version&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"⚠️ Composer requested but PHP is not installed. Skipping Composer..."&lt;/span&gt;
  &lt;span class="k"&gt;fi
else
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"⏭️ Skipping Composer installation..."&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="c"&gt;# Apache PHP-FPM conf setup&lt;/span&gt;
&lt;span class="c"&gt;# conf-available create all versions, enable only default&lt;/span&gt;
&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_APACHE2&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Creating Apache PHP-FPM conf files in conf-available..."&lt;/span&gt;

  &lt;span class="nv"&gt;PHP_VERSIONS&lt;/span&gt;&lt;span class="o"&gt;=()&lt;/span&gt;
  PHP_VERSIONS+&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ENABLE_MULTI_PHP_FPM&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;PHP_VERSIONS+&lt;span class="o"&gt;=(&lt;/span&gt;7.4 8.0 8.1 8.2 8.3&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;fi

  &lt;/span&gt;&lt;span class="nv"&gt;PHP_VERSIONS&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PHP_VERSIONS&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;v &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PHP_VERSIONS&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nv"&gt;PHP_CONF&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/etc/apache2/conf-available/php&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-fpm.conf"&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"➡️ Creating: &lt;/span&gt;&lt;span class="nv"&gt;$PHP_CONF&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

    &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PHP_CONF&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
# Auto-generated PHP-FPM config: PHP &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
&amp;lt;IfModule proxy_fcgi_module&amp;gt;
    &amp;lt;FilesMatch &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="sh"&gt;.php&lt;/span&gt;&lt;span class="nv"&gt;$&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;
        SetHandler "proxy:unix:/run/php/php&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;-fpm.sock|fcgi://localhost/"
    &amp;lt;/FilesMatch&amp;gt;
&amp;lt;/IfModule&amp;gt;
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;  &lt;span class="k"&gt;done

  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Disabling other PHP-FPM confs (avoid conflict)..."&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;v &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PHP_VERSIONS&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
      &lt;/span&gt;a2disconf &lt;span class="s2"&gt;"php&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-fpm"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1 &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
    &lt;/span&gt;&lt;span class="k"&gt;fi
  done

  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Enabling only default PHP-FPM conf: php&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-fpm"&lt;/span&gt;
  a2enconf &lt;span class="s2"&gt;"php&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-fpm"&lt;/span&gt;

  systemctl reload apache2
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="c"&gt;# Nginx PHP-FPM config setup&lt;/span&gt;
&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_NGINX&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Configuring Nginx for PHP-FPM (default PHP &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)..."&lt;/span&gt;

  &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /etc/nginx/sites-enabled/default

  &lt;span class="nv"&gt;NGINX_SITE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/etc/nginx/sites-available/default-php-fpm"&lt;/span&gt;

  &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NGINX_SITE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/html;
    index index.php index.html index.htm;

    server_name _;

    location / {
        try_files &lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="sh"&gt;uri &lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="sh"&gt;uri/ =404;
    }

    location ~ &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="sh"&gt;.php&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="sh"&gt; {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_PHP_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;-fpm.sock;
    }

    location ~ /&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="sh"&gt;.ht {
        deny all;
    }
}
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;  &lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-sf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NGINX_SITE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; /etc/nginx/sites-enabled/default-php-fpm

  nginx &lt;span class="nt"&gt;-t&lt;/span&gt;
  systemctl reload nginx
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="c"&gt;# PHP Info test file&lt;/span&gt;
&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_APACHE2&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_NGINX&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Creating PHP test file: /var/www/html/info.php"&lt;/span&gt;
  &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /var/www/html/info.php &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
&amp;lt;?php
phpinfo();
?&amp;gt;
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="c"&gt;# Optional: phpMyAdmin&lt;/span&gt;
&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_PHPMYADMIN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Installing phpMyAdmin..."&lt;/span&gt;
  apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; phpmyadmin &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true

  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_APACHE2&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;systemctl reload apache2
  &lt;span class="k"&gt;fi

  if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_NGINX&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;systemctl reload nginx
  &lt;span class="k"&gt;fi
fi&lt;/span&gt;

&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="c"&gt;# Docker Install (Optional)&lt;/span&gt;
&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_DOCKER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Installing Docker + Docker Compose (official)..."&lt;/span&gt;

  &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; 0755 &lt;span class="nt"&gt;-d&lt;/span&gt; /etc/apt/keyrings
  &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /etc/apt/keyrings/docker.gpg

  curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://download.docker.com/linux/ubuntu/gpg | gpg &lt;span class="nt"&gt;--dearmor&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /etc/apt/keyrings/docker.gpg
  &lt;span class="nb"&gt;chmod &lt;/span&gt;a+r /etc/apt/keyrings/docker.gpg

  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"deb [arch=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;dpkg &lt;span class="nt"&gt;--print-architecture&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; signed-by=/etc/apt/keyrings/docker.gpg] &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
  https://download.docker.com/linux/ubuntu &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
  &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; /etc/os-release &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$VERSION_CODENAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; stable"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /etc/apt/sources.list.d/docker.list

  apt update &lt;span class="nt"&gt;-y&lt;/span&gt;
  apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
  systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; docker

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SUDO_USER&lt;/span&gt;&lt;span class="k"&gt;:-}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Adding user '&lt;/span&gt;&lt;span class="nv"&gt;$SUDO_USER&lt;/span&gt;&lt;span class="s2"&gt;' to docker group..."&lt;/span&gt;
    usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; docker &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SUDO_USER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;fi
else
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"⏭️ Skipping Docker installation..."&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="c"&gt;# UFW Firewall (Optional)&lt;/span&gt;
&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ENABLE_UFW&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Setting up UFW firewall..."&lt;/span&gt;
  apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; ufw

  &lt;span class="c"&gt;# Only allow SSH if OpenSSH install enabled&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_OPENSSH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;ufw allow OpenSSH
  &lt;span class="k"&gt;fi

  &lt;/span&gt;ufw allow 80/tcp
  ufw allow 443/tcp

  ufw &lt;span class="nt"&gt;--force&lt;/span&gt; &lt;span class="nb"&gt;enable
  &lt;/span&gt;ufw status verbose
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="c"&gt;# Finished Summary&lt;/span&gt;
&lt;span class="c"&gt;# -----------------------------&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"==========================================="&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ INSTALLATION COMPLETE!"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"==========================================="&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"OpenSSH Installed: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_OPENSSH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Git Installed:     &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_GIT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Composer Installed:&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_COMPOSER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Apache Installed:  &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_APACHE2&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Nginx Installed:   &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_NGINX&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"MySQL Installed:   &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_MYSQL&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"MariaDB Installed: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_MARIADB&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Docker Installed:  &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INSTALL_DOCKER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"OpenSSH:    systemctl status ssh"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Apache:     systemctl status apache2"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Nginx:      systemctl status nginx"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"MySQL:      systemctl status mysql"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"MariaDB:    systemctl status mariadb"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"PHP (CLI):  php -v | head -n 1"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Git:        git --version"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Composer:   composer --version"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Docker:     docker --version"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Compose:    docker compose version"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"🔑 DB root password set to:"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"   &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ PHP test page (if web server installed):"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"   http://YOUR_SERVER_IP/info.php"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"⚠️ IMPORTANT: Delete info.php after testing:"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"   sudo rm /var/www/html/info.php"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ If Docker group added, logout/login required for it to work without sudo."&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"==========================================="&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ✅ Quick Troubleshooting
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✅ Check services
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl status ssh
systemctl status nginx
systemctl status apache2
systemctl status mariadb
systemctl status mysql
systemctl status php8.4-fpm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ✅ Check open ports
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ss &lt;span class="nt"&gt;-tulpn&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'(:22|:80|:443|:3306)'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ✅ Done ✅
&lt;/h2&gt;

&lt;p&gt;If you want, I can add these in the next version:&lt;/p&gt;

&lt;p&gt;✅ &lt;code&gt;INSTALL_SSL_CERTBOT="yes/no"&lt;/code&gt; (Let’s Encrypt auto SSL)&lt;br&gt;&lt;br&gt;
✅ &lt;code&gt;INSTALL_REDIS="yes/no"&lt;/code&gt;&lt;br&gt;&lt;br&gt;
✅ &lt;code&gt;INSTALL_FAIL2BAN="yes/no"&lt;/code&gt;&lt;br&gt;&lt;br&gt;
✅ per-site multi PHP config templates  &lt;/p&gt;

&lt;p&gt;Happy Hosting 🚀&lt;/p&gt;

</description>
      <category>ubuntu</category>
      <category>docker</category>
      <category>php</category>
      <category>mysql</category>
    </item>
    <item>
      <title>Complete Step-by-Step Jenkins CI/CD Deployment on Ubuntu with GitLab</title>
      <dc:creator>M. K. Tanjin Sarker</dc:creator>
      <pubDate>Thu, 25 Sep 2025 10:12:33 +0000</pubDate>
      <link>https://dev.to/tanjinsarker/gitlabjenkins-cicd-4hf0</link>
      <guid>https://dev.to/tanjinsarker/gitlabjenkins-cicd-4hf0</guid>
      <description>&lt;h2&gt;
  
  
  Step 1: Update Ubuntu &amp;amp; Install Dependencies
&lt;/h2&gt;

&lt;p&gt;Install Java 17 (required by Jenkins), &lt;code&gt;curl&lt;/code&gt;, and other dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; openjdk-17-jdk curl gnupg2 apt-transport-https software-properties-common
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 2: Add Jenkins Repository
&lt;/h2&gt;

&lt;p&gt;Add the Jenkins GPG key and repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://pkg.jenkins.io/debian/jenkins.io-2023.key | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    /usr/share/keyrings/jenkins-keyring.asc &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null

&lt;span class="nb"&gt;echo &lt;/span&gt;deb &lt;span class="o"&gt;[&lt;/span&gt;signed-by&lt;span class="o"&gt;=&lt;/span&gt;/usr/share/keyrings/jenkins-keyring.asc] https://pkg.jenkins.io/debian binary/ | &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/apt/sources.list.d/jenkins.list &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 3: Install Jenkins
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; jenkins
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 4: Start &amp;amp; Enable Jenkins
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start jenkins
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;jenkins
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl status jenkins
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Default Jenkins runs on port &lt;code&gt;8080&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;To change the port:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/default/jenkins
&lt;span class="c"&gt;# Change HTTP_PORT=8080 to HTTP_PORT=8008&lt;/span&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /lib/systemd/system/jenkins.service
&lt;span class="c"&gt;# Add Environment="JENKINS_PORT=8008"&lt;/span&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl daemon-reload
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart jenkins
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Verify port:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ss &lt;span class="nt"&gt;-tulnp&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;jenkins
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Allow firewall access:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Open Jenkins in your browser: &lt;code&gt;http://&amp;lt;jenkins-server-ip&amp;gt;:8080&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 5: Unlock Jenkins
&lt;/h2&gt;

&lt;p&gt;Get the initial admin password:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo cat&lt;/span&gt; /var/lib/jenkins/secrets/initialAdminPassword
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use this password to login via the browser.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 6: Install Recommended Plugins
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Choose &lt;strong&gt;Install suggested plugins&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Create the first admin user and continue.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 7: Install Essential Plugins
&lt;/h2&gt;

&lt;p&gt;Go to &lt;strong&gt;Manage Jenkins → Plugins → Available&lt;/strong&gt; and install:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitLab&lt;/li&gt;
&lt;li&gt;SSH Agent&lt;/li&gt;
&lt;li&gt;GitLab API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Restart Jenkins after installation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 8: Setup SSH Access for Deployment
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Generate SSH key for Jenkins user:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; rsa &lt;span class="nt"&gt;-b&lt;/span&gt; 4096 &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"jenkins@jenkins-server"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Copy the public key to your application server:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-copy-id user@application-server-ip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Test password-less login:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh user@application-server-ip &lt;span class="s2"&gt;"ls -la"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 9: Add SSH Key to Jenkins Credentials
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Manage Jenkins → Credentials → Global → Add Credentials&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Configure as:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Kind:&lt;/strong&gt; SSH Username with private key
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scope:&lt;/strong&gt; Global
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ID:&lt;/strong&gt; &lt;code&gt;deploy-private-key&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Username:&lt;/strong&gt; &lt;code&gt;root&lt;/code&gt; (or your server user)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Private Key:&lt;/strong&gt; Enter directly (paste your &lt;code&gt;~/.ssh/id_rsa&lt;/code&gt;)
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Step 10: Add GitLab Access Token
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;In GitLab → &lt;strong&gt;Settings → Personal Access Tokens&lt;/strong&gt;, create a token:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Token Name:&lt;/strong&gt; &lt;code&gt;jenkins-server&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expiration Date:&lt;/strong&gt; As desired
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scopes:&lt;/strong&gt; Check &lt;strong&gt;API&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Copy the generated token.&lt;/li&gt;
&lt;li&gt;In Jenkins, add it as a credential:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Kind:&lt;/strong&gt; GitLab API token
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Token:&lt;/strong&gt; Paste the token
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ID:&lt;/strong&gt; &lt;code&gt;gitlab-access-token&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Configure GitLab connection in Jenkins:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Connection Name:&lt;/strong&gt; &lt;code&gt;gitlab.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitLab Host URL:&lt;/strong&gt; &lt;code&gt;https://gitlab.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Credential:&lt;/strong&gt; &lt;code&gt;gitlab-access-token&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Apply/Save&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Step 11: Add Application Server SSH Key to GitLab
&lt;/h2&gt;

&lt;p&gt;On your application server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; rsa &lt;span class="nt"&gt;-b&lt;/span&gt; 4096 &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"server.application"&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/id_rsa.pub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add this public key in GitLab: &lt;strong&gt;Preferences → SSH Keys → Add new key&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 12: Create Jenkins Pipeline Job
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;New Item → Pipeline&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Configure GitLab connection:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Triggers:&lt;/strong&gt; Check &lt;em&gt;Build when a change is pushed to GitLab&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Pipeline script example:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;

    &lt;span class="n"&gt;stages&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Deploy main'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;sshagent&lt;/span&gt;&lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'deploy-private-key'&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;sh&lt;/span&gt; &lt;span class="s2"&gt;"ssh -o StrictHostKeyChecking=no -p 22 user@application_server_ip 'cd /var/www/html/application &amp;amp;&amp;amp; git pull origin main'"&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Adjust the SSH port and paths as needed.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 13: Build &amp;amp; Deploy
&lt;/h2&gt;

&lt;p&gt;Now, whenever you push to GitLab, Jenkins will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pull the latest code from the repository
&lt;/li&gt;
&lt;li&gt;Deploy it automatically to your application server
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check the &lt;strong&gt;Build History&lt;/strong&gt; in Jenkins to verify successful deployments.&lt;/p&gt;




&lt;p&gt;✅ &lt;strong&gt;Your CI/CD pipeline is now fully functional, secure, and automated!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ubuntu</category>
      <category>cicd</category>
      <category>tutorial</category>
      <category>devops</category>
    </item>
    <item>
      <title>How to Install and Manage Multiple PHP Versions (7.4 - 8.4) on Ubuntu with Apache.</title>
      <dc:creator>M. K. Tanjin Sarker</dc:creator>
      <pubDate>Thu, 18 Sep 2025 12:27:14 +0000</pubDate>
      <link>https://dev.to/tanjinsarker/how-to-install-and-manage-multiple-php-versions-74-84-on-ubuntu-with-apache-1o12</link>
      <guid>https://dev.to/tanjinsarker/how-to-install-and-manage-multiple-php-versions-74-84-on-ubuntu-with-apache-1o12</guid>
      <description>&lt;h1&gt;
  
  
  🚀 PHP Multiple Versions (7.4 → 8.4) with Apache on Ubuntu
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1️⃣ Add PHP PPA
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; software-properties-common ca-certificates lsb-release apt-transport-https
&lt;span class="nb"&gt;sudo &lt;/span&gt;add-apt-repository &lt;span class="nt"&gt;-y&lt;/span&gt; ppa:ondrej/php
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2️⃣ Install PHP Versions
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# PHP 7.4&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; php7.4 php7.4-cli php7.4-fpm

&lt;span class="c"&gt;# PHP 8.0&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; php8.0 php8.0-cli php8.0-fpm

&lt;span class="c"&gt;# PHP 8.1&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; php8.1 php8.1-cli php8.1-fpm

&lt;span class="c"&gt;# PHP 8.2&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; php8.2 php8.2-cli php8.2-fpm

&lt;span class="c"&gt;# PHP 8.3&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; php8.3 php8.3-cli php8.3-fpm

&lt;span class="c"&gt;# PHP 8.4&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; php8.4 php8.4-cli php8.4-fpm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3️⃣ Install Important Extensions
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Replace X.X with version (7.4, 8.0, 8.1, 8.2, 8.3, 8.4)&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; phpX.X-cli phpX.X-fpm phpX.X-mysql phpX.X-xml phpX.X-curl phpX.X-mbstring phpX.X-zip phpX.X-bcmath phpX.X-gd phpX.X-intl phpX.X-readline phpX.X-soap phpX.X-opcache phpX.X-dev phpX.X-imagick phpX.X-pgsql phpX.X-sqlite3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Covers &lt;strong&gt;Laravel, Symfony, WordPress, Drupal, Magento, APIs, image processing, DB drivers, and performance&lt;/strong&gt;.  &lt;/p&gt;

&lt;h2&gt;
  
  
  4️⃣ Check Installed Versions
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php &lt;span class="nt"&gt;-v&lt;/span&gt;                              &lt;span class="c"&gt;# Current CLI version&lt;/span&gt;
update-alternatives &lt;span class="nt"&gt;--list&lt;/span&gt; php      &lt;span class="c"&gt;# All installed CLI versions&lt;/span&gt;
systemctl list-units | &lt;span class="nb"&gt;grep &lt;/span&gt;php     &lt;span class="c"&gt;# Running PHP-FPM services&lt;/span&gt;
php &lt;span class="nt"&gt;-m&lt;/span&gt;                              &lt;span class="c"&gt;# Installed extensions&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5️⃣ Switch PHP (CLI)
&lt;/h2&gt;

&lt;p&gt;Interactive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;update-alternatives &lt;span class="nt"&gt;--config&lt;/span&gt; php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Direct:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;update-alternatives &lt;span class="nt"&gt;--set&lt;/span&gt; php /usr/bin/php8.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6️⃣ Switch PHP (Apache FPM)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Enable/disable PHP-FPM
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl stop php7.4-fpm
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; php8.3-fpm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Enable Apache modules/config
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;a2enmod proxy_fcgi setenvif
&lt;span class="nb"&gt;sudo &lt;/span&gt;a2enconf php8.3-fpm
&lt;span class="nb"&gt;sudo &lt;/span&gt;a2disconf php7.4-fpm
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl reload apache2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  VirtualHost Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nl"&gt;FilesMatch&lt;/span&gt;&lt;span class="sr"&gt; \.php$&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="nc"&gt;SetHandler&lt;/span&gt; "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost/"
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nl"&gt;FilesMatch&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reload Apache:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart apache2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7️⃣ Test PHP
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;/var/www/html/info.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="nb"&gt;phpinfo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open in browser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost/info.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🔄 Quick Reference
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Switch CLI PHP&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="nb"&gt;sudo &lt;/span&gt;update-alternatives &lt;span class="nt"&gt;--config&lt;/span&gt; php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Switch Apache PHP-FPM&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl stop php8.0-fpm
  &lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start php8.2-fpm
  &lt;span class="nb"&gt;sudo &lt;/span&gt;a2enconf php8.2-fpm
  &lt;span class="nb"&gt;sudo &lt;/span&gt;a2disconf php8.0-fpm
  &lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl reload apache2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ With this setup, you can:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install &lt;strong&gt;PHP 7.4 → 8.4&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Enable required &lt;strong&gt;extensions&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Switch between versions for &lt;strong&gt;CLI &amp;amp; Apache&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Verify with &lt;code&gt;php -v&lt;/code&gt; and &lt;code&gt;phpinfo()&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ubuntu</category>
      <category>devops</category>
      <category>tutorial</category>
      <category>php</category>
    </item>
    <item>
      <title>Automating MySQL Backups with Bash Script &amp; Cron</title>
      <dc:creator>M. K. Tanjin Sarker</dc:creator>
      <pubDate>Mon, 25 Aug 2025 04:19:44 +0000</pubDate>
      <link>https://dev.to/tanjinsarker/automating-mysql-backups-with-bash-script-cron-40oc</link>
      <guid>https://dev.to/tanjinsarker/automating-mysql-backups-with-bash-script-cron-40oc</guid>
      <description>&lt;h1&gt;
  
  
  🚀 Automating MySQL Backups with Bash Script &amp;amp; Cron
&lt;/h1&gt;

&lt;p&gt;Databases are the heart of most applications—and losing them can be a nightmare. Manual backups work for quick fixes, but in production environments, &lt;strong&gt;automated MySQL backups&lt;/strong&gt; are essential.  &lt;/p&gt;

&lt;p&gt;In this guide, we’ll build a &lt;strong&gt;simple Bash script&lt;/strong&gt; to back up MySQL databases, compress them, keep them for a fixed number of days, and schedule it with &lt;code&gt;cron&lt;/code&gt;.  &lt;/p&gt;




&lt;h2&gt;
  
  
  🔑 Why Automate Backups?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✅ Ensures you always have a recent copy of your data
&lt;/li&gt;
&lt;li&gt;✅ Reduces risk of human error
&lt;/li&gt;
&lt;li&gt;✅ Saves time compared to manual exports
&lt;/li&gt;
&lt;li&gt;✅ Easy to restore when disaster strikes
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🛠 Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A Linux server with MySQL/MariaDB installed
&lt;/li&gt;
&lt;li&gt;A user with access to all databases you want to back up
&lt;/li&gt;
&lt;li&gt;Basic knowledge of shell commands
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  1) Login as Root
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2) Create a Backup Folder &amp;amp; Script File
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /home/backup
&lt;span class="nb"&gt;touch&lt;/span&gt; /home/backup/backup-mysql.sh
nano /home/backup/backup-mysql.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3.1) Add the Backup Script for all Databases.
&lt;/h2&gt;

&lt;p&gt;Paste this inside the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;#----------------------------------------&lt;/span&gt;
&lt;span class="c"&gt;# MySQL Backup Script&lt;/span&gt;
&lt;span class="c"&gt;#----------------------------------------&lt;/span&gt;

&lt;span class="c"&gt;# 🔧 Configuration&lt;/span&gt;
&lt;span class="nv"&gt;HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'mysql-localhost'&lt;/span&gt;      &lt;span class="c"&gt;# MySQL server host&lt;/span&gt;
&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'mysql-username'&lt;/span&gt;       &lt;span class="c"&gt;# Username&lt;/span&gt;
&lt;span class="nv"&gt;PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'mysql-password'&lt;/span&gt;   &lt;span class="c"&gt;# Password&lt;/span&gt;
&lt;span class="nv"&gt;DAYS_TO_KEEP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5              &lt;span class="c"&gt;# Delete backups older than X days&lt;/span&gt;
&lt;span class="nv"&gt;GZIP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1                      &lt;span class="c"&gt;# 1 = gzip compression, 0 = plain .sql&lt;/span&gt;
&lt;span class="nv"&gt;BACKUP_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'/home/backup/mysql'&lt;/span&gt;   &lt;span class="c"&gt;# Location to store backups&lt;/span&gt;
&lt;span class="c"&gt;#TIMESTAMP=$(date +"%d_%m_%Y_%H_%M_%S")   # Date-time for unique file names&lt;/span&gt;
&lt;span class="nv"&gt;TIMESTAMP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"yesterday"&lt;/span&gt; +&lt;span class="s2"&gt;"%d_%m_%Y"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="c"&gt;#Date-time for previous date file names. reminder here crontab use after 12 am&lt;/span&gt;

&lt;span class="c"&gt;#----------------------------------------&lt;/span&gt;

&lt;span class="c"&gt;# 📂 Create backup folder if not exists&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# 📋 Get database list&lt;/span&gt;
&lt;span class="nv"&gt;databases&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;mysql &lt;span class="nt"&gt;-h&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOST&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$USER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PASSWORD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"SHOW DATABASES;"&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"|"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; Database&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# 🔄 Loop through databases&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;DB &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;$databases&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c"&gt;# Skip system databases&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DB&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'information_schema'&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DB&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'performance_schema'&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DB&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'mysql'&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DB&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'sys'&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Skipping database: &lt;/span&gt;&lt;span class="nv"&gt;$DB&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;continue
  fi&lt;/span&gt;

  &lt;span class="c"&gt;# Backup (with or without compression)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$GZIP&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Backing up database: &lt;/span&gt;&lt;span class="nv"&gt;$DB&lt;/span&gt;&lt;span class="s2"&gt; (no compression)"&lt;/span&gt;
    mysqldump &lt;span class="nt"&gt;-h&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOST&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$USER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PASSWORD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--databases&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DB&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--single-transaction&lt;/span&gt; &lt;span class="nt"&gt;--quick&lt;/span&gt; &lt;span class="nt"&gt;--extended-insert&lt;/span&gt; &lt;span class="nt"&gt;--compact&lt;/span&gt; &lt;span class="nt"&gt;--hex-blob&lt;/span&gt; &lt;span class="nt"&gt;--max-allowed-packet&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;256M &lt;span class="nt"&gt;--net-buffer-length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2M &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_PATH&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DB&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TIMESTAMP&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.sql"&lt;/span&gt;
  &lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Backing up database: &lt;/span&gt;&lt;span class="nv"&gt;$DB&lt;/span&gt;&lt;span class="s2"&gt; (with compression)"&lt;/span&gt;
    mysqldump &lt;span class="nt"&gt;-h&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOST&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$USER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PASSWORD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--databases&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DB&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--single-transaction&lt;/span&gt; &lt;span class="nt"&gt;--quick&lt;/span&gt; &lt;span class="nt"&gt;--extended-insert&lt;/span&gt; &lt;span class="nt"&gt;--compact&lt;/span&gt; &lt;span class="nt"&gt;--hex-blob&lt;/span&gt; &lt;span class="nt"&gt;--max-allowed-packet&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;256M &lt;span class="nt"&gt;--net-buffer-length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2M | &lt;span class="nb"&gt;gzip&lt;/span&gt; &lt;span class="nt"&gt;-9&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_PATH&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DB&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TIMESTAMP&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.sql.gz"&lt;/span&gt;
  &lt;span class="k"&gt;fi
done&lt;/span&gt;

&lt;span class="c"&gt;# 🧹 Delete old backups&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DAYS_TO_KEEP&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-gt&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Deleting backups older than &lt;/span&gt;&lt;span class="nv"&gt;$DAYS_TO_KEEP&lt;/span&gt;&lt;span class="s2"&gt; days"&lt;/span&gt;
  find &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="nt"&gt;-mtime&lt;/span&gt; +&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DAYS_TO_KEEP&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-exec&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3.2) Add the Backup Script for single Database.
&lt;/h2&gt;

&lt;p&gt;Paste this inside the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;#----------------------------------------&lt;/span&gt;
&lt;span class="c"&gt;# MySQL Backup Script&lt;/span&gt;
&lt;span class="c"&gt;#----------------------------------------&lt;/span&gt;

&lt;span class="c"&gt;# 🔧 Configuration&lt;/span&gt;
&lt;span class="nv"&gt;HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'mysql-localhost'&lt;/span&gt;      &lt;span class="c"&gt;# MySQL server host&lt;/span&gt;
&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'mysql-username'&lt;/span&gt;       &lt;span class="c"&gt;# Username&lt;/span&gt;
&lt;span class="nv"&gt;PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'mysql-password'&lt;/span&gt;   &lt;span class="c"&gt;# Password&lt;/span&gt;
&lt;span class="nv"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'mysql-database'&lt;/span&gt;
&lt;span class="nv"&gt;DAYS_TO_KEEP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5              &lt;span class="c"&gt;# Delete backups older than X days&lt;/span&gt;
&lt;span class="nv"&gt;GZIP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1                      &lt;span class="c"&gt;# 1 = gzip compression, 0 = plain .sql&lt;/span&gt;
&lt;span class="nv"&gt;BACKUP_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'/home/backup/mysql'&lt;/span&gt;   &lt;span class="c"&gt;# Location to store backups&lt;/span&gt;
&lt;span class="c"&gt;#TIMESTAMP=$(date +"%d_%m_%Y_%H_%M_%S")   # Date-time for unique file names&lt;/span&gt;
&lt;span class="nv"&gt;TIMESTAMP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"yesterday"&lt;/span&gt; +&lt;span class="s2"&gt;"%d_%m_%Y"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="c"&gt;#Date-time for previous date file names. reminder here crontab use after 12 am&lt;/span&gt;

&lt;span class="c"&gt;#----------------------------------------&lt;/span&gt;

&lt;span class="c"&gt;# Create the backup folder&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;$BACKUP_PATH&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;$BACKUP_PATH&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;


  &lt;span class="c"&gt;# Backup (with or without compression)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$GZIP&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Backing up database: &lt;/span&gt;&lt;span class="nv"&gt;$DB&lt;/span&gt;&lt;span class="s2"&gt; (no compression)"&lt;/span&gt;
    mysqldump &lt;span class="nt"&gt;-h&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOST&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$USER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PASSWORD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--databases&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DB&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--single-transaction&lt;/span&gt; &lt;span class="nt"&gt;--quick&lt;/span&gt; &lt;span class="nt"&gt;--extended-insert&lt;/span&gt; &lt;span class="nt"&gt;--compact&lt;/span&gt; &lt;span class="nt"&gt;--hex-blob&lt;/span&gt; &lt;span class="nt"&gt;--max-allowed-packet&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;256M &lt;span class="nt"&gt;--net-buffer-length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2M &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_PATH&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DB&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TIMESTAMP&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.sql"&lt;/span&gt;
  &lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Backing up database: &lt;/span&gt;&lt;span class="nv"&gt;$DB&lt;/span&gt;&lt;span class="s2"&gt; (with compression)"&lt;/span&gt;
    mysqldump &lt;span class="nt"&gt;-h&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOST&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$USER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PASSWORD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--databases&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DB&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--single-transaction&lt;/span&gt; &lt;span class="nt"&gt;--quick&lt;/span&gt; &lt;span class="nt"&gt;--extended-insert&lt;/span&gt; &lt;span class="nt"&gt;--compact&lt;/span&gt; &lt;span class="nt"&gt;--hex-blob&lt;/span&gt; &lt;span class="nt"&gt;--max-allowed-packet&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;256M &lt;span class="nt"&gt;--net-buffer-length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2M | &lt;span class="nb"&gt;gzip&lt;/span&gt; &lt;span class="nt"&gt;-9&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_PATH&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DB&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TIMESTAMP&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.sql.gz"&lt;/span&gt;
  &lt;span class="k"&gt;fi&lt;/span&gt;


&lt;span class="c"&gt;# Delete old backups&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DAYS_TO_KEEP&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-gt&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Deleting backups older than &lt;/span&gt;&lt;span class="nv"&gt;$DAYS_TO_KEEP&lt;/span&gt;&lt;span class="s2"&gt; days"&lt;/span&gt;
  find &lt;span class="nv"&gt;$BACKUP_PATH&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="nt"&gt;-mtime&lt;/span&gt; +&lt;span class="nv"&gt;$DAYS_TO_KEEP&lt;/span&gt; &lt;span class="nt"&gt;-exec&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4) Make the Script Executable
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x /home/backup/backup-mysql.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5) Test the Script
&lt;/h2&gt;

&lt;p&gt;Run it manually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/home/backup/backup-mysql.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Backups will be stored inside:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/home/backup/mysql/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  6) Automate with Cron
&lt;/h2&gt;

&lt;p&gt;Open crontab:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;crontab &lt;span class="nt"&gt;-e&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add this line to run the backup daily at &lt;strong&gt;2:30 AM&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;30 2 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; /home/backup/backup-mysql.sh &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart cron service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart cron
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧠 How It Works (Script Breakdown)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Configuration variables&lt;/strong&gt; → Define MySQL credentials, backup path, retention days.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timestamp&lt;/strong&gt; → Ensures unique filenames (&lt;code&gt;dbname-24_08_2025_02_30_00.sql.gz&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timestamp&lt;/strong&gt; → Ensures previous filenames (&lt;code&gt;dbname-24_08_2025.sql.gz&lt;/code&gt;). &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database filtering&lt;/strong&gt; → Skips system databases (&lt;code&gt;information_schema&lt;/code&gt;, etc.).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;mysqldump with &lt;code&gt;--single-transaction&lt;/code&gt;&lt;/strong&gt; → Ensures consistent snapshot for InnoDB without locking tables.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;gzip compression&lt;/strong&gt; → Saves space.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retention policy (&lt;code&gt;find -mtime&lt;/code&gt;)&lt;/strong&gt; → Deletes backups older than 5 days.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ✅ Conclusion
&lt;/h2&gt;

&lt;p&gt;With just a few lines of Bash and a cron job, you’ve automated MySQL backups.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Backups run &lt;strong&gt;every day at 2:30 AM&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Old backups &lt;strong&gt;older than 5 days are automatically removed&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The script is simple to extend for remote storage, logging, or notifications
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Automating backups is a small investment that can &lt;strong&gt;save you hours—or even your entire project—in case of data loss&lt;/strong&gt;.  &lt;/p&gt;

</description>
      <category>bash</category>
      <category>mysql</category>
      <category>automation</category>
      <category>devops</category>
    </item>
    <item>
      <title>Fail2Ban: The Essential Security Tool for Preventing Attacks on Linux Servers</title>
      <dc:creator>M. K. Tanjin Sarker</dc:creator>
      <pubDate>Sun, 24 Aug 2025 17:38:40 +0000</pubDate>
      <link>https://dev.to/tanjinsarker/fail2ban-the-essential-security-tool-for-preventing-attacks-on-linux-servers-559d</link>
      <guid>https://dev.to/tanjinsarker/fail2ban-the-essential-security-tool-for-preventing-attacks-on-linux-servers-559d</guid>
      <description>&lt;h1&gt;
  
  
  🚀 Fail2Ban Setup with Email Alerts (msmtp + Gmail)
&lt;/h1&gt;

&lt;p&gt;This guide explains how to install, configure, and use &lt;strong&gt;Fail2Ban&lt;/strong&gt; to protect your server from brute-force attacks, block malicious requests, and send email alerts via &lt;strong&gt;msmtp + Gmail&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  📌 1. Install Fail2Ban
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;fail2ban &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enable and start the service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;fail2ban
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start fail2ban
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl status fail2ban
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📌 2. Configure Fail2Ban
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Copy default configuration:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo cp&lt;/span&gt; /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or open directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/fail2ban/jail.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example &lt;code&gt;jail.local&lt;/code&gt; configuration:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[DEFAULT]&lt;/span&gt;
&lt;span class="c"&gt;# Ban settings
&lt;/span&gt;&lt;span class="py"&gt;bantime&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;1m&lt;/span&gt;
&lt;span class="py"&gt;findtime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;10m&lt;/span&gt;
&lt;span class="py"&gt;maxretry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;2&lt;/span&gt;
&lt;span class="py"&gt;backend&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;auto&lt;/span&gt;
&lt;span class="py"&gt;banaction&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;ufw&lt;/span&gt;
&lt;span class="py"&gt;action&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;%(action_mwl)s&lt;/span&gt;

&lt;span class="c"&gt;# Email notification
&lt;/span&gt;&lt;span class="py"&gt;destemail&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;tanjinsarker@gmail.com&lt;/span&gt;
&lt;span class="py"&gt;sender&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;tanjinfail2ban@gmail.com&lt;/span&gt;
&lt;span class="py"&gt;mta&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;sendmail&lt;/span&gt;

&lt;span class="c"&gt;# Ignore trusted IPs
&lt;/span&gt;&lt;span class="py"&gt;ignoreip&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;127.0.0.1/8 ::1&lt;/span&gt;

&lt;span class="c"&gt;# Logging
&lt;/span&gt;&lt;span class="py"&gt;loglevel&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;INFO&lt;/span&gt;
&lt;span class="py"&gt;logtarget&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;/var/log/fail2ban.log&lt;/span&gt;


&lt;span class="c"&gt;# 🚀 Protect SSH
&lt;/span&gt;&lt;span class="nn"&gt;[sshd]&lt;/span&gt;
&lt;span class="py"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;

&lt;span class="c"&gt;# 🚀 Block malicious file requests (.php, .asp, .jsp, .exe)
&lt;/span&gt;&lt;span class="nn"&gt;[php-url-ban]&lt;/span&gt;
&lt;span class="py"&gt;enabled&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;filter&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;php-url&lt;/span&gt;
&lt;span class="py"&gt;port&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;http,https&lt;/span&gt;
&lt;span class="py"&gt;logpath&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;/var/www/html/access.log&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📌 3. Create Custom Fail2Ban Filter
&lt;/h2&gt;

&lt;p&gt;Create a new filter for suspicious &lt;code&gt;.php&lt;/code&gt;, &lt;code&gt;.asp&lt;/code&gt;, &lt;code&gt;.jsp&lt;/code&gt;, &lt;code&gt;.exe&lt;/code&gt; requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/fail2ban/filter.d/php-url.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[Definition]&lt;/span&gt;
&lt;span class="py"&gt;failregex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;^&amp;lt;HOST&amp;gt; -.*"(GET|POST).*&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s"&gt;(php|asp|jsp|exe)(&lt;/span&gt;&lt;span class="se"&gt;\?&lt;/span&gt;&lt;span class="s"&gt;.*)? HTTP.*"&lt;/span&gt;
&lt;span class="py"&gt;ignoreregex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📌 4. Manage Fail2Ban
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Check active jails:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;fail2ban-client status | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"Jail list"&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;: &lt;span class="nt"&gt;-f2&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="s1"&gt;','&lt;/span&gt; &lt;span class="s1"&gt;'\n'&lt;/span&gt; | &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read &lt;/span&gt;jail&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Jail: &lt;/span&gt;&lt;span class="nv"&gt;$jail&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;sudo &lt;/span&gt;fail2ban-client status &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$jail&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"Banned IP list"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Ban / Unban IPs manually:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Ban IP&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;fail2ban-client &lt;span class="nb"&gt;set &lt;/span&gt;sshd banip 192.168.68.129

&lt;span class="c"&gt;# Unban IP&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;fail2ban-client &lt;span class="nb"&gt;set &lt;/span&gt;sshd unbanip 192.168.68.129

&lt;span class="c"&gt;# Check if an IP is banned&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;fail2ban-client get sshd banip 192.168.68.129
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📌 5. Firewall Configuration
&lt;/h2&gt;

&lt;p&gt;Ensure only &lt;strong&gt;one firewall backend&lt;/strong&gt; is active.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check status:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl is-active ufw
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl is-active firewalld
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl is-active nftables
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Disable unused backends:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Disable firewalld&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl stop firewalld
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl disable firewalld
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl mask firewalld

&lt;span class="c"&gt;# Disable nftables&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl stop nftables
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl disable nftables
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl mask nftables
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Re-enable if needed:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl unmask firewalld
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl unmask nftables
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📌 6. Install msmtp (Email Relay)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;msmtp msmtp-mta mailutils
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📌 7. Configure msmtp
&lt;/h2&gt;

&lt;p&gt;Edit config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/msmtprc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example &lt;code&gt;msmtprc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="err"&gt;defaults&lt;/span&gt;
&lt;span class="err"&gt;auth&lt;/span&gt; &lt;span class="err"&gt;on&lt;/span&gt;
&lt;span class="err"&gt;tls&lt;/span&gt; &lt;span class="err"&gt;on&lt;/span&gt;
&lt;span class="err"&gt;tls_trust_file&lt;/span&gt; &lt;span class="err"&gt;/etc/ssl/certs/ca-certificates.crt&lt;/span&gt;
&lt;span class="err"&gt;logfile&lt;/span&gt; &lt;span class="err"&gt;~/.msmtp.log&lt;/span&gt;

&lt;span class="err"&gt;account&lt;/span&gt; &lt;span class="err"&gt;gmail&lt;/span&gt;
&lt;span class="err"&gt;host&lt;/span&gt; &lt;span class="err"&gt;smtp.gmail.com&lt;/span&gt;
&lt;span class="err"&gt;port&lt;/span&gt; &lt;span class="err"&gt;587&lt;/span&gt;
&lt;span class="err"&gt;from&lt;/span&gt; &lt;span class="err"&gt;tanjinfail2ban@gmail.com&lt;/span&gt;
&lt;span class="err"&gt;user&lt;/span&gt; &lt;span class="err"&gt;tanjinfail2ban@gmail.com&lt;/span&gt;
&lt;span class="err"&gt;password&lt;/span&gt; &lt;span class="err"&gt;*********&lt;/span&gt;
&lt;span class="err"&gt;account&lt;/span&gt; &lt;span class="err"&gt;default&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="err"&gt;gmail&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Set permissions:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo chown &lt;/span&gt;root:root /etc/msmtprc
&lt;span class="nb"&gt;sudo chmod &lt;/span&gt;600 /etc/msmtprc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If running as non-root user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo chown&lt;/span&gt; &lt;span class="nv"&gt;$USER&lt;/span&gt;:&lt;span class="nv"&gt;$USER&lt;/span&gt; ~/.msmtprc
&lt;span class="nb"&gt;sudo chmod &lt;/span&gt;600 ~/.msmtprc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or make globally readable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo chmod &lt;/span&gt;644 /etc/msmtprc
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart fail2ban
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart Fail2ban:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart fail2ban
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📌 8. Test Email Sending
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"Subject: test&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;This is a test email"&lt;/span&gt; | msmtp &lt;span class="nt"&gt;--debug&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; gmail tanjinsarker@gmail.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check your inbox to verify delivery.&lt;/p&gt;




&lt;h2&gt;
  
  
  📌 9. Testing Fail2Ban Functionality
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Test SSH protection:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Attempt multiple failed SSH logins from a different IP (up to &lt;code&gt;maxretry&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;Check if the IP gets banned:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;fail2ban-client status sshd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Verify email notification was sent.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Test Web filter (&lt;code&gt;php-url-ban&lt;/code&gt;):
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Simulate a request to a forbidden URL (e.g., &lt;code&gt;.php&lt;/code&gt;, &lt;code&gt;.asp&lt;/code&gt;):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://your-server-ip/test.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Check if the IP appears in the banned list:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;fail2ban-client status php-url-ban
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Check your email for the ban alert.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Test Filter Regex Manually
&lt;/h3&gt;

&lt;p&gt;Before banning, you can &lt;strong&gt;test the filter regex&lt;/strong&gt; against your access log:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;fail2ban-regex /var/www/html/access.log /etc/fail2ban/filter.d/php-url.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Show which lines match the filter.&lt;/li&gt;
&lt;li&gt;Confirm your &lt;code&gt;php-url&lt;/code&gt; filter works correctly.&lt;/li&gt;
&lt;li&gt;Help troubleshoot if IPs are not being banned.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📌 10. SSH Successful Login Email Alerts
&lt;/h2&gt;

&lt;p&gt;This guide explains how to configure your server so that &lt;strong&gt;every successful SSH login triggers an email alert&lt;/strong&gt;. This method uses PAM (Pluggable Authentication Modules), which integrates directly with the SSH login process.&lt;/p&gt;




&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A working mail service on your server (e.g., &lt;code&gt;postfix&lt;/code&gt;, &lt;code&gt;sendmail&lt;/code&gt;, or an SMTP relay)&lt;/li&gt;
&lt;li&gt;Root or sudo access&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 1: Edit PAM SSH Configuration
&lt;/h2&gt;

&lt;p&gt;Open the PAM configuration for SSH:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/pam.d/sshd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the end of the file, add the following line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;session optional pam_exec.so seteuid /usr/local/bin/ssh-login-alert.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells PAM to run our custom script on every successful SSH login.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Create the Alert Script
&lt;/h2&gt;

&lt;p&gt;Create a new script at &lt;code&gt;/usr/local/bin/ssh-login-alert.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /usr/local/bin/ssh-login-alert.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;whoami&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;IP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$PAM_RHOST&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="s1"&gt;'+%Y-%m-%d %H:%M:%S'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;MESSAGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"SSH Login on &lt;/span&gt;&lt;span class="nv"&gt;$HOST&lt;/span&gt;&lt;span class="s2"&gt;
User: &lt;/span&gt;&lt;span class="nv"&gt;$USERNAME&lt;/span&gt;&lt;span class="s2"&gt;
From: &lt;/span&gt;&lt;span class="nv"&gt;$IP&lt;/span&gt;&lt;span class="s2"&gt;
Date: &lt;/span&gt;&lt;span class="nv"&gt;$DATE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MESSAGE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | mail &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"SSH Login Alert on &lt;/span&gt;&lt;span class="nv"&gt;$HOST&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; you@example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;🔧 Replace &lt;code&gt;you@example.com&lt;/code&gt; with your actual email address.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 3: Make Script Executable
&lt;/h2&gt;

&lt;p&gt;Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo chmod&lt;/span&gt; +x /usr/local/bin/ssh-login-alert.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 4: Restart SSH Service
&lt;/h2&gt;

&lt;p&gt;Apply changes by restarting SSH:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart sshd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 5: Test
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Log out of your server.&lt;/li&gt;
&lt;li&gt;Log back in via SSH.&lt;/li&gt;
&lt;li&gt;Check your email inbox.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You should receive an alert similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SSH Login on myserver
User: root
From: 192.168.1.100
Date: 2025-08-27 12:34:56
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ensure your mail system is properly configured; otherwise, emails will not be delivered.&lt;/li&gt;
&lt;li&gt;For added reliability, consider also logging alerts to a file.&lt;/li&gt;
&lt;li&gt;This method works for &lt;strong&gt;all SSH users&lt;/strong&gt; system-wide.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;✅ Done! You now receive an email on &lt;strong&gt;every successful SSH login&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ Final Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Fail2Ban is now protecting &lt;strong&gt;SSH&lt;/strong&gt; and &lt;strong&gt;web access logs&lt;/strong&gt; from malicious requests.
&lt;/li&gt;
&lt;li&gt;Emails will be sent using &lt;strong&gt;msmtp (Gmail SMTP relay)&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Always secure your Gmail account with an &lt;strong&gt;App Password&lt;/strong&gt; (never your real Gmail password).&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
  </channel>
</rss>
