functions/Install-SiteForgeProject.ps1
|
function Install-SiteForgeProject { <# .SYNOPSIS Fully automates deployment of a new website on Ubuntu using PowerShell + NGINX. Handles installs, SSL, firewall, Fail2Ban, and SSH (if needed). .EXAMPLE Install-SiteForgeProject -Domain "example.com" -Repo "git@github.com:Unit-259/example.git" -Email "me@example.com" -UseSSH -EnableFirewall -EnableFail2Ban -AutoDNSCheck -SkipPrompts #> [CmdletBinding()] param( [Parameter(Mandatory = $false)] [string]$Domain, [Parameter(Mandatory = $false)] [string]$Repo, [Parameter(Mandatory = $false)] [string]$Email, [switch]$ForceReinstall, [switch]$UseSSH, [switch]$EnableFirewall, [switch]$EnableFail2Ban, [switch]$SkipPrompts, [switch]$AutoDNSCheck ) # Silence file copy progress $oldPref = $ProgressPreference $ProgressPreference = 'SilentlyContinue' Write-Host "`n🚀 Launching SiteForge Project Installer..." -ForegroundColor Cyan # --- Step 0: Collect inputs --- if (-not $Domain -and -not $SkipPrompts) { $Domain = Read-Host "Enter your primary domain (e.g. example.com)" } if (-not $Repo -and -not $SkipPrompts) { $Repo = Read-Host "Enter your Git repository URL (HTTPS or SSH)" } if (-not $Email -and -not $SkipPrompts) { $Email = Read-Host "Enter your contact email for SSL + SSH key" } if (-not $Domain -or -not $Repo -or -not $Email) { Write-Host "❌ Missing required parameters. Use -SkipPrompts for unattended mode." -ForegroundColor Red $ProgressPreference = $oldPref return } if ($UseSSH -or -not $SkipPrompts) { if (-not $UseSSH) { $privateRepo = Read-Host "Is this a PRIVATE repository that requires SSH? (y/N)" $UseSSH = $privateRepo.Trim().ToLower() -in @('y','yes') } } else { $UseSSH = $false } # --- Step 0.5: DNS validation --- if ($AutoDNSCheck) { Write-Host "`n🌍 Auto DNS check enabled — verifying $Domain..." -ForegroundColor Cyan for ($i = 1; $i -le 10; $i++) { Write-Host "🔎 Attempt $i/10..." -ForegroundColor Gray if (Test-SiteForgeDNS -Domain $Domain) { Write-Host "✅ DNS successfully resolves to this server!" -ForegroundColor Green break } else { if ($i -lt 10) { Write-Host "⚠️ DNS not ready yet — retrying in 30 seconds..." -ForegroundColor Yellow Start-Sleep -Seconds 30 } else { Write-Host "❌ DNS still not pointing to this server after 10 attempts. Exiting." -ForegroundColor Red $ProgressPreference = $oldPref return } } } } else { if (-not (Test-SiteForgeDNS -Domain $Domain)) { Write-Host "`n⚠️ DNS is not yet pointing to this server." -ForegroundColor Yellow Write-Host " Please update your A record to this server's IP and rerun Install-SiteForgeProject." -ForegroundColor DarkGray $ProgressPreference = $oldPref return } } # --- Step 1: Force reinstall logic --- if ($ForceReinstall) { Write-Host "`n⚠️ Force reinstall mode activated for $Domain" -ForegroundColor Yellow if (-not $SkipPrompts) { $confirm = Read-Host "This will delete NGINX config, SSL certs, site files, and SiteForge vars. Proceed? (y/N)" if ($confirm.Trim().ToLower() -notin @('y','yes')) { Write-Host "❌ Operation cancelled." $ProgressPreference = $oldPref return } } Write-Host "`n🧹 Cleaning up old configuration..." -ForegroundColor Yellow try { sudo systemctl stop nginx *> $null 2>&1 sudo rm -f "/etc/nginx/sites-available/$Domain" "/etc/nginx/sites-enabled/$Domain" *> $null 2>&1 sudo rm -rf "/etc/letsencrypt/live/$Domain" "/etc/letsencrypt/renewal/$Domain.conf" "/var/www/html/*" *> $null 2>&1 if (Test-Path $PROFILE) { (Get-Content $PROFILE) | Where-Object { $_ -notmatch 'SiteForge Variables' -and $_ -notmatch '\$gitRepo|\$webDomain|\$emailAddr' } | Set-Content $PROFILE } if (-not $SkipPrompts) { $sshConfirm = Read-Host "Do you also want to delete your SSH key (~/.ssh/id_ed25519)? (y/N)" if ($sshConfirm.Trim().ToLower() -in @('y','yes')) { sudo rm -f ~/.ssh/id_ed25519 ~/.ssh/id_ed25519.pub *> $null 2>&1 Write-Host "🗝️ SSH keys deleted." } } sudo systemctl start nginx *> $null 2>&1 Write-Host "✅ Reinstall cleanup complete." } catch { Write-Host "⚠️ Cleanup encountered an error: $_" -ForegroundColor Red } } # --- Step 2: Install dependencies --- Write-Host "`n📦 Installing required packages..." -ForegroundColor Yellow sudo apt-get update -y *> $null 2>&1 sudo apt-get upgrade -y *> $null 2>&1 sudo apt-get install -y nginx git curl software-properties-common certbot python3-certbot-nginx *> $null 2>&1 # --- Step 3: Optional SSH key generation --- if ($UseSSH) { if (-not (Test-Path -Path ~/.ssh/id_ed25519)) { Write-Host "`n🔑 Generating new SSH key..." ssh-keygen -t ed25519 -C $Email -f ~/.ssh/id_ed25519 -N "" *> $null 2>&1 Write-Host "`n📋 Public SSH key (add to GitHub Deploy Keys):" -ForegroundColor Yellow cat ~/.ssh/id_ed25519.pub Read-Host "`nPress Enter once you've added the key to GitHub" } else { Write-Host "✅ SSH key already exists — skipping generation." } } else { Write-Host "🔓 Skipping SSH key generation (public repo)." } # --- Step 3.5: Optional Security Hardening --- if ($EnableFirewall -or (-not $SkipPrompts -and (Read-Host "Would you like to enable and lock down the firewall to ports 22, 80, and 443? (Y/n)") -notin @('n','no'))) { Write-Host "`n🛡️ Enabling firewall..." -ForegroundColor Yellow Enable-Firewall *> $null 2>&1 } if ($EnableFail2Ban -or (-not $SkipPrompts -and (Read-Host "Would you like to install and enable Fail2Ban for brute-force protection? (Y/n)") -notin @('n','no'))) { Write-Host "`n🚨 Installing Fail2Ban..." -ForegroundColor Yellow Enable-Fail2Ban *> $null 2>&1 } # --- Step 4: Ensure PowerShell profile exists --- if (-not (Test-Path -Path $PROFILE)) { Write-Host "Creating PowerShell profile..." $profileDir = Split-Path -Parent $PROFILE if (-not (Test-Path -Path $profileDir)) { New-Item -ItemType Directory -Path $profileDir -Force *> $null 2>&1 } New-Item -ItemType File -Path $PROFILE -Force *> $null 2>&1 } # --- Step 5: Persist variables + helper functions --- $varsBlock = @" # SiteForge Variables `$gitRepo = '$Repo' `$webDomain = '$Domain' `$emailAddr = '$Email' Import-Module SiteForge -Force "@ $helpers = @' # --- SiteForge Helper Functions --- function errorLogs { sudo tail -f /var/log/nginx/error.log } function nginxConfig { sudo nano "/etc/nginx/sites-available/$webDomain" } function catnginxConfig{ sudo cat "/etc/nginx/sites-available/$webDomain" } function restartNginx { sudo nginx -t && sudo systemctl reload nginx } '@ $content = Get-Content $PROFILE -Raw $content = $content -replace '(?s)# SiteForge Variables.*?(?=# ---|$)', '' $content += "`n$varsBlock`n$helpers" Set-Content -Path $PROFILE -Value $content Start-Sleep -Seconds 1 . $PROFILE # --- Step 7: Deploy initial site --- Write-Host "`n🌍 Deploying website for $Domain..." -ForegroundColor Cyan $webRoot = "/var/www/html" sudo mkdir -p $webRoot *> $null 2>&1 cd /root/ git clone $Repo tempdir *> $null 2>&1 if (Test-Path "./tempdir/html") { Get-ChildItem "./tempdir/html" -Recurse | Move-Item -Destination $webRoot -Force } else { Get-ChildItem "./tempdir" -Recurse -Exclude '.git','README.md' | Move-Item -Destination $webRoot -Force } Remove-Item -Recurse -Force ./tempdir *> $null 2>&1 # --- Step 8: Create NGINX config --- $configPath = "/etc/nginx/sites-available/$Domain" if (-not (Test-Path $configPath)) { Write-Host "`n⚙️ Creating NGINX configuration..." -ForegroundColor Yellow $nginxConfig = @' server { listen 80; server_name DOMAIN_PLACEHOLDER www.DOMAIN_PLACEHOLDER; root /var/www/html; index index.html index.htm index.php; location / { try_files $uri $uri/ /index.html; } } '@ -replace 'DOMAIN_PLACEHOLDER', $Domain $nginxConfig | sudo tee $configPath > $null sudo ln -sf $configPath "/etc/nginx/sites-enabled/$Domain" *> $null 2>&1 } # --- Step 9: Obtain SSL cert --- Write-Host "`n🔐 Requesting Let's Encrypt SSL certificate..." -ForegroundColor Yellow sudo nginx -t *> $null 2>&1 sudo certbot --nginx --non-interactive --agree-tos --email $Email -d $Domain -d "www.$Domain" *> $null 2>&1 # --- Step 10: Reload NGINX --- sudo nginx -t *> $null 2>&1 sudo systemctl reload nginx *> $null 2>&1 # --- Step 11: Success summary --- Write-Host "`n✅ SiteForge setup complete!" -ForegroundColor Green Write-Host "🌐 Website: https://$Domain" Write-Host "📂 Web root: /var/www/html" Write-Host "🧩 Config: /etc/nginx/sites-available/$Domain" Write-Host "💾 Repo: $Repo" Write-Host "`nRun 'update-Website' anytime to redeploy from Git." -ForegroundColor Cyan # --- Step 12: Reload profile & status --- Write-Host "`n🔄 Reloading PowerShell profile..." -ForegroundColor Yellow Start-Sleep -Seconds 2 & pwsh -NoLogo -Command ". $PROFILE; Get-SiteForgeStatus" # Restore preference and exit $ProgressPreference = $oldPref exit } |