#!/bin/bash # # This is a Shell script for VPS initialization and # LAMP (Linux + Apache + MariaDB + PHP) installation # # Supported OS: # Debian 11 # Debian 12 # Debian 13 # Ubuntu 20.04 # Ubuntu 22.04 # Ubuntu 24.04 # # Copyright (C) 2013 - 2025 Teddysun # trap _exit INT QUIT TERM cur_dir="$(cd -P -- "$(dirname -- "$0")" && pwd -P)" _red() { printf '\033[1;31;31m%b\033[0m' "$1" } _green() { printf '\033[1;31;32m%b\033[0m' "$1" } _yellow() { printf '\033[1;31;33m%b\033[0m' "$1" } _printargs() { printf -- "%s" "[$(date)] " printf -- "%s" "$1" printf "\n" } _info() { _printargs "$@" } _warn() { printf -- "%s" "[$(date)] " _yellow "$1" printf "\n" } _error() { printf -- "%s" "[$(date)] " _red "$1" printf "\n" exit 2 } _exit() { printf "\n" _red "$0 has been terminated." printf "\n" exit 1 } _exists() { local cmd="$1" if eval type type >/dev/null 2>&1; then eval type "$cmd" >/dev/null 2>&1 elif command >/dev/null 2>&1; then command -v "$cmd" >/dev/null 2>&1 else which "$cmd" >/dev/null 2>&1 fi local rt=$? return ${rt} } _error_detect() { local cmd="$1" _info "${cmd}" if ! eval "${cmd}" 1>/dev/null; then _error "Execution command (${cmd}) failed, please check it and try again." fi } check_sys() { local value="$1" local release='' if [ -f /etc/redhat-release ]; then release="rhel" elif grep -Eqi "debian" /etc/issue; then release="debian" elif grep -Eqi "ubuntu" /etc/issue; then release="ubuntu" elif grep -Eqi "centos|red hat|redhat" /etc/issue; then release="rhel" elif grep -Eqi "debian" /proc/version; then release="debian" elif grep -Eqi "ubuntu" /proc/version; then release="ubuntu" elif grep -Eqi "centos|red hat|redhat" /proc/version; then release="rhel" fi if [ "${value}" == "${release}" ]; then return 0 else return 1 fi } get_char() { SAVEDSTTY=$(stty -g) stty -echo stty cbreak dd if=/dev/tty bs=1 count=1 2>/dev/null stty -raw stty echo stty "${SAVEDSTTY}" } get_opsy() { [ -f /etc/redhat-release ] && awk '{print $0}' /etc/redhat-release && return [ -f /etc/os-release ] && awk -F'[= "]' '/PRETTY_NAME/{print $3,$4,$5}' /etc/os-release && return [ -f /etc/lsb-release ] && awk -F'[="]+' '/DESCRIPTION/{print $2}' /etc/lsb-release && return } get_rhelversion() { if check_sys rhel; then local version local code=$1 local main_ver version=$(get_opsy) main_ver=$(echo "${version}" | grep -oE "[0-9.]+") if [ "${main_ver%%.*}" == "${code}" ]; then return 0 else return 1 fi else return 1 fi } get_debianversion() { if check_sys debian; then local version local code=$1 local main_ver version=$(get_opsy) main_ver=$(echo "${version}" | grep -oE "[0-9.]+") if [ "${main_ver%%.*}" == "${code}" ]; then return 0 else return 1 fi else return 1 fi } get_ubuntuversion() { if check_sys ubuntu; then local version local code=$1 version=$(get_opsy) if echo "${version}" | grep -q "${code}"; then return 0 else return 1 fi else return 1 fi } version_ge() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1" } check_kernel_version() { local kernel_version kernel_version=$(uname -r | cut -d- -f1) if version_ge "${kernel_version}" 4.9; then return 0 else return 1 fi } # Check BBR status check_bbr_status() { local param param=$(sysctl net.ipv4.tcp_congestion_control | awk '{print $3}') if [[ "${param}" == "bbr" ]]; then return 0 else return 1 fi } initialize_deb() { _error_detect "apt-get update" _error_detect "apt-get -yq install lsb-release ca-certificates curl gnupg" _error_detect "apt-get -yq install vim nano tar zip unzip net-tools screen git virt-what wget mtr traceroute iftop htop jq tree" if ufw status >/dev/null 2>&1; then _error_detect "ufw allow http" _error_detect "ufw allow https" _error_detect "ufw allow 443/udp" else _warn "ufw is not running, skipped firewall configuration" fi } # Configure BBR configure_bbr() { if check_kernel_version; then if ! check_bbr_status; then sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf sed -i '/net.core.rmem_max/d' /etc/sysctl.conf cat >>"/etc/sysctl.conf" </dev/null 2>&1 _info "BBR configured" else _info "BBR is already enabled, skipped configuration" fi else _warn "Kernel version is below 4.9, skipped BBR configuration" fi } # Configure systemd-journald configure_journald() { local journald_config if systemctl status systemd-journald >/dev/null 2>&1; then if [ -s "/etc/systemd/journald.conf" ]; then journald_config="/etc/systemd/journald.conf" elif [ -s "/usr/lib/systemd/journald.conf" ]; then journald_config="/usr/lib/systemd/journald.conf" fi sed -i 's/^#\?Storage=.*/Storage=volatile/' ${journald_config} sed -i 's/^#\?SystemMaxUse=.*/SystemMaxUse=16M/' ${journald_config} sed -i 's/^#\?RuntimeMaxUse=.*/RuntimeMaxUse=16M/' ${journald_config} _error_detect "systemctl restart systemd-journald" _info "systemd-journald configuration completed" fi } # Check user [ ${EUID} -ne 0 ] && _red "This script must be run as root!\n" && exit 1 # Check OS if ! get_debianversion 11 && ! get_debianversion 12 && ! get_debianversion 13 && ! get_ubuntuversion 20.04 && ! get_ubuntuversion 22.04 && ! get_ubuntuversion 24.04; then _error "Unsupported OS. Please switch to Debian 11+, or Ubuntu 20.04+ and try again." fi # Choose MariaDB version while true; do _info "Please choose a version of the MariaDB:" _info "$(_green 1). MariaDB 10.11" _info "$(_green 2). MariaDB 11.4" _info "$(_green 3). MariaDB 11.8" read -r -p "[$(date)] Please input a number: (Default 2) " mariadb_version [ -z "${mariadb_version}" ] && mariadb_version=2 case "${mariadb_version}" in 1) mariadb_ver="10.11" break ;; 2) mariadb_ver="11.4" break ;; 3) mariadb_ver="11.8" break ;; *) _info "Input error. Please input a number between 1 and 3" ;; esac done _info "---------------------------" _info "MariaDB version = $(_red "${mariadb_ver}")" _info "---------------------------" # Set MariaDB root password _info "Please input the root password of MariaDB:" read -s -r -p "[$(date)] (Default password: Teddysun.com) (password will not shown):" db_pass if [ -z "${db_pass}" ]; then db_pass="Teddysun.com" fi echo _info "---------------------------" _info "Password = $(_red "${db_pass}")" _info "---------------------------" # Choose PHP version while true; do _info "Please choose a version of the PHP:" _info "$(_green 1). PHP 7.4" _info "$(_green 2). PHP 8.0" _info "$(_green 3). PHP 8.1" _info "$(_green 4). PHP 8.2" _info "$(_green 5). PHP 8.3" _info "$(_green 6). PHP 8.4" _info "$(_green 7). PHP 8.5" read -r -p "[$(date)] Please input a number: (Default 6) " php_version [ -z "${php_version}" ] && php_version=6 case "${php_version}" in 1) php_ver="7.4" break ;; 2) php_ver="8.0" break ;; 3) php_ver="8.1" break ;; 4) php_ver="8.2" break ;; 5) php_ver="8.3" break ;; 6) php_ver="8.4" break ;; 7) php_ver="8.5" break ;; *) _info "Input error. Please input a number between 1 and 7" ;; esac done _info "---------------------------" _info "PHP version = $(_red "${php_ver}")" _info "---------------------------" _info "Press any key to start...or Press Ctrl+C to cancel" char=$(get_char) _info "Initialization start" configure_bbr configure_journald initialize_deb echo netstat -nxtulpe echo _info "Initialization completed" sleep 3 clear _info "LAMP (Linux + Apache + MariaDB + PHP) installation start" _info "Apache installation start" _error_detect "apt-get install -y apache2 libapache2-mod-perl2 libapache2-mod-md" _error_detect "systemctl stop apache2" _error_detect "a2enmod ssl http2 brotli data unique_id vhost_alias echo expires info" _error_detect "a2enmod headers perl rewrite lua request md mime_magic remoteip userdir" _error_detect "a2enmod auth*" _error_detect "a2enmod cache*" _error_detect "a2enmod dav*" _error_detect "a2enmod proxy*" _error_detect "a2enmod session*" sed -i "s@^ServerTokens.*@ServerTokens Minimal@" "/etc/apache2/conf-available/security.conf" sed -i "s@^ServerSignature.*@ServerSignature Off@" "/etc/apache2/conf-available/security.conf" _info "Apache installation completed" _info "Setting up Apache" _error_detect "mkdir -p /data/www/default" _error_detect "mkdir -p /data/wwwlog" _error_detect "mkdir -p /etc/apache2/ssl" _error_detect "cp -f ${cur_dir}/conf/apache2.conf /etc/apache2/apache2.conf" _error_detect "cp -f ${cur_dir}/conf/ssl.conf /etc/apache2/mods-available/" _error_detect "cp -f ${cur_dir}/conf/favicon.ico /data/www/default/" _error_detect "cp -f ${cur_dir}/conf/index.html /data/www/default/" _error_detect "cp -f ${cur_dir}/conf/lamp.png /data/www/default/" cat >/etc/apache2/sites-available/000-default.conf < ServerName localhost DocumentRoot /data/www/default SetOutputFilter DEFLATE Options FollowSymLinks AllowOverride All Order Deny,Allow Allow from All DirectoryIndex index.html index.htm index.php EOF _info "Apache configuration completed" _info "MariaDB installation start" _error_detect "wget -qO mariadb_repo_setup.sh https://dl.lamp.sh/files/mariadb_repo_setup.sh" _error_detect "chmod +x mariadb_repo_setup.sh" _info "./mariadb_repo_setup.sh --mariadb-server-version=mariadb-${mariadb_ver}" ./mariadb_repo_setup.sh --mariadb-server-version=mariadb-${mariadb_ver} >/dev/null 2>&1 _error_detect "rm -f mariadb_repo_setup.sh" _error_detect "apt-get install -y mariadb-common mariadb-server mariadb-client mariadb-backup" mariadb_cnf="/etc/mysql/mariadb.conf.d/50-server.cnf" _info "MariaDB installation completed" _info "Setting up MariaDB" lnum=$(sed -n '/\[mysqld\]/=' "${mariadb_cnf}") [ -n "${lnum}" ] && sed -i "${lnum}ainnodb_buffer_pool_size = 100M\nmax_allowed_packet = 1024M\nnet_read_timeout = 3600\nnet_write_timeout = 3600" "${mariadb_cnf}" lnum=$(sed -n '/\[mariadb\]/=' "${mariadb_cnf}" | tail -1) [ -n "${lnum}" ] && sed -i "${lnum}acharacter-set-server = utf8mb4\n\n\[client-mariadb\]\ndefault-character-set = utf8mb4" "${mariadb_cnf}" _error_detect "systemctl start mariadb" sleep 3 /usr/bin/mariadb -e "grant all privileges on *.* to root@'127.0.0.1' identified by \"${db_pass}\" with grant option;" /usr/bin/mariadb -e "grant all privileges on *.* to root@'localhost' identified by \"${db_pass}\" with grant option;" /usr/bin/mariadb -uroot -p"${db_pass}" 2>/dev/null <"/etc/mysql/debian.cnf" </dev/null < /data/www/default/pma/sql/create_tables.sql" /usr/bin/mariadb -uroot -p"${db_pass}" 2>/dev/null /etc/apt/sources.list.d/php.list fi # https://launchpad.net/~ondrej/+archive/ubuntu/php if check_sys ubuntu; then _error_detect "add-apt-repository -y ppa:ondrej/php" fi _error_detect "apt-get update" _error_detect "apt-get install -y php-common php${php_ver}-common php${php_ver}-cli php${php_ver}-fpm php${php_ver}-opcache php${php_ver}-readline" _error_detect "apt-get install -y libphp${php_ver}-embed php${php_ver}-bcmath php${php_ver}-gd php${php_ver}-imap php${php_ver}-mysql php${php_ver}-dba php${php_ver}-mongodb php${php_ver}-sybase" _error_detect "apt-get install -y php${php_ver}-pgsql php${php_ver}-odbc php${php_ver}-enchant php${php_ver}-gmp php${php_ver}-intl php${php_ver}-ldap php${php_ver}-snmp php${php_ver}-soap" _error_detect "apt-get install -y php${php_ver}-mbstring php${php_ver}-curl php${php_ver}-pspell php${php_ver}-xml php${php_ver}-zip php${php_ver}-bz2 php${php_ver}-lz4 php${php_ver}-zstd" _error_detect "apt-get install -y php${php_ver}-tidy php${php_ver}-sqlite3 php${php_ver}-imagick php${php_ver}-grpc php${php_ver}-yaml php${php_ver}-uuid" _error_detect "mkdir -m770 /var/lib/php/{session,wsdlcache,opcache}" _info "PHP installation completed" _info "Setting up PHP" sed -i "s@^user.*@user = www-data@" "${php_conf}" sed -i "s@^group.*@group = www-data@" "${php_conf}" sed -i "s@^listen.owner.*@;&@" "${php_conf}" sed -i "s@^listen.group.*@;&@" "${php_conf}" sed -i "s@^;listen.acl_users.*@listen.acl_users = www-data@" "${php_conf}" sed -i "s@^;listen.allowed_clients.*@listen.allowed_clients = 127.0.0.1@" "${php_conf}" sed -i "s@^pm.max_children.*@pm.max_children = 50@" "${php_conf}" sed -i "s@^pm.start_servers.*@pm.start_servers = 5@" "${php_conf}" sed -i "s@^pm.min_spare_servers.*@pm.min_spare_servers = 5@" "${php_conf}" sed -i "s@^pm.max_spare_servers.*@pm.max_spare_servers = 35@" "${php_conf}" sed -i "s@^;slowlog.*@slowlog = /var/log/www-slow.log@" "${php_conf}" sed -i "s@^;php_admin_value\[error_log\].*@php_admin_value[error_log] = /var/log/www-error.log@" "${php_conf}" sed -i "s@^;php_admin_flag\[log_errors\].*@php_admin_flag[log_errors] = on@" "${php_conf}" cat >>"${php_conf}" </dev/null 2>&1 ln -s ../mods-available/php.conf php.conf popd >/dev/null 2>&1 _error_detect "systemctl daemon-reload" _error_detect "systemctl start ${php_fpm}" _error_detect "systemctl start apache2" sleep 3 _error_detect "systemctl restart ${php_fpm}" sleep 1 _error_detect "systemctl restart apache2" sleep 1 _error_detect "systemctl restart mariadb" sleep 1 _info "systemctl enable mariadb" systemctl enable mariadb >/dev/null 2>&1 _info "systemctl enable ${php_fpm}" systemctl enable "${php_fpm}" >/dev/null 2>&1 _info "systemctl enable apache2" systemctl enable apache2 >/dev/null 2>&1 pkill -9 gpg-agent _info "systemctl status mariadb" systemctl --no-pager -l status mariadb _info "systemctl status ${php_fpm}" systemctl --no-pager -l status "${php_fpm}" _info "systemctl status apache2" systemctl --no-pager -l status apache2 echo netstat -nxtulpe echo _info "LAMP (Linux + Apache + MariaDB + PHP) installation completed"