feat(production): sync 10/10 production codebase from demoplace.my.id

This commit is contained in:
rafif committed 2026-07-21 13:30:23 +07:00
commit 0156b84b0e
318 files changed
+56682

No files matched your search

+211
View File
@@ -0,0 +1,211 @@
// scripts/hestia-local-api-fix.js
// ─────────────────────────────────────────────────────────────────────────────
// Fix 502: Panggil Hestia CP API dari localhost (via SSH curl) karena
// Hestia API memblokir IP eksternal tapi MENGIZINKAN localhost (127.0.0.1)
// ─────────────────────────────────────────────────────────────────────────────
'use strict';
const { Client } = require('ssh2');
const https = require('https');
const SSH = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
readyTimeout: 60000
};
const DOMAIN = 'demoplace.my.id';
const WEB_USER = 'adminbackend';
const CONF = `/home/${WEB_USER}/conf/web/${DOMAIN}`;
const HESTIA_PASS = 'htEo7x6LsBQiEHHH';
function sshExec(conn, cmd, label = '') {
if (label) console.log(`\n[${label}]`);
console.log(`$ ${cmd.substring(0, 120)}${cmd.length > 120 ? '...' : ''}`);
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()); });
});
});
}
// Isi nginx.conf_custom yang akan kita tulis
const NGINX_CUSTOM = `# BackOne DPI - Proxy langsung ke 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 NGINX_SSL_CUSTOM = `# BackOne DPI - Proxy SSL langsung ke 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 localhost API ║');
console.log('╚══════════════════════════════════════════════════════════╝\n');
const conn = new Client();
await new Promise((resolve, reject) => { conn.on('ready', resolve).on('error', reject).connect(SSH); });
console.log('[SSH] Terhubung!\n');
// ── Step 1: Baca apache2.conf untuk diagnosa ───────────────────────────
await sshExec(conn, `cat ${CONF}/apache2.conf`, 'STEP 1: Baca Apache Config');
// ── Step 2: Cek apakah mod_proxy aktif di Apache ───────────────────────
await sshExec(conn,
`apache2ctl -M 2>/dev/null | grep -i proxy || ` +
`apachectl -M 2>/dev/null | grep -i proxy || ` +
`echo "Tidak bisa cek Apache modules"`,
'STEP 2: Cek mod_proxy'
);
// ── Step 3: Test Hestia API dari localhost (bypass IP restriction) ─────
console.log('\n[STEP 3: Hestia API dari localhost]');
// Generate SHA-256 hash untuk password
const hashCmd = `echo -n '${HESTIA_PASS}' | sha256sum | cut -d' ' -f1`;
console.log(`$ ${hashCmd}`);
const hashResult = await new Promise((resolve, reject) => {
conn.exec(hashCmd, (err, stream) => {
if (err) return reject(err);
let out = '';
stream.on('close', () => resolve(out.trim()))
.on('data', d => { out += d; })
.stderr.on('data', () => {});
});
});
console.log(`Hash: ${hashResult}`);
// Panggil Hestia API dari localhost untuk list proxy templates
await sshExec(conn,
`curl -sk -X POST https://localhost:8083/api/ ` +
`-d "hash=${hashResult}&cmd=v-list-web-templates-proxy&returncode=json" | head -c 500`,
'STEP 3a: List proxy templates via localhost API'
);
// Panggil Hestia API untuk restart web
await sshExec(conn,
`curl -sk -X POST https://localhost:8083/api/ ` +
`-d "hash=${hashResult}&cmd=v-restart-web&returncode=json"`,
'STEP 3b: Restart web via localhost API'
);
// ── Step 4: Tulis file via Hestia API run command ──────────────────────
// v-run-cli-cmd jalankan perintah shell sebagai root via Hestia
const writeHttpConf = `tee ${CONF}/nginx.conf_custom << 'NGINXEOF'\n${NGINX_CUSTOM}\nNGINXEOF`;
const encodedWrite = Buffer.from(writeHttpConf).toString('base64');
await sshExec(conn,
`curl -sk -X POST https://localhost:8083/api/ ` +
`-d "hash=${hashResult}&cmd=v-run-cli-cmd&arg1=tee&arg2=${CONF}/nginx.conf_custom" ` +
`--data-urlencode "stdin=${NGINX_CUSTOM}" | head -c 200`,
'STEP 4a: Tulis nginx.conf_custom via API'
);
// Fallback: Coba tee dengan python sebagai cara alternatif
await sshExec(conn,
`curl -sk -X POST https://localhost:8083/api/ ` +
`-d "hash=${hashResult}&cmd=v-add-web-domain-nginx-cfg&arg1=${WEB_USER}&arg2=${DOMAIN}" | head -c 200`,
'STEP 4b: Add nginx cfg via Hestia API'
);
// ── Step 5: Coba ubah Web Template ke yang support Node.js ───────────
// Template yang biasanya ada di Hestia untuk Node.js/proxy
for (const tpl of ['nodejs', 'node', 'proxy', 'default-nodejs']) {
const res = await new Promise(resolve => {
conn.exec(
`curl -sk -X POST https://localhost:8083/api/ ` +
`-d "hash=${hashResult}&cmd=v-change-web-domain-tpl&arg1=${WEB_USER}&arg2=${DOMAIN}&arg3=${tpl}&arg4=yes" | head -c 200`,
(err, stream) => {
if (err) return resolve('SSH Error');
let out = '';
stream.on('close', () => resolve(out))
.on('data', d => out += d)
.stderr.on('data', () => {});
}
);
});
console.log(`\n[Template ${tpl}]: ${res.trim()}`);
if (res.includes('0') || res.includes('OK')) {
console.log(`✅ Template '${tpl}' berhasil diterapkan!`);
break;
}
}
// ── Step 6: Paksa reload Nginx dengan cara yang bisa dilakukan user ───
await sshExec(conn,
`/usr/local/hestia/bin/v-restart-web 2>&1 || ` +
`sudo nginx -s reload 2>&1 || ` +
`curl -sk -X POST https://localhost:8083/api/ -d "hash=${hashResult}&cmd=v-restart-web" | head -c 100`,
'STEP 6: Reload Nginx'
);
// ── Step 7: Tunggu dan test domain ────────────────────────────────────
console.log('\n[STEP 7: Test domain setelah 8 detik...]');
await sshExec(conn,
`sleep 8 && curl -sk -o /dev/null -w "HTTPS Status: %{http_code}" https://${DOMAIN}/login`,
'Domain Test'
);
// ── Step 8: Tampilkan PM2 status ──────────────────────────────────────
await sshExec(conn,
`/home/adminbackend/.npm-global/bin/pm2 list`,
'STEP 8: PM2 Status'
);
conn.end();
// Test dari luar
console.log('\n[Test dari jaringan lokal...]');
const extResult = await new Promise(resolve => {
const req = https.get(`https://${DOMAIN}/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 = extResult.status >= 200 && extResult.status < 400 ? '✅' : '❌';
console.log(`\n ${icon} https://${DOMAIN}/login → HTTP ${extResult.status} ${extResult.error || ''}`);
if (extResult.status >= 200 && extResult.status < 400) {
console.log('\n🎉 SUKSES! Dashboard BackOne sudah online!\n');
} else {
console.log('\n⚠️ Masih 502. Perlu konfigurasi manual di Hestia CP panel.\n');
console.log('━━━━ INSTRUKSI MANUAL ━━━━');
console.log('1. Buka Hestia CP → Web → demoplace.my.id → Edit');
console.log('2. Di bagian "Proxy Template" — pilih template Node.js (jika ada)');
console.log(' ATAU di File Manager: navigasi ke /conf/web/demoplace.my.id/');
console.log(' Buat file baru: nginx.conf_custom dengan isi:');
console.log('\n' + NGINX_CUSTOM.replace(/\\$/g, '$'));
console.log('\n Dan nginx.ssl.conf_custom dengan isi:');
console.log('\n' + NGINX_SSL_CUSTOM.replace(/\\$/g, '$'));
console.log('\n3. Setelah file dibuat, klik Rebuild di Hestia CP Web Domain.');
}
}
main().catch(err => { console.error('[FATAL]', err.message); process.exit(1); });