DEV Community

Cover image for Ubuntu 24.04 Setup Script: Nginx/Apache, PHP-FPM, MySQL/MariaDB, Docker, UFW
M. K. Tanjin Sarker
M. K. Tanjin Sarker

Posted on

Ubuntu 24.04 Setup Script: Nginx/Apache, PHP-FPM, MySQL/MariaDB, Docker, UFW

✅ Ubuntu 24.04 Full Server Setup Script (Apache/Nginx + PHP-FPM Multi Version + MySQL/MariaDB + Docker + UFW + OpenSSH + Git + Composer)

This post shares an All-in-One Bash Script to quickly set up a production-ready environment on Ubuntu 24.04.

Web Server: Apache2 or Nginx (choose one)

Database: MySQL or MariaDB (choose one)

PHP-FPM: Default PHP + Multi PHP (7.4–8.3 optional)

Apache (conf-available): Creates all PHP version .conf files automatically, but enables only the DEFAULT_PHP_VERSION

Docker + Docker Compose (Official Repo)

UFW Firewall (Optional)

OpenSSH Server (Optional)

Git (Optional)

Composer (Optional)


✅ Features

✅ Web Server (Choose One)

  • INSTALL_APACHE2="yes/no"
  • INSTALL_NGINX="yes/no"

⚠️ If both are yes, the script will stop (port 80/443 conflict).

✅ Database (Choose One)

  • INSTALL_MYSQL="yes/no"
  • INSTALL_MARIADB="yes/no"

⚠️ If both are yes, the script will stop to avoid conflicts.

✅ OpenSSH (Optional)

  • INSTALL_OPENSSH="yes/no"

Installs and enables openssh-server (useful for fresh VPS setups).

✅ Git (Optional)

  • INSTALL_GIT="yes/no"

Installs git.

✅ Composer (Optional)

  • INSTALL_COMPOSER="yes/no"

Installs Composer globally as /usr/local/bin/composer.

✅ Composer requires PHP CLI to be available.

If you disable both Apache and Nginx, PHP might not be installed and Composer installation will be skipped.

✅ PHP-FPM Multi-Version Support

  • DEFAULT_PHP_VERSION="8.4"
  • ENABLE_MULTI_PHP_FPM="yes/no"

✅ For Apache, the script auto-creates configs inside:

  • /etc/apache2/conf-available/php7.4-fpm.conf
  • /etc/apache2/conf-available/php8.0-fpm.conf
  • /etc/apache2/conf-available/php8.1-fpm.conf
  • /etc/apache2/conf-available/php8.2-fpm.conf
  • /etc/apache2/conf-available/php8.3-fpm.conf
  • /etc/apache2/conf-available/php8.4-fpm.conf

✅ But enables only:

  • a2enconf php8.4-fpm (or your selected default)

✅ Recommended Default Setup (Example)

✅ Nginx + MariaDB + Docker + OpenSSH + Git + Composer

INSTALL_APACHE2="yes"
INSTALL_NGINX="no"

INSTALL_MYSQL="yes"
INSTALL_MARIADB="no"

INSTALL_DOCKER="yes"
INSTALL_OPENSSH="yes"
INSTALL_GIT="yes"
INSTALL_COMPOSER="yes"
ENABLE_UFW="yes"
Enter fullscreen mode Exit fullscreen mode

⚠️ Security Note (Important)

This script creates /var/www/html/info.php for testing phpinfo().

✅ After testing, delete it immediately:

sudo rm /var/www/html/info.php
Enter fullscreen mode Exit fullscreen mode

✅ The Full Script (Copy & Run)

✅ Save as: full_setup_ubuntu24.sh

✅ Run:

sudo bash full_setup_ubuntu24.sh
Enter fullscreen mode Exit fullscreen mode
#!/bin/bash
set -euo pipefail

# -----------------------------
# CONFIG (EDIT THESE)
# -----------------------------
DEFAULT_PHP_VERSION="8.4"            # Default PHP-FPM version for Web Server
MYSQL_ROOT_PASSWORD="12345"          # Change this

ENABLE_MULTI_PHP_FPM="yes"           # yes/no (install & enable multiple FPM versions)
INSTALL_PHPMYADMIN="no"              # yes/no
ENABLE_UFW="yes"                     # yes/no

INSTALL_OPENSSH="yes"                # yes/no
INSTALL_GIT="yes"                    # yes/no
INSTALL_COMPOSER="yes"               # yes/no

INSTALL_APACHE2="yes"                 # yes/no
INSTALL_NGINX="no"                  # yes/no

INSTALL_MYSQL="yes"                   # yes/no
INSTALL_MARIADB="no"                # yes/no
INSTALL_DOCKER="yes"                 # yes/no
# -----------------------------

echo "==========================================="
echo " Ubuntu 24.04 Full Setup Script"
echo " OpenSSH Install: ${INSTALL_OPENSSH}"
echo " Git Install:     ${INSTALL_GIT}"
echo " Composer Install:${INSTALL_COMPOSER}"
echo " Apache Install:  ${INSTALL_APACHE2}"
echo " Nginx Install:   ${INSTALL_NGINX}"
echo " MySQL Install:   ${INSTALL_MYSQL}"
echo " MariaDB Install: ${INSTALL_MARIADB}"
echo " Docker Install:  ${INSTALL_DOCKER}"
echo " Default PHP:     PHP ${DEFAULT_PHP_VERSION}"
echo "==========================================="

# Check root
if [ "$EUID" -ne 0 ]; then
  echo "❌ Please run as root: sudo bash full_setup_ubuntu24.sh"
  exit 1
fi

# Conflict checks
if [ "${INSTALL_MYSQL}" = "yes" ] && [ "${INSTALL_MARIADB}" = "yes" ]; then
  echo "❌ ERROR: You cannot install both MySQL and MariaDB together."
  echo "   Set either INSTALL_MYSQL=yes OR INSTALL_MARIADB=yes"
  exit 1
fi

if [ "${INSTALL_APACHE2}" = "yes" ] && [ "${INSTALL_NGINX}" = "yes" ]; then
  echo "❌ ERROR: You cannot enable both Apache and Nginx together (port 80/443 conflict)."
  echo "   Set either INSTALL_APACHE2=yes OR INSTALL_NGINX=yes"
  exit 1
fi

echo "✅ Updating system..."
apt update && apt upgrade -y

echo "✅ Installing basic tools..."
apt install -y software-properties-common curl ca-certificates gnupg lsb-release unzip

# -----------------------------
# OpenSSH Install (Optional)
# -----------------------------
if [ "${INSTALL_OPENSSH}" = "yes" ]; then
  echo "✅ Installing OpenSSH Server..."
  apt install -y openssh-server
  systemctl enable --now ssh
else
  echo "⏭️ Skipping OpenSSH installation..."
fi

# -----------------------------
# Git Install (Optional)
# -----------------------------
if [ "${INSTALL_GIT}" = "yes" ]; then
  echo "✅ Installing Git..."
  apt install -y git
else
  echo "⏭️ Skipping Git installation..."
fi

# -----------------------------
# Apache2 Install (Optional)
# -----------------------------
if [ "${INSTALL_APACHE2}" = "yes" ]; then
  echo "✅ Installing Apache2..."
  apt install -y apache2
  systemctl enable --now apache2

  echo "✅ Enabling Apache modules for PHP-FPM..."
  apt install -y libapache2-mod-fcgid
  a2enmod proxy_fcgi setenvif
  systemctl restart apache2
else
  echo "⏭️ Skipping Apache2 installation..."
fi

# -----------------------------
# Nginx Install (Optional)
# -----------------------------
if [ "${INSTALL_NGINX}" = "yes" ]; then
  echo "✅ Installing Nginx..."
  apt install -y nginx
  systemctl enable --now nginx
else
  echo "⏭️ Skipping Nginx installation..."
fi

# -----------------------------
# MySQL Install (Optional)
# -----------------------------
if [ "${INSTALL_MYSQL}" = "yes" ]; then
  echo "✅ Installing MySQL Server..."
  apt install -y mysql-server
  systemctl enable --now mysql

  echo "✅ Setting MySQL root password + mysql_native_password..."
  mysql -u root <<MYSQL_SCRIPT
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '${MYSQL_ROOT_PASSWORD}';
FLUSH PRIVILEGES;
MYSQL_SCRIPT

  echo "✅ Testing MySQL root login..."
  mysql -u root -p"${MYSQL_ROOT_PASSWORD}" -e "SELECT 1;" >/dev/null
else
  echo "⏭️ Skipping MySQL installation..."
fi

# -----------------------------
# MariaDB Install (Optional)
# -----------------------------
if [ "${INSTALL_MARIADB}" = "yes" ]; then
  echo "✅ Installing MariaDB Server..."
  apt install -y mariadb-server
  systemctl enable --now mariadb

  echo "✅ Setting MariaDB root password..."
  mariadb -u root <<MARIADB_SCRIPT
ALTER USER 'root'@'localhost' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}';
FLUSH PRIVILEGES;
MARIADB_SCRIPT

  echo "✅ Testing MariaDB root login..."
  mariadb -u root -p"${MYSQL_ROOT_PASSWORD}" -e "SELECT 1;" >/dev/null
else
  echo "⏭️ Skipping MariaDB installation..."
fi

# -----------------------------
# PHP Install (Ondrej PPA)
# Only if Apache or Nginx is installed
# -----------------------------
PHP_INSTALLED="no"
if [ "${INSTALL_APACHE2}" = "yes" ] || [ "${INSTALL_NGINX}" = "yes" ]; then
  PHP_INSTALLED="yes"

  echo "✅ Adding PHP PPA (ondrej/php)..."
  add-apt-repository ppa:ondrej/php -y
  apt update -y

  echo "✅ Installing Default PHP ${DEFAULT_PHP_VERSION} (FPM + extensions + opcache)..."
  apt install -y \
  php${DEFAULT_PHP_VERSION} \
  php${DEFAULT_PHP_VERSION}-fpm \
  php${DEFAULT_PHP_VERSION}-cli \
  php${DEFAULT_PHP_VERSION}-common \
  php${DEFAULT_PHP_VERSION}-mysql \
  php${DEFAULT_PHP_VERSION}-curl \
  php${DEFAULT_PHP_VERSION}-mbstring \
  php${DEFAULT_PHP_VERSION}-xml \
  php${DEFAULT_PHP_VERSION}-zip \
  php${DEFAULT_PHP_VERSION}-gd \
  php${DEFAULT_PHP_VERSION}-intl \
  php${DEFAULT_PHP_VERSION}-bcmath \
  php${DEFAULT_PHP_VERSION}-opcache

  echo "✅ Enabling PHP-FPM service for ${DEFAULT_PHP_VERSION}..."
  systemctl enable --now php${DEFAULT_PHP_VERSION}-fpm

  # Optional: Multi PHP-FPM
  if [ "${ENABLE_MULTI_PHP_FPM}" = "yes" ]; then
    echo "✅ Installing multiple PHP-FPM versions..."
    for v in 7.4 8.0 8.1 8.2 8.3; do
      echo "➡️ Installing PHP ${v} FPM..."
      apt install -y \
      php${v} \
      php${v}-fpm \
      php${v}-cli \
      php${v}-common \
      php${v}-mysql \
      php${v}-curl \
      php${v}-mbstring \
      php${v}-xml \
      php${v}-zip \
      php${v}-gd \
      php${v}-intl \
      php${v}-bcmath \
      php${v}-opcache || true

      systemctl enable --now php${v}-fpm || true
    done
  fi

  # Set CLI default PHP
  echo "✅ Setting CLI default PHP to ${DEFAULT_PHP_VERSION}..."
  update-alternatives --set php /usr/bin/php${DEFAULT_PHP_VERSION} || true
  update-alternatives --set phar /usr/bin/phar${DEFAULT_PHP_VERSION} || true
  update-alternatives --set phar.phar /usr/bin/phar.phar${DEFAULT_PHP_VERSION} || true
  update-alternatives --set phpize /usr/bin/phpize${DEFAULT_PHP_VERSION} || true
  update-alternatives --set php-config /usr/bin/php-config${DEFAULT_PHP_VERSION} || true
else
  echo "⏭️ Skipping PHP installation because both Apache & Nginx are disabled..."
fi

# -----------------------------
# Composer Install (Optional)
# Requires PHP CLI
# -----------------------------
if [ "${INSTALL_COMPOSER}" = "yes" ]; then
  if command -v php >/dev/null 2>&1; then
    echo "✅ Installing Composer..."

    EXPECTED_CHECKSUM="$(php -r 'copy("https://composer.github.io/installer.sig", "php://stdout");')"
    php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"

    ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")"

    if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]; then
      echo "❌ ERROR: Invalid Composer installer checksum"
      rm -f composer-setup.php
      exit 1
    fi

    php composer-setup.php --quiet --install-dir=/usr/local/bin --filename=composer
    rm -f composer-setup.php

    echo "✅ Composer installed: $(composer --version)"
  else
    echo "⚠️ Composer requested but PHP is not installed. Skipping Composer..."
  fi
else
  echo "⏭️ Skipping Composer installation..."
fi

# -----------------------------
# Apache PHP-FPM conf setup
# conf-available create all versions, enable only default
# -----------------------------
if [ "${INSTALL_APACHE2}" = "yes" ]; then
  echo "✅ Creating Apache PHP-FPM conf files in conf-available..."

  PHP_VERSIONS=()
  PHP_VERSIONS+=("${DEFAULT_PHP_VERSION}")

  if [ "${ENABLE_MULTI_PHP_FPM}" = "yes" ]; then
    PHP_VERSIONS+=(7.4 8.0 8.1 8.2 8.3)
  fi

  PHP_VERSIONS=($(printf "%s\n" "${PHP_VERSIONS[@]}" | sort -u))

  for v in "${PHP_VERSIONS[@]}"; do
    PHP_CONF="/etc/apache2/conf-available/php${v}-fpm.conf"
    echo "➡️ Creating: $PHP_CONF"

    cat > "$PHP_CONF" <<EOF
# Auto-generated PHP-FPM config: PHP ${v}
<IfModule proxy_fcgi_module>
    <FilesMatch \\.php$>
        SetHandler "proxy:unix:/run/php/php${v}-fpm.sock|fcgi://localhost/"
    </FilesMatch>
</IfModule>
EOF
  done

  echo "✅ Disabling other PHP-FPM confs (avoid conflict)..."
  for v in "${PHP_VERSIONS[@]}"; do
    if [ "$v" != "${DEFAULT_PHP_VERSION}" ]; then
      a2disconf "php${v}-fpm" >/dev/null 2>&1 || true
    fi
  done

  echo "✅ Enabling only default PHP-FPM conf: php${DEFAULT_PHP_VERSION}-fpm"
  a2enconf "php${DEFAULT_PHP_VERSION}-fpm"

  systemctl reload apache2
fi

# -----------------------------
# Nginx PHP-FPM config setup
# -----------------------------
if [ "${INSTALL_NGINX}" = "yes" ]; then
  echo "✅ Configuring Nginx for PHP-FPM (default PHP ${DEFAULT_PHP_VERSION})..."

  rm -f /etc/nginx/sites-enabled/default

  NGINX_SITE="/etc/nginx/sites-available/default-php-fpm"

  cat > "$NGINX_SITE" <<EOF
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 \$uri \$uri/ =404;
    }

    location ~ \\.php\$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php${DEFAULT_PHP_VERSION}-fpm.sock;
    }

    location ~ /\\.ht {
        deny all;
    }
}
EOF

  ln -sf "$NGINX_SITE" /etc/nginx/sites-enabled/default-php-fpm

  nginx -t
  systemctl reload nginx
fi

# -----------------------------
# PHP Info test file
# -----------------------------
if [ "${INSTALL_APACHE2}" = "yes" ] || [ "${INSTALL_NGINX}" = "yes" ]; then
  echo "✅ Creating PHP test file: /var/www/html/info.php"
  cat > /var/www/html/info.php <<EOF
<?php
phpinfo();
?>
EOF
fi

# -----------------------------
# Optional: phpMyAdmin
# -----------------------------
if [ "${INSTALL_PHPMYADMIN}" = "yes" ]; then
  echo "✅ Installing phpMyAdmin..."
  apt install -y phpmyadmin || true

  if [ "${INSTALL_APACHE2}" = "yes" ]; then
    systemctl reload apache2
  fi

  if [ "${INSTALL_NGINX}" = "yes" ]; then
    systemctl reload nginx
  fi
fi

# -----------------------------
# Docker Install (Optional)
# -----------------------------
if [ "${INSTALL_DOCKER}" = "yes" ]; then
  echo "✅ Installing Docker + Docker Compose (official)..."

  install -m 0755 -d /etc/apt/keyrings
  rm -f /etc/apt/keyrings/docker.gpg

  curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
  chmod a+r /etc/apt/keyrings/docker.gpg

  echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
  > /etc/apt/sources.list.d/docker.list

  apt update -y
  apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
  systemctl enable --now docker

  if [ -n "${SUDO_USER:-}" ]; then
    echo "✅ Adding user '$SUDO_USER' to docker group..."
    usermod -aG docker "$SUDO_USER"
  fi
else
  echo "⏭️ Skipping Docker installation..."
fi

# -----------------------------
# UFW Firewall (Optional)
# -----------------------------
if [ "${ENABLE_UFW}" = "yes" ]; then
  echo "✅ Setting up UFW firewall..."
  apt install -y ufw

  # Only allow SSH if OpenSSH install enabled
  if [ "${INSTALL_OPENSSH}" = "yes" ]; then
    ufw allow OpenSSH
  fi

  ufw allow 80/tcp
  ufw allow 443/tcp

  ufw --force enable
  ufw status verbose
fi

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

✅ Quick Troubleshooting

✅ Check services

systemctl status ssh
systemctl status nginx
systemctl status apache2
systemctl status mariadb
systemctl status mysql
systemctl status php8.4-fpm
Enter fullscreen mode Exit fullscreen mode

✅ Check open ports

ss -tulpn | grep -E '(:22|:80|:443|:3306)'
Enter fullscreen mode Exit fullscreen mode

✅ Done ✅

If you want, I can add these in the next version:

INSTALL_SSL_CERTBOT="yes/no" (Let’s Encrypt auto SSL)

INSTALL_REDIS="yes/no"

INSTALL_FAIL2BAN="yes/no"

✅ per-site multi PHP config templates

Happy Hosting 🚀

Top comments (0)