#!/bin/bash export DEBIAN_FRONTEND=noninteractive ### CONFIGURATION ### BUILD=20240727 PASS=$(openssl rand -base64 32 | sha256sum | base64 | head -c 32 | tr '[:upper:]' '[:lower:]') DBPASS=$(openssl rand -base64 24 | sha256sum | base64 | head -c 32 | tr '[:upper:]' '[:lower:]') SERVERID=$(openssl rand -base64 12 | sha256sum | base64 | head -c 32 | tr '[:upper:]' '[:lower:]') REPO=yolanmees/Spikster BRANCH=master ADMIN_EMAIL="your_admin_email@example.com" USE_LOCAL_IP=false # CLI tool coloring reset=$(tput sgr0) bold=$(tput bold) underline=$(tput smul) black=$(tput setaf 0) white=$(tput setaf 7) red=$(tput setaf 1) green=$(tput setaf 2) yellow=$(tput setaf 3) blue=$(tput setaf 4) purple=$(tput setaf 5) bgblack=$(tput setab 0) bgwhite=$(tput setab 7) bgred=$(tput setab 1) bggreen=$(tput setab 2) bgyellow=$(tput setab 4) bgblue=$(tput setab 4) bgpurple=$(tput setab 5) # Function to check disk space check_disk_space() { required_space=2048 # available_space=$(df / | tail -1 | awk '{print $4}') if ((available_space < required_space)); then echo "${bgred}${white}${bold}Error: Not enough disk space. Required: ${required_space}MB, Available: $(($available_space / 1024))MB.${reset}" exit 1 fi } # Call to the disk space check function clear check_disk_space # LOGO clear echo "${green}${bold}" echo "" echo "███████╗██████╗ ██╗██╗ ██╗███████╗████████╗███████╗██████╗ " echo "██╔════╝██╔══██╗██║██║ ██╔╝██╔════╝╚══██╔══╝██╔════╝██╔══██╗" echo "███████╗██████╔╝██║█████╔╝ ███████╗ ██║ █████╗ ██████╔╝" echo "╚════██║██╔═══╝ ██║██╔═██╗ ╚════██║ ██║ ██╔══╝ ██╔══██╗" echo "███████║██║ ██║██║ ██╗███████║ ██║ ███████╗██║ ██║" echo "╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝ ╚═╝ ╚══════╝╚═╝ ╚═╝" echo "" echo "Installation has been started... Hold on!" echo "${reset}" sleep 3s help() { echo "Usage: $0 [OPTIONS] -n, --nginx Install Nginx [yes|no] default: yes -p, --phpfpm Install PHP-FPM [yes|no] default: yes -m, --mysql Install MySQL [yes|no] default: yes -b, --branch Set branch for admin panel default: master -f, --force Force installation -l, --local Use local IP instead of external IP -h, --help Print this help Example: bash $0 -n no -p yes -m yes" exit 1 } # Parse short and long arguments nginx='yes' phpfpm='yes' mysql='yes' while [ $# -gt 0 ]; do case $1 in -n | --nginx) nginx="$2" shift 2 ;; -p | --phpfpm) phpfpm="$2" shift 2 ;; -m | --mysql) mysql="$2" shift 2 ;; -b | --branch) BRANCH="$2" shift 2 ;; -f | --force) force='yes' shift ;; -l | --local) USE_LOCAL_IP=true shift ;; -h | --help) help ;; *) echo "Unknown option: $1" help ;; esac done # Ensure valid input values validate_choice() { if [ "$1" != "yes" ] && [ "$1" != "no" ]; then echo "${bgred}${white}${bold}Invalid option for $2. Expected [yes|no].${reset}" exit 1 fi } validate_choice "$nginx" "Nginx" validate_choice "$phpfpm" "PHP-FPM" validate_choice "$mysql" "MySQL" # Function to log messages log_message() { echo "$(date +'%Y-%m-%d %H:%M:%S') - $1" >>/var/log/spikster_install.log } # Function to handle errors gracefully handle_error() { echo "${bgred}${white}${bold}Error occurred during $1. Check logs for details. Exiting.${reset}" log_message "Error occurred during $1. Exiting." exit 1 } # Check for existing software versions log_message "Checking current versions of installed software" nginx_version=$(nginx -v 2>&1) php_version=$(php -v 2>&1) mysql_version=$(mysql --version 2>&1) versions="" if dpkg -l | grep -qw nginx; then versions+="Nginx: $nginx_version\n" else versions+="Nginx: Not installed\n" fi if dpkg -l | grep -qw php; then versions+="PHP: $php_version\n" else versions+="PHP: Not installed\n" fi if dpkg -l | grep -qw mysql-server; then versions+="MySQL: $mysql_version\n" else versions+="MySQL: Not installed\n" fi echo -e "$versions" >>/var/log/spikster_install.log # OS Check clear log_message "OS check..." echo "${bggreen}${black}${bold}" echo "OS check..." echo "${reset}" sleep 1s ID=$(grep -oP '(?<=^ID=).+' /etc/os-release | tr -d '"') VERSION=$(grep -oP '(?<=^VERSION_ID=).+' /etc/os-release | tr -d '"') if [ "$ID" = "ubuntu" ]; then case $VERSION in 20.04 | 22.04 | 23.04 | 24.04) ;; *) echo "${bgred}${white}${bold}" echo "Spikster requires a minimum of Linux Ubuntu 20.04 LTS" echo "${reset}" log_message "Unsupported Ubuntu version: $VERSION" exit 1 ;; esac else echo "${bgred}${white}${bold}" echo "Spikster requires a minimum of Linux Ubuntu 20.04 LTS" echo "${reset}" log_message "Unsupported OS: $ID" exit 1 fi # Root check clear log_message "Permission check..." echo "${bggreen}${black}${bold}" echo "Permission check..." echo "${reset}" sleep 1s if [ "$(id -u)" != "0" ]; then echo "${bgred}${white}${bold}" echo "You have to run Spikster as root. (In AWS use 'sudo -s')" echo "${reset}" log_message "Script must be run as root" exit 1 fi # Backup existing configurations backup_configuration() { backup_dir="/root/spikster_backup_$(date +%s)" mkdir -p $backup_dir config_files=( "/etc/nginx" "/etc/mysql" "/etc/php" "/etc/supervisor/conf.d" ) for file in "${config_files[@]}"; do if [ -d $file ]; then cp -r $file $backup_dir fi done log_message "Configuration files backed up to $backup_dir" echo "Backup completed and stored to $backup_dir" } get_local_ip() { local_ip=$(hostname -I | awk '{print $1}') echo $local_ip } # Perform backup backup_configuration # Basic setup clear log_message "Basic setup..." echo "${bggreen}${black}${bold}" echo "Base setup..." echo "${reset}" sleep 1s apt-get update || handle_error "apt-get update" apt-get -y install software-properties-common curl wget nano vim sed zip unzip openssl expect \ dirmngr apt-transport-https lsb-release ca-certificates dnsutils dos2unix zsh htop ffmpeg || handle_error "installing basic packages" # GET IP clear echo "${bggreen}${black}${bold}" echo "Getting IP..." echo "${reset}" sleep 1s if $USE_LOCAL_IP; then IP=$(get_local_ip) else IP=$(curl -s https://checkip.amazonaws.com) fi log_message "Server IP obtained: $IP" # MOTD WELCOME MESSAGE clear echo "${bggreen}${black}${bold}" echo "Motd settings..." echo "${reset}" sleep 1s WELCOME=/etc/motd touch $WELCOME cat >"$WELCOME" <>/etc/fstab log_message "1GB swapfile created and enabled" fi # ALIAS clear echo "${bggreen}${black}${bold}" echo "Custom CLI configuration..." echo "${reset}" sleep 1s shopt -s expand_aliases alias ll='ls -alF' log_message "CLI aliases set" # Spikster DIRS clear echo "${bggreen}${black}${bold}" echo "Spikster directories..." echo "${reset}" sleep 1s mkdir /etc/spikster/ && chmod o-r /etc/spikster mkdir /var/spikster/ && chmod o-r /var/spikster log_message "Spikster directories created" # USER clear echo "${bggreen}${black}${bold}" echo "Spikster root user..." echo "${reset}" sleep 1s # Check if user already exists if id "spikster" &>/dev/null; then echo "${bgyellow}${black}${bold}User 'spikster' already exists. Deleting user...${reset}" userdel -r spikster || handle_error "deleting existing spikster user" log_message "'spikster' user already existed and was deleted" fi pam-auth-update --package || handle_error "updating PAM authentication" useradd -m -s /bin/bash spikster || handle_error "creating spikster user" echo "spikster:$PASS" | chpasswd || handle_error "setting spikster user password" usermod -aG sudo spikster || handle_error "modifying spikster user groups" log_message "Spikster user account created" if [ "$phpfpm" = "yes" ]; then clear log_message "PHP-FPM setup..." echo "${bggreen}${black}${bold}" echo "PHP setup..." echo "${reset}" sleep 1s add-apt-repository -y ppa:ondrej/php || handle_error "adding PPA for PHP" apt-get update || handle_error "apt-get update after adding PPA" apt-get -y install php8.3-fpm php8.3-common php8.3-curl php8.3-bcmath \ php8.3-mbstring php8.3-mysql php8.3-sqlite3 php8.3-pgsql php8.3-redis \ php8.3-memcached php8.3-zip php8.3-xml php8.3-soap php8.3-gd \ php8.3-imagick php8.3-imap php8.3-cli || handle_error "installing PHP packages" if ! command -v php >/dev/null 2>&1; then echo "${bgred}${white}${bold}PHP installation failed${reset}" log_message "PHP installation failed" exit 1 else log_message "PHP installed successfully" fi PHPINI=/etc/php/8.3/fpm/conf.d/spikster.ini touch $PHPINI cat >"$PHPINI" <&2 'ERROR: Invalid installer signature' rm -f composer-setup.php exit 1 fi php composer-setup.php --quiet --install-dir=/usr/local/bin --filename=composer RESULT=$? rm -f composer-setup.php if [ $RESULT -ne 0 ]; then log_message "Composer installation failed" exit $RESULT fi composer --version log_message "Composer installed" fi # GIT clear echo "${bggreen}${black}${bold}" echo "GIT setup..." echo "${reset}" sleep 1s apt-get -y install git ssh-keygen -t rsa -C "git@github.com" -f /etc/spikster/github -q -P "" log_message "GIT installed" # SUPERVISOR clear echo "${bggreen}${black}${bold}" echo "Supervisor setup..." echo "${reset}" sleep 1s apt-get -y install supervisor service supervisor restart log_message "Supervisor installed" # Install Nginx if [ "$nginx" = "yes" ]; then start_nginx() { log_message "Checking Nginx configuration..." nginx -t || handle_error "Nginx configuration check" log_message "Nginx configuration is valid." log_message "Starting Nginx service..." systemctl start nginx.service || handle_error "starting Nginx" systemctl enable nginx.service || handle_error "enabling Nginx" log_message "Nginx started and enabled to start on boot." } clear log_message "Nginx setup..." echo "${bggreen}${black}${bold}" echo "Nginx setup..." echo "${reset}" sleep 1s apt-get -y install nginx-core || handle_error "installing Nginx" start_nginx sed -i -e 's|http {|&\n limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;\n fastcgi_read_timeout 300;|g' /etc/nginx/nginx.conf || handle_error "configuring Nginx" systemctl enable nginx.service || handle_error "enabling Nginx" log_message "Nginx installed" # DEFAULT VHOST clear echo "${bggreen}${black}${bold}" echo "Default vhost..." echo "${reset}" sleep 1s NGINX=/etc/nginx/sites-available/default if test -f "$NGINX"; then unlink NGINX fi touch $NGINX cat >"$NGINX" <"$NODE" </etc/dovecot/dovecot.conf <"$JAIL" <>/usr/lib/systemd/system/user@.service echo 'DefaultStartLimitBurst=50' >>/usr/lib/systemd/system/user@.service echo 'StartLimitBurst=0' >>/usr/lib/systemd/system/user@.service systemctl daemon-reload || handle_error "daemon-reload" # Set up the cron jobs TASK=/etc/cron.d/spikster.crontab touch $TASK cat >"$TASK" < /proc/sys/vm/drop_caches && swapoff -a && swapon -a * * * * * cd /var/www/html && php artisan schedule:run >> /dev/null 2>&1 5 2 * * * cd /var/www/html/utility/spikster-update && sh run.sh >> /dev/null 2>&1 EOF crontab $TASK || handle_error "setting up crontab" systemctl restart nginx.service || handle_error "restarting nginx" log_message "Cron jobs and Nginx restart configured" # Strengthen SSH configuration rpl -i -w "#PasswordAuthentication" "PasswordAuthentication" /etc/ssh/sshd_config rpl -i -w "# PasswordAuthentication" "PasswordAuthentication" /etc/ssh/sshd_config rpl -i -w "PasswordAuthentication no" "PasswordAuthentication yes" /etc/ssh/sshd_config rpl -i -w "PermitRootLogin yes" "PermitRootLogin no" /etc/ssh/sshd_config service sshd restart || handle_error "restarting SSH service" log_message "SSH configuration strengthened" # Supervisor setup for worker processes clear echo "${bggreen}${black}${bold}" echo "Supervisor setup..." echo "${reset}" sleep 1s # Install Supervisor apt-get install -y supervisor || handle_error "installing Supervisor" service supervisor start || handle_error "starting Supervisor" # Create the directory if it doesn't exist mkdir -p /etc/supervisor/conf.d TASK=/etc/supervisor/conf.d/spikster-worker.conf touch $TASK cat >"$TASK" </dev/null; then echo "${bgred}${white}${bold}supervisorctl is missing. Exiting.${reset}" log_message "supervisorctl is missing. Exiting." exit 1 fi supervisorctl reread || handle_error "supervisor reread" supervisorctl update || handle_error "supervisor update" supervisorctl start all || handle_error "supervisor start all" service supervisor restart || handle_error "restarting supervisor" log_message "Supervisor configured" # Additional installations apt install -y bind9 bind9utils bind9-doc || handle_error "installing bind9" apt install -y python3-pip || handle_error "installing Python3 pip" pip install glances bottle fastapi uvicorn || handle_error "installing Python packages" log_message "Additional packages installed: bind9, glances, bottle, fastapi" # Complete clear echo "${bggreen}${black}${bold}" echo "Spikster installation has been completed..." echo "${reset}" sleep 1s # Send notification email upon successful completion email_notification() { local subject="$1" local body="$2" mail -s "$subject" $ADMIN_EMAIL </var/log/glances.log 2>&1 & echo "Glances has been started in the background." # Confirm script completion log_message "Script completed successfully." echo "${bggreen}${black}${bold}" echo "Script completed successfully." echo "${reset}" sleep 1s echo "***********************************************************" echo " SETUP COMPLETE" echo "***********************************************************" echo "" echo " SSH root user: spikster" echo " SSH root pass: $PASS" echo " MySQL root user: spikster" echo " MySQL root pass: $DBPASS" echo "" echo " To manage your server visit: http://$IP" echo " and click on 'dashboard' button." echo " Default credentials are: administrator@localhost / password" echo "" echo "***********************************************************" echo " DO NOT LOSE AND KEEP SAFE THIS DATA" echo "***********************************************************" # Exit script exit 0