From 7f204426edcba37a0e5234ad21e44902406e6be5 Mon Sep 17 00:00:00 2001 From: DeNNiiInc Date: Sat, 27 Dec 2025 17:11:42 +1100 Subject: [PATCH] Add deployment scripts and config --- .gitignore | 3 + PROXMOX_DEPLOY_TEMPLATE.md | 211 ++++++++++++++++++++++++++++++++++++ config/nginx.conf.template | 25 +++++ deploy-to-proxmox.ps1 | 75 +++++++++++++ ecosystem.config.js | 14 +++ scripts/setup-server.sh | 50 +++++++++ scripts/sync-and-restart.sh | 44 ++++++++ 7 files changed, 422 insertions(+) create mode 100644 PROXMOX_DEPLOY_TEMPLATE.md create mode 100644 config/nginx.conf.template create mode 100644 deploy-to-proxmox.ps1 create mode 100644 ecosystem.config.js create mode 100644 scripts/setup-server.sh create mode 100644 scripts/sync-and-restart.sh diff --git a/.gitignore b/.gitignore index 37d7e73..1b496df 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ node_modules .env +deploy-secrets.json +config/secrets.env +scripts/auth.json diff --git a/PROXMOX_DEPLOY_TEMPLATE.md b/PROXMOX_DEPLOY_TEMPLATE.md new file mode 100644 index 0000000..5d21676 --- /dev/null +++ b/PROXMOX_DEPLOY_TEMPLATE.md @@ -0,0 +1,211 @@ +# 🚀 Proxmox Deployment Template (TurnKey Node.js) + +**Use this guide to deploy ANY Node.js application to a TurnKey Linux LXC Container.** + +--- + +## 📋 Prerequisites + +1. **Project**: A Node.js application (Express, Next.js, etc.) in a Git repository. +2. **Server**: A Proxmox TurnKey Node.js Container. +3. **Access**: Root SSH password for the container. +4. **Domain (Optional)**: If using Cloudflare Tunnel. + +--- + +## 🛠️ Step 1: Prepare Your Project + +Ensure your project is ready for production: + +1. **Port Configuration**: Ensure your app listens on a configurable port or a fixed internal port (e.g., `4001`). + ```javascript + // server.js + const PORT = process.env.PORT || 4001; + app.listen(PORT, ...); + ``` + +2. **Git Ignore**: Ensure `node_modules` and config files with secrets are ignored. + ```gitignore + node_modules/ + .env + config.json + ``` + +--- + +## 🖥️ Step 2: One-Time Server Setup + +SSH into your new container: +```bash +ssh root@ +``` + +Run these commands to prepare the environment: + +### 1. Install Essentials +```bash +apt-get update && apt-get install -y git +``` + +### 2. Prepare Directory +```bash +# Standard web directory +mkdir -p /var/www/ +cd /var/www/ + +# Clone your repo (Use Basic Auth with Token if private) +# Format: https://:@github.com//.git +git clone . + +# Install dependencies +npm install +``` + +### 3. Setup Permissions +```bash +# Give ownership to www-data (Nginx user) +chown -R www-data:www-data /var/www/ +``` + +--- + +## ⚙️ Step 3: Application Configuration + +### 1. Systemd Service +Create a service file to keep your app running. + +Create `/etc/systemd/system/.service`: +```ini +[Unit] +Description= Service +After=network.target + +[Service] +Type=simple +User=root +# OR use 'www-data' if app doesn't need root ports +# User=www-data +WorkingDirectory=/var/www/ +ExecStart=/usr/local/bin/node server.js +Restart=always +Environment=NODE_ENV=production +Environment=PORT=4001 + +[Install] +WantedBy=multi-user.target +``` + +Enable and start: +```bash +systemctl daemon-reload +systemctl enable +systemctl start +``` + +### 2. Nginx Reverse Proxy +Configure Nginx to forward port 80 to your app (Port 4001). + +Create `/etc/nginx/sites-available/`: +```nginx +server { + listen 80; + server_name _; + + root /var/www/; + index index.html; + + # Serve static files (Optional) + location / { + try_files $uri $uri/ =404; + } + + # Proxy API/Dynamic requests + location /api { + proxy_pass http://localhost:4001; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + } +} +``` + +Enable site: +```bash +# Remove defaults +rm -f /etc/nginx/sites-enabled/default +rm -f /etc/nginx/sites-enabled/nodejs + +# Link new site +ln -s /etc/nginx/sites-available/ /etc/nginx/sites-enabled/ + +# Reload +nginx -t && systemctl reload nginx +``` + +--- + +## ☁️ Step 4: Cloudflare Tunnel (Secure Access) + +Expose your app securely without opening router ports. + +### 1. Install Cloudflared +```bash +# Add Key +mkdir -p --mode=0755 /usr/share/keyrings +curl -fsSL https://pkg.cloudflare.com/cloudflare-public-v2.gpg | tee /usr/share/keyrings/cloudflare-public-v2.gpg >/dev/null + +# Add Repo +echo 'deb [signed-by=/usr/share/keyrings/cloudflare-public-v2.gpg] https://pkg.cloudflare.com/cloudflared any main' | tee /etc/apt/sources.list.d/cloudflared.list + +# Install +apt-get update && apt-get install -y cloudflared +``` + +### 2. Create Tunnel +```bash +cloudflared tunnel login +cloudflared tunnel create +# Follow on-screen instructions to map domain -> http://localhost:4001 +``` + +--- + +## 🔄 Step 5: Automated Updates (PowerShell) + +Create a script `deploy-remote.ps1` in your project root to automate updates. + +**Pre-requisite**: Create `deploy-config.json` (Add to .gitignore!): +```json +{ + "host": "", + "username": "root", + "password": "", + "remotePath": "/var/www/" +} +``` + +**Script `deploy-remote.ps1`**: +```powershell +# Reads config and updates remote server +$Config = Get-Content "deploy-config.json" | ConvertFrom-Json +$User = $Config.username; $HostName = $Config.host; $Pass = $Config.password +$RemotePath = $Config.remotePath + +# Commands to run remotely +$Cmds = " + cd $RemotePath + echo '⬇️ Pulling code...' + git pull + echo '📦 Installing deps...' + npm install + echo '🚀 Restarting service...' + systemctl restart + systemctl status --no-pager +" + +echo y | plink -ssh -t -pw $Pass "$User@$HostName" $Cmds +``` + +**Usage**: Just run `./deploy-remote.ps1` to deploy! diff --git a/config/nginx.conf.template b/config/nginx.conf.template new file mode 100644 index 0000000..8b8a89b --- /dev/null +++ b/config/nginx.conf.template @@ -0,0 +1,25 @@ +server { + listen 80; + server_name _; + + root /var/www/Advanced-Smtp-Tester; + index index.html; + + # Serve static frontend files + location / { + try_files $uri $uri/ =404; + } + + # Proxy API requests to Node.js app + location /api { + proxy_pass http://localhost:4001; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + } + + # Increase body size for larger payloads if needed + client_max_body_size 10M; +} diff --git a/deploy-to-proxmox.ps1 b/deploy-to-proxmox.ps1 new file mode 100644 index 0000000..9f534f7 --- /dev/null +++ b/deploy-to-proxmox.ps1 @@ -0,0 +1,75 @@ +# deploy-to-proxmox.ps1 + +# 1. Read Configuration +if (-not (Test-Path "deploy-secrets.json")) { + Write-Error "Could not find deploy-secrets.json. Please create it first." + exit 1 +} + +$Config = Get-Content "deploy-secrets.json" | ConvertFrom-Json +$HostName = $Config.host +$User = $Config.username +$Password = $Config.password +$GitUser = $Config.gitUser +$GitToken = $Config.gitToken +$RepoUrl = $Config.repoUrl + +# Construct Authenticated Repo URL +# Extract the domain and path from RepoUrl (remove https://) +$RepoPath = $RepoUrl -replace "https://", "" +# Use Token as username (GitHub supports this) to avoid issues with @ in email usernames +$AuthRepoUrl = "https://${GitToken}@${RepoPath}" + +$AppName = "Advanced-Smtp-Tester" +$RemoteDir = "/var/www/$AppName" + +Write-Host "🚀 Starting Deployment to $HostName..." -ForegroundColor Cyan + +# 2. Define Remote Commands +# We use a Here-String for the remote script +$RemoteScript = @" +set -e + +echo "🔹 [Remote] Checking prerequisites..." +if ! command -v git &> /dev/null; then + echo "📦 [Remote] Installing Git..." + apt-get update && apt-get install -y git +fi + +echo "🔹 [Remote] Preparing directory $RemoteDir..." +mkdir -p "$RemoteDir" + +# Check if .git exists, if not clone, else pull +if [ ! -d "$RemoteDir/.git" ]; then + echo "⬇️ [Remote] Cloning repository..." + # Clone with token for future auth-less pulls + git clone "$AuthRepoUrl" "$RemoteDir" +else + echo "⬇️ [Remote] Repository exists. Pulling latest..." + cd "$RemoteDir" + # Update remote url to ensure token is correct (in case it changed) + git remote set-url origin "$AuthRepoUrl" + git pull +fi + +# Run the setup script from the repo +echo "⚡ [Remote] Running setup script..." +cd "$RemoteDir" +chmod +x scripts/setup-server.sh +./scripts/setup-server.sh + +echo "✅ [Remote] Deployment Logic Finished." +"@ -replace "`r`n", "`n" + +# 3. Execute via Plink (Putty Link) or SSH +# We'll use plink if available because it handles password via argument easier than OpenSSH on Windows +# If plink is not found, we warn the user. +if (Get-Command plink -ErrorAction SilentlyContinue) { + echo y | plink -ssh -l $User -pw $Password $HostName $RemoteScript +} +else { + Write-Warning "Plink not found. Trying standard ssh (you may be prompted for password)." + ssh "$User@$HostName" $RemoteScript +} + +Write-Host "✨ Deployment script completed." -ForegroundColor Green diff --git a/ecosystem.config.js b/ecosystem.config.js new file mode 100644 index 0000000..7a9279e --- /dev/null +++ b/ecosystem.config.js @@ -0,0 +1,14 @@ +module.exports = { + apps: [{ + name: "Advanced-Smtp-Tester", + script: "server.js", + instances: 1, + autorestart: true, + watch: false, + max_memory_restart: '1G', + env: { + NODE_ENV: "production", + PORT: 4001 + } + }] +}; diff --git a/scripts/setup-server.sh b/scripts/setup-server.sh new file mode 100644 index 0000000..6f4f1f0 --- /dev/null +++ b/scripts/setup-server.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +# Exit on error +set -e + +APP_NAME="Advanced-Smtp-Tester" +APP_DIR="/var/www/$APP_NAME" + +echo "🚀 Starting Server Setup for $APP_NAME..." + +# 1. Install Dependencies +echo "📦 Installing system dependencies..." +apt-get update +# Note: nodejs and npm should be present in the TurnKey Node.js template +apt-get install -y git nginx curl build-essential + +# Install PM2 globally if not exists +if ! command -v pm2 &> /dev/null; then + echo "📦 Installing PM2..." + npm install -g pm2 +fi + +# 2. Setup Nginx +echo "⚙️ Configuring Nginx..." +cp "$APP_DIR/config/nginx.conf.template" "/etc/nginx/sites-available/$APP_NAME" +# Remove default site if exists +rm -f /etc/nginx/sites-enabled/default +rm -f /etc/nginx/sites-enabled/nodejs # Common in TurnKey +# Enable site +ln -sf "/etc/nginx/sites-available/$APP_NAME" "/etc/nginx/sites-enabled/" +# Test and Reload +nginx -t && systemctl reload nginx + +# 3. Setup PM2 +echo "⚙️ Configuring PM2..." +cd "$APP_DIR" +pm2 start ecosystem.config.js +pm2 save +pm2 startup systemd -u root --hp /root + +# 4. Setup Cron Job for Auto-Sync (Every 5 minutes) +echo "⏰ Setting up Auto-Sync Cron Job..." +SCRIPT_PATH="$APP_DIR/scripts/sync-and-restart.sh" +chmod +x "$SCRIPT_PATH" + +# Add to crontab if not already there +(crontab -l 2>/dev/null; echo "*/5 * * * * $SCRIPT_PATH") | awk '!x[$0]++' | crontab - + +echo "✅ Setup Complete! Application is running and auto-sync is enabled." +echo "🌐 Access your app at http://" diff --git a/scripts/sync-and-restart.sh b/scripts/sync-and-restart.sh new file mode 100644 index 0000000..f5a2462 --- /dev/null +++ b/scripts/sync-and-restart.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +# Configuration +APP_DIR="/var/www/Advanced-Smtp-Tester" +LOG_FILE="/var/log/smtp-tester-sync.log" + +# Navigate to app directory +cd "$APP_DIR" || exit 1 + +# Log function +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE" +} + +# Fetch latest changes +git fetch origin + +# Check if there are changes +HEADHASH=$(git rev-parse HEAD) +UPSTREAMHASH=$(git rev-parse origin/main) + +if [ "$HEADHASH" != "$UPSTREAMHASH" ]; then + log "Changes detected. Updating..." + + # Pull changes + git pull origin main >> "$LOG_FILE" 2>&1 + + # Check if package.json changed + if git diff --name-only "$HEADHASH" "$UPSTREAMHASH" | grep "package.json"; then + log "package.json changed. Installing dependencies..." + npm install >> "$LOG_FILE" 2>&1 + fi + + # Restart application + log "Restarting application..." + pm2 reload all >> "$LOG_FILE" 2>&1 + + log "Update complete." +else + # Uncomment next line for verbose logging of no-changes + # log "No changes detected." + # echo "No changes." + : +fi