new-ubuntu-laravel/setup_server_laravel.sh

348 lines
No EOL
10 KiB
Bash

#!/bin/bash
# Script configuration
script_log_file="script_log.log"
backup_dir="/root/config_backup_$(date +%Y%m%d_%H%M%S)"
green_color="\033[1;32m"
red_color="\033[1;31m"
yellow_color="\033[1;33m"
no_color="\033[0m"
# Generate random MySQL password
MYSQL_ROOT_PASSWORD=$(openssl rand -base64 16 | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1)
# Error handling
set -e
trap 'echo "${red_color}Error occurred on line $LINENO${no_color}"' ERR
# Function to log messages
log_message() {
local level=$1
local message=$2
local color=$no_color
case $level in
"INFO") color=$green_color ;;
"WARNING") color=$yellow_color ;;
"ERROR") color=$red_color ;;
esac
echo -e "${color}${message}${no_color}"
echo "$(date '+%Y-%m-%d %H:%M:%S') - $level - $message" >> "$script_log_file"
}
# Function to check command status
check_command_status() {
if [ $? -ne 0 ]; then
log_message "ERROR" "$1 failed"
exit 1
fi
}
# Parse command line arguments
while getopts d: flag; do
case "${flag}" in
d) domain=${OPTARG};;
*)
log_message "ERROR" "Invalid option: -$OPTARG"
exit 1
;;
esac
done
# Check if domain is provided
if [ -z "$domain" ]; then
log_message "ERROR" "Domain parameter is required. Usage: $0 -d example.com"
exit 1
fi
# Main installation process starts here
log_message "INFO" "Starting installation process for $domain"
# Prepare system for installation
log_message "INFO" "Preparing system for installation..."
rm -rf /var/lib/dpkg/lock /var/lib/dpkg/lock-frontend /var/cache/apt/archives/lock
check_command_status "Lock file removal"
# Update system packages
log_message "INFO" "Updating system packages..."
apt-get update -qq
check_command_status "System update"
# Remove Apache if installed
log_message "INFO" "Removing Apache if present..."
apt-get purge apache* -y
systemctl stop apache2 2>/dev/null || true
kill -9 $(lsof -t -i:80) 2>/dev/null || true
kill -9 $(lsof -t -i:443) 2>/dev/null || true
# Install and configure Nginx
log_message "INFO" "Installing and configuring Nginx..."
apt-get install nginx -y
check_command_status "Nginx installation"
# Configure firewall
log_message "INFO" "Configuring firewall..."
ufw --force enable
ufw allow 'Nginx Full'
ufw allow OpenSSH
check_command_status "Firewall configuration"
# Install PHP and extensions
log_message "INFO" "Installing PHP and extensions..."
add-apt-repository ppa:ondrej/php -y
apt-get update
# Install PHP 8.2
apt-get install -y php8.2 php8.2-fpm php8.2-common php8.2-mysql php8.2-xml php8.2-curl \
php8.2-gd php8.2-imagick php8.2-cli php8.2-dev php8.2-imap php8.2-mbstring \
php8.2-opcache php8.2-soap php8.2-zip php8.2-intl php8.2-bcmath
check_command_status "PHP 8.2 installation"
# Install PHP 8.3
apt-get install -y php8.3 php8.3-fpm php8.3-common php8.3-mysql php8.3-xml php8.3-curl \
php8.3-gd php8.3-imagick php8.3-cli php8.3-dev php8.3-imap php8.3-mbstring \
php8.3-opcache php8.3-soap php8.3-zip php8.3-intl php8.3-bcmath
check_command_status "PHP 8.3 installation"
# Install and configure Redis
log_message "INFO" "Installing Redis..."
apt-get install -y redis-server php8.2-redis php8.3-redis
systemctl enable redis-server
systemctl start redis-server
sed -i 's/supervised no/supervised systemd/' /etc/redis/redis.conf
systemctl restart redis-server
check_command_status "Redis installation"
# Install Node.js and NPM
log_message "INFO" "Installing Node.js and NPM..."
apt-get install -y nodejs npm
check_command_status "Node.js installation"
# Install Certbot for SSL
log_message "INFO" "Installing Certbot..."
snap install --classic certbot
ln -sf /snap/bin/certbot /usr/bin/certbot
check_command_status "Certbot installation"
# Configure Nginx for the domain
log_message "INFO" "Configuring Nginx for $domain..."
cat > "/etc/nginx/sites-available/$domain" << 'ENDOFFILE'
server {
listen 80;
listen [::]:80;
server_name DOMAIN_PLACEHOLDER www.DOMAIN_PLACEHOLDER;
root /var/www/html/DOMAIN_PLACEHOLDER/public;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
index index.php;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
ENDOFFILE
# Replace placeholder with actual domain
sed -i "s/DOMAIN_PLACEHOLDER/$domain/g" "/etc/nginx/sites-available/$domain"
# Create web root directory
mkdir -p "/var/www/html/$domain/public"
chown -R www-data:www-data "/var/www/html/$domain"
chmod -R 755 "/var/www/html/$domain"
# Enable the site
ln -sf "/etc/nginx/sites-available/$domain" /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
# Optimize Nginx configuration
cat > /etc/nginx/nginx.conf << 'ENDOFNGINX'
user www-data;
worker_processes auto;
worker_rlimit_nofile 65535;
pid /run/nginx.pid;
events {
worker_connections 65535;
multi_accept on;
use epoll;
}
http {
charset utf-8;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
server_tokens off;
log_not_found off;
types_hash_max_size 2048;
client_max_body_size 16M;
# MIME
include mime.types;
default_type application/octet-stream;
# Logging
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log warn;
# SSL
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Gzip
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml;
# Virtual Host Configs
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
ENDOFNGINX
# Optimize PHP configuration
for version in "8.2" "8.3"; do
phpfpm_conf="/etc/php/$version/fpm/php.ini"
if [ -f "$phpfpm_conf" ]; then
# Optimize PHP settings
sed -i 's/memory_limit = .*/memory_limit = 512M/' "$phpfpm_conf"
sed -i 's/upload_max_filesize = .*/upload_max_filesize = 64M/' "$phpfpm_conf"
sed -i 's/post_max_size = .*/post_max_size = 64M/' "$phpfpm_conf"
sed -i 's/max_execution_time = .*/max_execution_time = 300/' "$phpfpm_conf"
# Configure OpCache
cat >> "$phpfpm_conf" << 'ENDOFPHP'
[opcache]
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.revalidate_freq=0
opcache.validate_timestamps=0
opcache.save_comments=1
opcache.fast_shutdown=1
ENDOFPHP
systemctl restart "php$version-fpm"
fi
done
# Install and configure MySQL if not already installed
if ! command -v mysql &> /dev/null; then
log_message "INFO" "Installing MySQL..."
export DEBIAN_FRONTEND=noninteractive
debconf-set-selections <<< "mysql-server mysql-server/root_password password $MYSQL_ROOT_PASSWORD"
debconf-set-selections <<< "mysql-server mysql-server/root_password_again password $MYSQL_ROOT_PASSWORD"
apt-get install -y mysql-server
# Secure MySQL installation
mysql -e "DELETE FROM mysql.user WHERE User='';"
mysql -e "DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');"
mysql -e "DROP DATABASE IF EXISTS test;"
mysql -e "DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';"
mysql -e "FLUSH PRIVILEGES;"
# Optimize MySQL configuration
cat >> /etc/mysql/mysql.conf.d/mysqld.cnf << 'ENDOFMYSQL'
# Custom optimizations
innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
ENDOFMYSQL
systemctl restart mysql
log_message "INFO" "MySQL root password: $MYSQL_ROOT_PASSWORD"
echo "$MYSQL_ROOT_PASSWORD" > "/var/www/html/mysql_password.txt"
chmod 600 "/var/www/html/mysql_password.txt"
fi
# Setup Laravel Cron Jobs
crontab_content="################## START $domain ####################
* * * * * cd /var/www/html/$domain && php artisan schedule:run >> /dev/null 2>&1
* * * * * cd /var/www/html/$domain && php artisan queue:work --stop-when-empty >> /dev/null 2>&1
################## END $domain ####################"
(crontab -l 2>/dev/null; echo "$crontab_content") | crontab -
# Setup monitoring (Prometheus + Node Exporter)
log_message "INFO" "Setting up monitoring..."
apt-get install -y prometheus node-exporter
# Configure Prometheus
cat > /etc/prometheus/prometheus.yml << 'ENDOFPROMETHEUS'
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'node'
static_configs:
- targets: ['localhost:9100']
ENDOFPROMETHEUS
systemctl enable prometheus node-exporter
systemctl start prometheus node-exporter
# Install Fail2Ban
log_message "INFO" "Installing Fail2Ban..."
apt-get install -y fail2ban
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
systemctl enable fail2ban
systemctl start fail2ban
# Generate SSL certificate
log_message "INFO" "Generating SSL certificate for $domain..."
certbot --nginx -d "$domain" -d "www.$domain" --non-interactive --agree-tos -m "admin@$domain" --redirect
# Final system tweaks
log_message "INFO" "Applying system optimizations..."
cat >> /etc/sysctl.conf << 'ENDOFSYSCTL'
# Custom optimizations
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_fin_timeout = 10
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_keepalive_intvl = 15
ENDOFSYSCTL
sysctl -p
# Clean up
apt-get autoremove -y
apt-get autoclean
# Final restart of services
systemctl restart nginx php8.2-fpm
log_message "INFO" "Installation completed successfully!"
log_message "INFO" "Your MySQL root password is: $MYSQL_ROOT_PASSWORD"
log_message "INFO" "Please save this password in a secure location."