Files
Deep-Package-Inspection/scripts/hestia-nginx-fix.js
T

181 lines
8.5 KiB
JavaScript

// scripts/hestia-nginx-fix.js
// ─────────────────────────────────────────────────────────────────────────────
// Fix 502 Bad Gateway dengan cara:
// 1. Cek permissions direktori conf Nginx
// 2. Gunakan Hestia CP REST API untuk ubah proxy template ke Node.js
// 3. Atau tulis nginx.conf_custom via Hestia API command
// ─────────────────────────────────────────────────────────────────────────────
'use strict';
const { Client } = require('ssh2');
const https = require('https');
const querystring = require('querystring');
const crypto = require('crypto');
const SSH = { host: '103.185.47.52', port: 2222, username: 'adminbackend', password: 'htEo7x6LsBQiEHHH', readyTimeout: 60000 };
const HESTIA_HOST = 'isp.proit.id';
const HESTIA_PORT = 8083;
const HESTIA_USER = 'admin';
const HESTIA_PASS = 'htEo7x6LsBQiEHHH';
const DOMAIN = 'demoplace.my.id';
const WEB_USER = 'adminbackend';
const CONF = `/home/${WEB_USER}/conf/web/${DOMAIN}`;
// ── Hestia CP API call ─────────────────────────────────────────────────────
function hestiaApi(cmd, args = []) {
return new Promise((resolve, reject) => {
const hash = crypto.createHash('sha256').update(HESTIA_PASS).digest('hex');
const body = querystring.stringify({ hash, cmd, ...Object.fromEntries(args.map((a, i) => [`arg${i + 1}`, a])) });
const req = https.request({
hostname: HESTIA_HOST,
port: HESTIA_PORT,
path: '/api/',
method: 'POST',
rejectUnauthorized: false,
headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': Buffer.byteLength(body) }
}, res => {
let data = '';
res.on('data', d => data += d);
res.on('end', () => resolve({ status: res.statusCode, body: data.trim() }));
});
req.on('error', reject);
req.write(body);
req.end();
});
}
// ── SSH command runner ─────────────────────────────────────────────────────
function sshExec(conn, cmd) {
return new Promise((resolve, reject) => {
conn.exec(cmd, (err, stream) => {
if (err) return reject(err);
let out = '';
stream.on('close', () => resolve(out))
.on('data', d => { out += d; process.stdout.write(d.toString()); })
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); });
});
});
}
// ── Custom Nginx config content ───────────────────────────────────────────
const nginxCustomContent = `# BackOne DPI — Proxy to Next.js port 3000
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 86400;
}`;
const nginxSslContent = `# BackOne DPI — Proxy SSL to Next.js port 3000
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_read_timeout 86400;
}`;
async function main() {
console.log('\n╔══════════════════════════════════════════════════════════╗');
console.log('║ BackOne DPI — Fix 502 via Hestia API + Nginx Fix ║');
console.log('╚══════════════════════════════════════════════════════════╝\n');
// ── Step 1: Diagnose conf directory permissions via SSH ─────────────────
console.log('\n▶ Step 1: Check conf directory permissions via SSH...');
const conn = new Client();
await new Promise((resolve, reject) => { conn.on('ready', resolve).on('error', reject).connect(SSH); });
console.log('[SSH] Connected!\n');
await sshExec(conn, `echo "=== CONF DIR PERMS ===" && ls -la /home/${WEB_USER}/conf/web/`);
await sshExec(conn, `echo "=== DOMAIN CONF DIR ===" && ls -la ${CONF}/`);
await sshExec(conn, `echo "=== EXISTING CUSTOM CONF ===" && ls -la ${CONF}/nginx.conf_* 2>/dev/null || echo "No custom conf yet"`);
// ── Step 2: Try Python to write the file (avoids shell quoting issues) ──
console.log('\n▶ Step 2: Attempting to write nginx.conf_custom via Python...');
const pyScript = `python3 -c "
import os
content = '''${nginxCustomContent.replace(/'/g, "\\'")}'''
path = '${CONF}/nginx.conf_custom'
try:
with open(path, 'w') as f:
f.write(content + '\\n')
print('[OK] Written: ' + path)
except Exception as e:
print('[FAIL] ' + str(e))
"`;
await sshExec(conn, pyScript);
const pyScriptSsl = `python3 -c "
content = '''${nginxSslContent.replace(/'/g, "\\'")}'''
path = '${CONF}/nginx.ssl.conf_custom'
try:
with open(path, 'w') as f:
f.write(content + '\\n')
print('[OK] Written: ' + path)
except Exception as e:
print('[FAIL] ' + str(e))
"`;
await sshExec(conn, pyScriptSsl);
conn.end();
// ── Step 3: Try Hestia CP REST API to restart web ─────────────────────
console.log('\n▶ Step 3: Call Hestia CP REST API to restart web server...');
// Try listing available proxy templates first
console.log('\n → Listing available proxy templates...');
const templatesRes = await hestiaApi('v-list-web-templates-proxy', []);
console.log(` API Response [list-proxy-templates]: HTTP ${templatesRes.status}`);
console.log(` Body: ${templatesRes.body.substring(0, 300)}`);
// Try to restart web via API
console.log('\n → Restarting web server via Hestia API...');
const restartRes = await hestiaApi('v-restart-web', []);
console.log(` API Response [restart-web]: HTTP ${restartRes.status}`);
console.log(` Body: ${restartRes.body}`);
// Try restart with correct user arg
const restartRes2 = await hestiaApi('v-restart-web', [WEB_USER]);
console.log(` API Response [restart-web user]: HTTP ${restartRes2.status}`);
console.log(` Body: ${restartRes2.body}`);
// ── Step 4: Wait and test domain ─────────────────────────────────────
console.log('\n▶ Step 4: Waiting 8 seconds then testing domain...');
await new Promise(r => setTimeout(r, 8000));
const testRes = await new Promise(resolve => {
const req = https.get('https://demoplace.my.id/login', { timeout: 10000, rejectUnauthorized: false }, res => {
resolve({ status: res.statusCode, location: res.headers.location });
});
req.on('error', e => resolve({ status: 0, error: e.message }));
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
});
const icon = testRes.status >= 200 && testRes.status < 400 ? '✅' : '❌';
console.log(`\n ${icon} https://demoplace.my.id/login → HTTP ${testRes.status} ${testRes.error || ''}`);
if (testRes.location) console.log(` Location: ${testRes.location}`);
if (testRes.status >= 200 && testRes.status < 400) {
console.log('\n🎉 SUKSES! Domain sudah bisa diakses!\n');
} else {
console.log('\n⚠️ Domain masih belum bisa diakses. Perlu konfig manual via Hestia panel.\n');
console.log('Silakan buka Hestia CP File Manager dan buat file:');
console.log(` ${CONF}/nginx.conf_custom`);
console.log(` ${CONF}/nginx.ssl.conf_custom`);
console.log('\nDengan isi (untuk keduanya):');
console.log(nginxCustomContent);
console.log('\nKemudian di Hestia CP: Web → demoplace.my.id → Rebuild\n');
}
}
main().catch(err => { console.error('[FATAL]', err.message); process.exit(1); });