✅ 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"
⚠️ 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
✅ The Full Script (Copy & Run)
✅ Save as: full_setup_ubuntu24.sh
✅ Run:
sudo bash full_setup_ubuntu24.sh
#!/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 "==========================================="
✅ Quick Troubleshooting
✅ Check services
systemctl status ssh
systemctl status nginx
systemctl status apache2
systemctl status mariadb
systemctl status mysql
systemctl status php8.4-fpm
✅ Check open ports
ss -tulpn | grep -E '(:22|:80|:443|:3306)'
✅ 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)