#!/bin/bash # Exit on error set -e # Define config file path CONFIG_FILE="/etc/laravel-deploy/config.sh" # Check if config file exists, create if not if [ ! -f "$CONFIG_FILE" ]; then echo "Creating config file at $CONFIG_FILE..." mkdir -p /etc/laravel-deploy cat > "$CONFIG_FILE" << EOL #!/bin/bash # PHP and Node.js versions PHP_V=8.2 NPM_V=23.x # Database and deployment settings DB_NAME="laravel" DB_USER="laravel_user" DB_PASSWORD="your_secure_password" GITHUB_REPO="https://github.com/yourusername/your-repo.git" DOMAIN="yourdomain.com/server IP" PROJECT_PATH="/var/www/laravel" DEPLOY_PATH="$PROJECT_PATH/current" EOL echo "Config file created successfully!" fi # Source the config file to load variables source "$CONFIG_FILE" # Colors for output GREEN='\033[0;32m' NC='\033[0m' echo -e "${GREEN}Starting Laravel server setup...${NC}" # Update system apt-get update apt-get upgrade -y # Add PHP repository via ppa:ondrej apt-get install -y software-properties-common add-apt-repository ppa:ondrej/php -y apt-get update # Install required packages apt-get install -y \ nginx \ mysql-server \ php${PHP_V}-fpm \ php${PHP_V}-cli \ php${PHP_V}-common \ php${PHP_V}-mysql \ php${PHP_V}-mbstring \ php${PHP_V}-xml \ php${PHP_V}-curl \ php${PHP_V}-zip \ php${PHP_V}-gd \ php${PHP_V}-bcmath \ php${PHP_V}-intl \ composer \ git \ supervisor \ unzip \ acl # Install Node.js and NPM curl -fsSL https://deb.nodesource.com/setup_${NPM_V} | bash - apt-get install -y nodejs # Configure MySQL mysql -e "CREATE DATABASE $DB_NAME;" mysql -e "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASSWORD';" mysql -e "GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localhost';" mysql -e "FLUSH PRIVILEGES;" # Configure PHP sed -i 's/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/' /etc/php/${PHP_V}/fpm/php.ini systemctl restart php${PHP_V}-fpm # Configure Nginx cat > /etc/nginx/sites-available/laravel << EOL server { listen 80; listen [::]:80; server_name DOMAIN_PLACEHOLDER; root /var/www/laravel/current/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/php${PHP_V}-fpm.sock; fastcgi_param SCRIPT_FILENAME \$realpath_root\$fastcgi_script_name; include fastcgi_params; fastcgi_hide_header X-Powered-By; } location ~ /\.(?!well-known).* { deny all; } } EOL sed -i "s/DOMAIN_PLACEHOLDER/$DOMAIN/" /etc/nginx/sites-available/laravel ln -sf /etc/nginx/sites-available/laravel /etc/nginx/sites-enabled/ rm -f /etc/nginx/sites-enabled/default systemctl restart nginx # Create deployment structure mkdir -p $PROJECT_PATH/{shared,releases} cd $PROJECT_PATH git clone $GITHUB_REPO releases/initial # Install dependencies cd $PROJECT_PATH/releases/initial composer install --no-dev --optimize-autoloader npm install npm run build # Optimize Laravel php artisan optimize php artisan view:cache php artisan config:cache php artisan route:cache php artisan event:cache # Create shared directories mkdir -p shared touch shared/.env # If storage exists in git, move to shared or create new folders if [ -d "$PROJECT_PATH/releases/initial/storage" ]; then mv "$PROJECT_PATH/releases/initial/storage" "$PROJECT_PATH/shared/" else mkdir -p shared/storage/app/public mkdir -p shared/storage/framework/{cache,sessions,views} mkdir -p shared/storage/logs fi # Set permissions chown -R www-data:www-data $PROJECT_PATH chmod -R 775 $PROJECT_PATH # Create deployment script cat > /usr/local/bin/deploy-laravel << EOL #!/bin/bash set -e # Source the config file to load variables source "\$CONFIG_FILE" TIMESTAMP=\$(date +%Y%m%d_%H%M%S) PROJECT_PATH="/var/www/laravel" RELEASE_PATH="\$PROJECT_PATH/releases/\$TIMESTAMP" SHARED_PATH="\$PROJECT_PATH/shared" CURRENT_PATH="\$PROJECT_PATH/current" # Clone latest code git clone GITHUB_REPO_PLACEHOLDER "\$RELEASE_PATH" cd "\$RELEASE_PATH" # Install dependencies composer install --no-dev --optimize-autoloader npm install npm run build # Link shared resources ln -s "\$SHARED_PATH/.env" "\$RELEASE_PATH/.env" # Safer storage handling in deploy script if [ -d "\$RELEASE_PATH/storage" ]; then if [ ! -d "\$SHARED_PATH/storage" ]; then mv "\$RELEASE_PATH/storage" "\$SHARED_PATH/" else rm -rf "\$RELEASE_PATH/storage" fi fi ln -s "\$SHARED_PATH/storage" "\$RELEASE_PATH/storage" # Optimize Laravel php artisan optimize php artisan view:cache php artisan config:cache php artisan route:cache php artisan event:cache # Make new release live (atomic switch) ln -sfn "\$RELEASE_PATH" "\$CURRENT_PATH" # Cleanup old releases (keep last 5) cd "\$PROJECT_PATH/releases" && ls -t | tail -n +6 | xargs -r rm -rf # Restart PHP-FPM systemctl restart php\$PHP_V-fpm echo "Deployment completed successfully!" EOL # Replace placeholder with actual GitHub repository URL in the deployment script and make it executable sed -i "s|GITHUB_REPO_PLACEHOLDER|$GITHUB_REPO|" /usr/local/bin/deploy-laravel chmod +x /usr/local/bin/deploy-laravel # Create rollback script cat > /usr/local/bin/rollback-laravel << EOL #!/bin/bash set -e # Source the config file to load variables source "\$CONFIG_FILE" # Paths PROJECT_PATH="/var/www/laravel" CURRENT_PATH="\$PROJECT_PATH/current" RELEASES_PATH="\$PROJECT_PATH/releases" # Check if there are at least two releases if [ \$(ls -1 \$RELEASES_PATH | wc -l) -lt 2 ]; then echo "No previous release found. Rollback not possible." exit 1 fi # Identify the previous release (second latest) PREVIOUS_RELEASE=\$(ls -1t \$RELEASES_PATH | head -n 2 | tail -n 1) # Rollback to the previous release echo "Rolling back to \$PREVIOUS_RELEASE..." ln -sfn "\$RELEASES_PATH/\$PREVIOUS_RELEASE" "\$CURRENT_PATH" # Restart services systemctl restart php\$PHP_V-fpm # Ensure this matches your PHP version systemctl restart nginx echo "Rollback to \$PREVIOUS_RELEASE completed successfully!" EOL # Make the rollback script executable chmod +x /usr/local/bin/rollback-laravel # Create initial .env file cd $PROJECT_PATH/releases/initial cp .env.example $PROJECT_PATH/shared/.env # Set up initial symlinks ln -s $PROJECT_PATH/shared/.env $PROJECT_PATH/releases/initial/.env rm -rf $PROJECT_PATH/releases/initial/storage ln -s $PROJECT_PATH/shared/storage $PROJECT_PATH/releases/initial/storage # Make initial release current ln -sfn $PROJECT_PATH/releases/initial $PROJECT_PATH/current echo -e "${GREEN}Setup completed successfully!${NC}" echo -e "${GREEN}Next steps:${NC}" echo "1. Update the shared/.env file with your environment settings" echo "2. Run 'deploy-laravel' whenever you want to deploy new changes"