181 lines
8.5 KiB
JavaScript
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); });
|