Skip to content

Instantly share code, notes, and snippets.

@afiqiqmal
Created June 21, 2025 07:06
Show Gist options
  • Save afiqiqmal/ea72c0c727ba5bf0cf3881dcd4e5a40b to your computer and use it in GitHub Desktop.
Save afiqiqmal/ea72c0c727ba5bf0cf3881dcd4e5a40b to your computer and use it in GitHub Desktop.
Initial setup for ubuntu + Laravel
#!/bin/bash
# Server Provisioning Script
# Edit these variables before running the script
################
### CONFIGURATION VARIABLES ###
################
USER="your_username" # Replace with desired username
USER_PASSWORD="your_secure_password" # Replace with desired user password
PROJECT_NAME="your_project" # Replace with project name
PROJECT_GIT_URL="https://github.com/user/repo.git" # Replace with your git repository URL
OCTANE_PORT="2706" # Port for Laravel Octane
OCTANE_WORKERS="2" # Number of Octane workers
OCTANE_TASK_WORKERS="2" # Number of Octane task workers
OCTANE_MAX_REQUESTS="300" # Max requests per worker
################
### SCRIPT START ###
################
set -e # Exit on any error
echo "================================================"
echo "Starting Server Provisioning..."
echo "User: $USER"
echo "Project: $PROJECT_NAME"
echo "================================================"
################
### INITIAL SETUP ###
################
echo "Step 1: Updating system packages..."
sudo apt update
echo "Step 2: Adding new user: $USER"
if ! id "$USER" &>/dev/null; then
sudo adduser --disabled-password --gecos "" $USER
echo "$USER:$USER_PASSWORD" | sudo chpasswd
sudo usermod -aG sudo $USER
echo "User $USER created successfully with password"
else
echo "User $USER already exists, updating password..."
echo "$USER:$USER_PASSWORD" | sudo chpasswd
echo "Password updated for user $USER"
fi
echo "Step 3: Setting up SSH access for $USER"
sudo mkdir -p /home/$USER/.ssh
sudo cp ~/.ssh/authorized_keys /home/$USER/.ssh/ 2>/dev/null || echo "No SSH keys to copy"
sudo chown -R $USER:$USER /home/$USER/.ssh
sudo chmod 700 /home/$USER/.ssh
sudo chmod 600 /home/$USER/.ssh/authorized_keys 2>/dev/null || true
echo "Step 4: Configuring UFW firewall..."
sudo ufw --force enable
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
echo "Step 5: Removing Apache if installed..."
sudo systemctl stop apache2 2>/dev/null || true
sudo apt-get purge -y apache2 apache2-utils apache2-bin apache2-common 2>/dev/null || true
sudo apt-get autoremove -y
echo "Step 6: Installing system dependencies..."
sudo apt install -y libcurl4-openssl-dev acl unzip
echo "Step 7: Installing Nginx..."
sudo apt install -y nginx nginx-extras
sudo systemctl enable nginx
sudo systemctl start nginx
echo "Step 8: Installing PHP and extensions..."
sudo apt install -y php php-fpm php-cli php-gd php-dom php-xml php-zip php-redis php-bcmath php-mbstring php-intl php-opcache php-mysql php-pgsql php-curl php-dev php-pear
echo "Step 9: Installing Swoole extension..."
sudo pecl install swoole
# Create swoole.ini
PHP_VERSION=$(php -r "echo PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION;")
echo "extension=swoole.so" | sudo tee /etc/php/$PHP_VERSION/mods-available/swoole.ini
sudo phpenmod swoole
echo "Step 10: Installing Composer..."
curl -sS https://getcomposer.org/installer -o /tmp/composer-setup.php
EXPECTED_CHECKSUM="$(wget -q -O - https://composer.github.io/installer.sig)"
ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', '/tmp/composer-setup.php');")"
if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]; then
echo "ERROR: Invalid Composer installer checksum"
rm /tmp/composer-setup.php
exit 1
fi
sudo php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer
rm /tmp/composer-setup.php
echo "Step 11: Installing Node.js via NVM..."
# Install NVM for current user
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
# Install Node.js and Bun
nvm install 23
npm install -g bun
echo "Step 12: Installing Supervisor..."
sudo apt install -y supervisor
sudo systemctl enable supervisor
sudo systemctl start supervisor
################
### PROJECT SETUP ###
################
echo "================================================"
echo "Setting up project: $PROJECT_NAME"
echo "================================================"
echo "Step 13: Creating project directory..."
sudo mkdir -p /var/www/$PROJECT_NAME/app
sudo chown $USER:www-data /var/www/$PROJECT_NAME/app
echo "Step 14: Cloning project repository..."
cd /var/www/$PROJECT_NAME/app
if [ -d ".git" ]; then
echo "Git repository already exists, pulling latest changes..."
git pull
else
git clone $PROJECT_GIT_URL .
fi
echo "Step 15: Installing Composer dependencies..."
composer install --no-dev --optimize-autoloader
echo "Step 16: Installing Node.js dependencies and building assets..."
bun install
bun run build
echo "Step 17: Setting correct permissions..."
sudo chown -R $USER:www-data /var/www/$PROJECT_NAME/app
sudo find /var/www/$PROJECT_NAME/app -type d -exec chmod 775 {} \;
sudo find /var/www/$PROJECT_NAME/app -type f -exec chmod 664 {} \;
sudo chgrp -R www-data storage bootstrap/cache
sudo chmod -R ug+rwx storage bootstrap/cache
sudo rm -rf storage/logs/daily 2>/dev/null || true
sudo setfacl -d -m g::rwx storage/logs
echo "Step 18: Setting up cron job for Laravel scheduler..."
(sudo crontab -u www-data -l 2>/dev/null; echo "* * * * * php /var/www/$PROJECT_NAME/app/artisan schedule:run >> /dev/null 2>&1") | sudo crontab -u www-data -
echo "Step 19: Setting up Supervisor configuration for Octane..."
sudo tee /etc/supervisor/conf.d/${PROJECT_NAME}-octane.conf > /dev/null <<EOF
[program:${PROJECT_NAME}_octane]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/$PROJECT_NAME/app/artisan octane:start --server=swoole --workers=$OCTANE_WORKERS --task-workers=$OCTANE_TASK_WORKERS --port=$OCTANE_PORT --max-requests=$OCTANE_MAX_REQUESTS
autostart=true
autorestart=true
user=www-data
group=www-data
redirect_stderr=true
stdout_logfile=/var/www/$PROJECT_NAME/app/storage/logs/octane.log
stopwaitsecs=3600
EOF
echo "Step 20: Setting up Supervisor configuration for Horizon..."
sudo tee /etc/supervisor/conf.d/${PROJECT_NAME}-horizon.conf > /dev/null <<EOF
[program:${PROJECT_NAME}_horizon]
process_name=%(program_name)s
command=php /var/www/$PROJECT_NAME/app/artisan horizon
autostart=true
autorestart=true
user=www-data
redirect_stderr=false
stdout_logfile=/var/www/$PROJECT_NAME/app/storage/logs/horizon.log
stderr_logfile=/var/www/$PROJECT_NAME/app/storage/logs/horizon-error.log
stopwaitsecs=3600
EOF
echo "Step 21: Updating Supervisor configuration..."
sudo supervisorctl reread
sudo supervisorctl update
echo "Step 22: Starting Supervisor services..."
sudo supervisorctl start ${PROJECT_NAME}_octane:*
sudo supervisorctl start ${PROJECT_NAME}_horizon:*
################
### FINAL STEPS ###
################
echo "================================================"
echo "Provisioning Complete!"
echo "================================================"
echo "Server IP: $(curl -4 -s icanhazip.com)"
echo "Project Location: /var/www/$PROJECT_NAME/app"
echo "Octane Port: $OCTANE_PORT"
echo ""
echo "Next Steps:"
echo "1. Configure your .env file in /var/www/$PROJECT_NAME/app"
echo "2. Run database migrations: php artisan migrate"
echo "3. Configure Nginx virtual host for your domain"
echo "4. Set up SSL certificates"
echo ""
echo "Supervisor Status:"
sudo supervisorctl status
echo ""
echo "Setup completed successfully!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment