mirror of
https://github.com/DeNNiiInc/Advanced-Smtp-Tester.git
synced 2026-04-17 17:35:59 +00:00
Add deployment scripts and config
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,5 @@
|
|||||||
node_modules
|
node_modules
|
||||||
.env
|
.env
|
||||||
|
deploy-secrets.json
|
||||||
|
config/secrets.env
|
||||||
|
scripts/auth.json
|
||||||
|
|||||||
211
PROXMOX_DEPLOY_TEMPLATE.md
Normal file
211
PROXMOX_DEPLOY_TEMPLATE.md
Normal file
@@ -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@<YOUR_SERVER_IP>
|
||||||
|
```
|
||||||
|
|
||||||
|
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/<APP_NAME>
|
||||||
|
cd /var/www/<APP_NAME>
|
||||||
|
|
||||||
|
# Clone your repo (Use Basic Auth with Token if private)
|
||||||
|
# Format: https://<USER>:<TOKEN>@github.com/<ORG>/<REPO>.git
|
||||||
|
git clone <YOUR_REPO_URL> .
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Setup Permissions
|
||||||
|
```bash
|
||||||
|
# Give ownership to www-data (Nginx user)
|
||||||
|
chown -R www-data:www-data /var/www/<APP_NAME>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚙️ Step 3: Application Configuration
|
||||||
|
|
||||||
|
### 1. Systemd Service
|
||||||
|
Create a service file to keep your app running.
|
||||||
|
|
||||||
|
Create `/etc/systemd/system/<APP_NAME>.service`:
|
||||||
|
```ini
|
||||||
|
[Unit]
|
||||||
|
Description=<APP_NAME> 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/<APP_NAME>
|
||||||
|
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 <APP_NAME>
|
||||||
|
systemctl start <APP_NAME>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Nginx Reverse Proxy
|
||||||
|
Configure Nginx to forward port 80 to your app (Port 4001).
|
||||||
|
|
||||||
|
Create `/etc/nginx/sites-available/<APP_NAME>`:
|
||||||
|
```nginx
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
root /var/www/<APP_NAME>;
|
||||||
|
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/<APP_NAME> /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 <TUNNEL_NAME>
|
||||||
|
# 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": "<SERVER_IP>",
|
||||||
|
"username": "root",
|
||||||
|
"password": "<SSH_PASSWORD>",
|
||||||
|
"remotePath": "/var/www/<APP_NAME>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**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 <APP_NAME>
|
||||||
|
systemctl status <APP_NAME> --no-pager
|
||||||
|
"
|
||||||
|
|
||||||
|
echo y | plink -ssh -t -pw $Pass "$User@$HostName" $Cmds
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage**: Just run `./deploy-remote.ps1` to deploy!
|
||||||
25
config/nginx.conf.template
Normal file
25
config/nginx.conf.template
Normal file
@@ -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;
|
||||||
|
}
|
||||||
75
deploy-to-proxmox.ps1
Normal file
75
deploy-to-proxmox.ps1
Normal file
@@ -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
|
||||||
14
ecosystem.config.js
Normal file
14
ecosystem.config.js
Normal file
@@ -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
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
};
|
||||||
50
scripts/setup-server.sh
Normal file
50
scripts/setup-server.sh
Normal file
@@ -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://<YOUR_SERVER_IP>"
|
||||||
44
scripts/sync-and-restart.sh
Normal file
44
scripts/sync-and-restart.sh
Normal file
@@ -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
|
||||||
Reference in New Issue
Block a user