refactor: align deployment with proxmox template

This commit is contained in:
2025-12-27 15:52:31 +11:00
parent 908a00b38c
commit bd40b7cd8c
6 changed files with 266 additions and 21 deletions

211
PROXMOX_DEPLOY_TEMPLATE.md Normal file
View 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!

View File

@@ -0,0 +1,15 @@
[Unit]
Description=Advanced Raid Calculator Service
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/advanced-raid-calculator
ExecStart=/usr/bin/node server.js
Restart=always
Environment=NODE_ENV=production
Environment=PORT=4001
[Install]
WantedBy=multi-user.target

View File

@@ -3,30 +3,38 @@
# Ensure we are in the project directory # Ensure we are in the project directory
cd "$(dirname "$0")" cd "$(dirname "$0")"
echo "Deploying Advanced Raid Calculator..." APP_NAME="advanced-raid-calculator"
INSTALL_DIR="/var/www/$APP_NAME"
SERVICE_NAME="$APP_NAME.service"
echo "Deploying $APP_NAME..."
# Ensure install directory exists (if running for the first time outside of it, though git clone usually does this)
# If we are running this script FROM the repo, we assume we are already in the right place or we are setting it up.
# This script assumes it is being run inside the destination directory /var/www/advanced-raid-calculator
# Install dependencies # Install dependencies
echo "Installing dependencies..." echo "Installing dependencies..."
npm install npm install
# Restart the application using PM2 # Setup Systemd Service
if command -v pm2 &> /dev/null; then echo "Configuring Systemd Service..."
echo "Restarting with PM2..." if [ -f "$SERVICE_NAME" ]; then
# Check if the process is already running cp "$SERVICE_NAME" "/etc/systemd/system/$SERVICE_NAME"
if pm2 list | grep -q "raid-calculator"; then systemctl daemon-reload
pm2 reload raid-calculator systemctl enable "$SERVICE_NAME"
systemctl restart "$SERVICE_NAME"
echo "Service restarted."
else else
pm2 start server.js --name "raid-calculator" echo "Error: $SERVICE_NAME not found!"
fi exit 1
pm2 save
else
echo "PM2 not found. Please install PM2 globally (npm install -g pm2)."
# Fallback for testing without PM2, though PM2 is expected on the TurnKey template
# node server.js
fi fi
# Run the proxy setup script # Run the proxy setup script
chmod +x setup-proxy.sh chmod +x setup-proxy.sh
./setup-proxy.sh ./setup-proxy.sh
# Fix permissions (ensure www-data owns the web dir)
chown -R www-data:www-data "$INSTALL_DIR"
echo "Deployment complete." echo "Deployment complete."

View File

@@ -1,7 +1,7 @@
const express = require('express'); const express = require('express');
const path = require('path'); const path = require('path');
const app = express(); const app = express();
const PORT = process.env.PORT || 3000; const PORT = process.env.PORT || 4001;
// Serve static files from the current directory // Serve static files from the current directory
app.use(express.static(__dirname)); app.use(express.static(__dirname));

View File

@@ -8,15 +8,25 @@ fi
echo "Configuring Nginx Reverse Proxy..." echo "Configuring Nginx Reverse Proxy..."
APP_NAME="advanced-raid-calculator"
PORT=4001
# Create Nginx config for the app # Create Nginx config for the app
cat > /etc/nginx/sites-available/app <<EOF cat > /etc/nginx/sites-available/$APP_NAME <<EOF
server { server {
listen 80; listen 80;
listen [::]:80; listen [::]:80;
server_name _; server_name _;
root /var/www/$APP_NAME;
index index.html;
location / { location / {
proxy_pass http://localhost:3000; try_files \$uri \$uri/ =404;
}
location /api {
proxy_pass http://localhost:$PORT;
proxy_http_version 1.1; proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade; proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection 'upgrade'; proxy_set_header Connection 'upgrade';
@@ -30,14 +40,15 @@ EOF
rm -f /etc/nginx/sites-enabled/default rm -f /etc/nginx/sites-enabled/default
rm -f /etc/nginx/sites-enabled/tkl-default rm -f /etc/nginx/sites-enabled/tkl-default
rm -f /etc/nginx/sites-enabled/node rm -f /etc/nginx/sites-enabled/node
rm -f /etc/nginx/sites-enabled/app
# Enable the new app configuration # Enable the new app configuration
ln -sf /etc/nginx/sites-available/app /etc/nginx/sites-enabled/app ln -sf /etc/nginx/sites-available/$APP_NAME /etc/nginx/sites-enabled/$APP_NAME
# Restart Nginx to apply changes # Restart Nginx to apply changes
if systemctl is-active --quiet nginx; then if systemctl is-active --quiet nginx; then
systemctl restart nginx systemctl reload nginx
echo "Nginx restarted successfully." echo "Nginx reloaded successfully."
else else
echo "Nginx is not running. Starting it..." echo "Nginx is not running. Starting it..."
systemctl start nginx systemctl start nginx

View File

@@ -17,7 +17,7 @@ if [ $LOCAL = $REMOTE ]; then
elif [ $LOCAL = $BASE ]; then elif [ $LOCAL = $BASE ]; then
echo "Need to pull" echo "Need to pull"
git pull git pull
# Only run deploy/restart if we actually pulled changes # Re-run deploy to handle deps, service updates, and permissions
./deploy.sh ./deploy.sh
elif [ $REMOTE = $BASE ]; then elif [ $REMOTE = $BASE ]; then
echo "Need to push" echo "Need to push"