Last active
June 19, 2026 08:19
-
-
Save MostafaNorzade/0af3fdad035f027982e6c4aa9834a2fe to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # setup-laravel-php84-ssh.sh | |
| # Automated Laravel setup on Ubuntu with PHP 8.4 and SSH keys for GitLab (using non‑root deploy user) | |
| set -e | |
| if [[ $EUID -ne 0 ]]; then | |
| echo "This script must be run with sudo!" | |
| exit 1 | |
| fi | |
| # --------------------------------------------- | |
| # 1. System packages and PHP 8.4 | |
| # --------------------------------------------- | |
| echo "➡️ Installing prerequisites and PHP 8.4..." | |
| apt update && apt upgrade -y | |
| apt install -y sudo curl gnupg lsb-release software-properties-common | |
| add-apt-repository ppa:ondrej/php -y | |
| apt update | |
| apt install -y php8.4 php8.4-fpm php8.4-mbstring php8.4-xml php8.4-curl php8.4-zip \ | |
| php8.4-bcmath php8.4-mysql php8.4-cli php8.4-intl php8.4-gd \ | |
| unzip git composer redis-server mysql-server nginx acl supervisor | |
| # --------------------------------------------- | |
| # 2. Start and enable services | |
| # --------------------------------------------- | |
| for service in nginx php8.4-fpm redis-server mysql supervisor; do | |
| systemctl enable --now $service | |
| if ! systemctl is-active --quiet $service; then | |
| echo "❌ Service $service is not active!" | |
| exit 1 | |
| fi | |
| done | |
| # --------------------------------------------- | |
| # 3. Database setup | |
| # --------------------------------------------- | |
| read -p "Enter Laravel database name: " DB_NAME | |
| read -p "Enter database username: " DB_USER | |
| read -s -p "Enter database password: " DB_PASS | |
| echo | |
| mysql -u root <<MYSQL_SCRIPT | |
| CREATE DATABASE IF NOT EXISTS $DB_NAME CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; | |
| CREATE USER IF NOT EXISTS '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS'; | |
| GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localhost'; | |
| FLUSH PRIVILEGES; | |
| MYSQL_SCRIPT | |
| # --------------------------------------------- | |
| # 4. Create deploy user | |
| # --------------------------------------------- | |
| if ! id -u deploy &>/dev/null; then | |
| useradd -m -s /bin/bash deploy | |
| echo "✅ User 'deploy' created." | |
| else | |
| if [ ! -d "/home/deploy" ]; then | |
| mkdir -p /home/deploy | |
| chown deploy:deploy /home/deploy | |
| usermod -d /home/deploy deploy | |
| echo "✅ Home directory for 'deploy' created." | |
| fi | |
| fi | |
| mkdir -p /home/deploy/.ssh | |
| chmod 700 /home/deploy/.ssh | |
| chown -R deploy:deploy /home/deploy/.ssh | |
| # --------------------------------------------- | |
| # 5. SSH key for GitLab | |
| # --------------------------------------------- | |
| SSH_KEY="/home/deploy/.ssh/id_ed25519" | |
| if [ ! -f "$SSH_KEY" ]; then | |
| echo "➡️ Generating SSH key..." | |
| sudo -u deploy ssh-keygen -t ed25519 -C "laravel-server-key" -f "$SSH_KEY" -N "" | |
| echo "Add this public key to GitLab → Settings → SSH Keys:" | |
| echo | |
| cat "$SSH_KEY.pub" | |
| echo | |
| read -p "Press Enter after adding the key to GitLab..." | |
| fi | |
| # --------------------------------------------- | |
| # 6. Git clone / pull | |
| # --------------------------------------------- | |
| PROJECT_DIR="/var/www/laminor" | |
| read -p "Enter GitLab SSH URL: " GIT_SSH_URL | |
| read -p "Enter branch name (default: master): " BRANCH_NAME | |
| BRANCH_NAME=${BRANCH_NAME:-master} | |
| if [ ! -d "$PROJECT_DIR" ]; then | |
| sudo -u deploy git clone --branch "$BRANCH_NAME" --single-branch "$GIT_SSH_URL" "$PROJECT_DIR" \ | |
| || { echo "❌ Git clone failed"; exit 1; } | |
| else | |
| cd "$PROJECT_DIR" || exit | |
| sudo -u deploy git fetch origin "$BRANCH_NAME" || { echo "❌ git fetch failed"; exit 1; } | |
| sudo -u deploy git checkout "$BRANCH_NAME" || { echo "❌ git checkout failed"; exit 1; } | |
| sudo -u deploy git pull origin "$BRANCH_NAME" || { echo "❌ git pull failed"; exit 1; } | |
| fi | |
| cd "$PROJECT_DIR" || exit | |
| # --------------------------------------------- | |
| # 7. Composer install | |
| # --------------------------------------------- | |
| read -p "Enter username for nx.laminor.org: " COMPOSER_USERNAME | |
| read -sp "Enter password/token for nx.laminor.org: " COMPOSER_PASSWORD | |
| echo | |
| sudo -u deploy composer config --global http-basic.nx.laminor.org "$COMPOSER_USERNAME" "$COMPOSER_PASSWORD" | |
| sudo -u deploy composer install --no-dev --optimize-autoloader --no-interaction \ | |
| || { echo "❌ Composer install failed"; exit 1; } | |
| # --------------------------------------------- | |
| # 8. .env configuration | |
| # --------------------------------------------- | |
| if [ -f ".env" ]; then | |
| read -p ".env file exists, overwrite it? (y/N): " ENV_ANSWER | |
| if [[ "$ENV_ANSWER" =~ ^[Yy]$ ]]; then | |
| cp .env.example .env | |
| else | |
| echo "❌ Installation aborted." | |
| exit 1 | |
| fi | |
| else | |
| cp .env.example .env | |
| fi | |
| sed -i "s/DB_DATABASE=.*/DB_DATABASE=$DB_NAME/" .env | |
| sed -i "s/DB_USERNAME=.*/DB_USERNAME=$DB_USER/" .env | |
| sed -i "s/DB_PASSWORD=.*/DB_PASSWORD=$DB_PASS/" .env | |
| sed -i "s/DB_HOST=.*/DB_HOST=127.0.0.1/" .env | |
| sed -i "s/APP_KEY=.*/APP_KEY=/" .env | |
| read -p "Enter APP_URL: " APP_URL | |
| if [ -n "$APP_URL" ]; then | |
| sed -i "s|APP_URL=.*|APP_URL=$APP_URL|" .env | |
| fi | |
| sed -i "s/REDIS_HOST=.*/REDIS_HOST=127.0.0.1/" .env | |
| sed -i "s/REDIS_PASSWORD=.*/REDIS_PASSWORD=null/" .env | |
| sed -i "s/REDIS_PORT=.*/REDIS_PORT=6379/" .env | |
| chown deploy:deploy "$PROJECT_DIR/.env" | |
| # --------------------------------------------- | |
| # 9. Disable IgnitionServiceProvider | |
| # --------------------------------------------- | |
| if grep -q "Spatie\\\\LaravelIgnition\\\\IgnitionServiceProvider" config/app.php; then | |
| sed -i 's/\(.*Spatie\\LaravelIgnition\\IgnitionServiceProvider.*\)/\/\/ \1/' config/app.php | |
| fi | |
| # --------------------------------------------- | |
| # 10. Laravel key and migrations | |
| # --------------------------------------------- | |
| sudo -u deploy php artisan key:generate || { echo "❌ key:generate failed"; exit 1; } | |
| sudo -u deploy php artisan config:cache | |
| sudo -u deploy php artisan route:cache | |
| sudo -u deploy php artisan view:cache | |
| sudo -u deploy php artisan migrate --seed || { echo "❌ migrate failed"; exit 1; } | |
| # --------------------------------------------- | |
| # 11. Permissions | |
| # --------------------------------------------- | |
| chown -R deploy:www-data "$PROJECT_DIR/storage" "$PROJECT_DIR/bootstrap/cache" | |
| find "$PROJECT_DIR/storage" -type d -exec chmod 775 {} \; | |
| find "$PROJECT_DIR/storage" -type f -exec chmod 664 {} \; | |
| find "$PROJECT_DIR/bootstrap/cache" -type d -exec chmod 775 {} \; | |
| find "$PROJECT_DIR/bootstrap/cache" -type f -exec chmod 664 {} \; 2>/dev/null || true | |
| setfacl -R -m u:www-data:rwx "$PROJECT_DIR/storage/logs" 2>/dev/null || true | |
| # --------------------------------------------- | |
| # 12. Supervisor configuration | |
| # --------------------------------------------- | |
| echo "➡️ Configuring Supervisor..." | |
| mkdir -p /var/log/supervisor/laravel | |
| # Laravel Queue Worker | |
| cat > /etc/supervisor/conf.d/laravel-worker.conf <<EOF | |
| [program:laravel-worker] | |
| process_name=%(program_name)s_%(process_num)02d | |
| command=php $PROJECT_DIR/artisan queue:work redis --sleep=3 --tries=3 --max-time=3600 | |
| autostart=true | |
| autorestart=true | |
| stopasgroup=true | |
| killasgroup=true | |
| user=deploy | |
| numprocs=2 | |
| redirect_stderr=true | |
| stdout_logfile=/var/log/supervisor/laravel/worker.log | |
| stopwaitsecs=60 | |
| EOF | |
| # Laravel Scheduler | |
| cat > /etc/supervisor/conf.d/laravel-schedule.conf <<EOF | |
| [program:laravel-schedule] | |
| process_name=%(program_name)s | |
| command=sh -c "php $PROJECT_DIR/artisan schedule:run --no-ansi && sleep 60" | |
| autostart=true | |
| autorestart=true | |
| user=deploy | |
| redirect_stderr=true | |
| stdout_logfile=/var/log/supervisor/laravel/schedule.log | |
| EOF | |
| # Reload supervisor | |
| supervisorctl reread | |
| supervisorctl update | |
| supervisorctl start laravel-worker:* | |
| supervisorctl start laravel-schedule | |
| echo "✅ Supervisor configured:" | |
| supervisorctl status | |
| # --------------------------------------------- | |
| # 13. Nginx configuration | |
| # --------------------------------------------- | |
| NGINX_AVAILABLE="/etc/nginx/sites-available/laminor.conf" | |
| NGINX_ENABLED="/etc/nginx/sites-enabled/laminor.conf" | |
| mkdir -p /etc/nginx/sites-available /etc/nginx/sites-enabled | |
| cat > "$NGINX_AVAILABLE" <<EOL | |
| server { | |
| listen 80; | |
| server_name _; | |
| root $PROJECT_DIR/public; | |
| index index.php index.html; | |
| location / { | |
| try_files \$uri \$uri/ /index.php?\$query_string; | |
| } | |
| location ~ \.php\$ { | |
| include snippets/fastcgi-php.conf; | |
| fastcgi_pass unix:/run/php/php8.4-fpm.sock; | |
| fastcgi_param SCRIPT_FILENAME \$realpath_root\$fastcgi_script_name; | |
| include fastcgi_params; | |
| } | |
| location ~ /\.ht { | |
| deny all; | |
| } | |
| fastcgi_read_timeout 300; | |
| proxy_read_timeout 300; | |
| } | |
| EOL | |
| rm -f "$NGINX_ENABLED" | |
| ln -s "$NGINX_AVAILABLE" "$NGINX_ENABLED" | |
| rm -f /etc/nginx/sites-enabled/default | |
| nginx -t || { echo "❌ Nginx test failed"; exit 1; } | |
| systemctl reload nginx | |
| systemctl restart php8.4-fpm | |
| echo "" | |
| echo "✅ Laravel project is ready!" | |
| echo "📌 Supervisor status:" | |
| supervisorctl status | |
| # ============================================================ | |
| # 🧰 دستورات کمکی – کامنت شده (برای استفاده بعدی) | |
| # ============================================================ | |
| # | |
| # --- انتقال فایل دیتابیس از لوکال به سرور --- | |
| # scp core.sql ubuntu@IP_SERVER:~ | |
| # | |
| # --- وارد کردن (import) فایل دیتابیس در دیتابیس موجود (تغییر با اسم واقعی) --- | |
| # sudo mysql database_name < /home/ubuntu/core.sql | |
| # | |
| # --- یا با کاربر معمولی (اگر دسترسی SUPER نباشد) --- | |
| # sed -i 's/\s*DEFINER=`[^`]*`@`[^`]*`//g' /home/ubuntu/core.sql | |
| # mysql -u username -p database_name < /home/ubuntu/core.sql | |
| # | |
| # --- اگر خطای Table already exists رخ داد، میتوانید جداول را قبل از import پاک کنید --- | |
| # sudo -u deploy php artisan db:wipe | |
| # سپس import را دوباره انجام دهید. | |
| # | |
| # --- تنظیمات دستی دیتابیس پس از import --- | |
| # sudo mysql -u root -p | |
| # CREATE DATABASE IF NOT EXISTS database_name; | |
| # GRANT ALL PRIVILEGES ON database_name.* TO 'username'@'localhost'; | |
| # FLUSH PRIVILEGES; | |
| # | |
| # --- اصلاح مستقیم DB_HOST در فایل .env (در صورت بروز خطای اتصال به دیتابیس) --- | |
| # sed -i "s/DB_HOST=.*/DB_HOST=127.0.0.1/" /var/www/laminor/.env | |
| # sudo -u deploy php artisan config:clear | |
| # | |
| # --- بررسی وضعیت سرویسها --- | |
| # systemctl status nginx php8.4-fpm redis-server mysql | |
| # | |
| # --- مشاهده خطاهای Nginx --- | |
| # tail -f /var/log/nginx/error.log | |
| # | |
| # --- مشاهده خطاهای PHP-FPM --- | |
| # tail -f /var/log/php8.4-fpm.log | |
| # | |
| # --- خالی کردن کش لاراول --- | |
| # cd /var/www/laminor | |
| # sudo -u deploy php artisan config:clear | |
| # sudo -u deploy php artisan cache:clear | |
| # sudo -u deploy php artisan view:clear | |
| # sudo systemctl restart php8.4-fpm | |
| # | |
| # ============================================================ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment