chore: super deep scanning cleanup - remove obsolete debug scripts, redundant components, and temporary files
This commit is contained in:
1 parent
97d2c89c15
commit
a577f2d672
189 files changed
-11112
No files matched your search
@@ -1,66 +0,0 @@
|
||||
const { Client } = require('ssh2');
|
||||
|
||||
const remoteScript = `
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const root = '/home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/.next/server/app/(dashboard)';
|
||||
|
||||
function scanDir(dir) {
|
||||
const results = [];
|
||||
if (!fs.existsSync(dir)) return results;
|
||||
const items = fs.readdirSync(dir, { withFileTypes: true });
|
||||
for (const item of items) {
|
||||
const fullPath = path.join(dir, item.name);
|
||||
if (item.isDirectory()) {
|
||||
results.push(...scanDir(fullPath));
|
||||
} else if (item.name.endsWith('.html') || item.name.endsWith('.js')) {
|
||||
results.push(fullPath);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
console.log('=== AUDITING ALL PAGE HEADERS AND TITLES ON DEMOPLACE.MY.ID ===\\n');
|
||||
|
||||
const files = scanDir(root);
|
||||
files.forEach(file => {
|
||||
const content = fs.readFileSync(file, 'utf8');
|
||||
const rel = path.relative(root, file);
|
||||
|
||||
// Extract <h2> or <h1> or header titles
|
||||
const h2s = [];
|
||||
const h2Match = content.matchAll(/<h2[^>]*>(.*?)<\/h2>/gi);
|
||||
for (const m of h2Match) {
|
||||
const clean = m[1].replace(/<[^>]+>/g, '').trim();
|
||||
if (clean && !h2s.includes(clean)) h2s.push(clean);
|
||||
}
|
||||
|
||||
// Extract Learn This Page triggers
|
||||
const hasHelpTrigger = content.includes('Learn This Page');
|
||||
|
||||
if (h2s.length > 0 || hasHelpTrigger) {
|
||||
console.log('Page Route File:', rel);
|
||||
if (h2s.length > 0) console.log(' Headers (H2):', h2s.join(' | '));
|
||||
console.log(' Has Learn This Page Button:', hasHelpTrigger);
|
||||
console.log('---');
|
||||
}
|
||||
});
|
||||
`;
|
||||
|
||||
const conn = new Client();
|
||||
conn.on('ready', () => {
|
||||
conn.exec(`node -e ${JSON.stringify(remoteScript)}`, (err, stream) => {
|
||||
let out = '';
|
||||
stream.on('data', d => out += d);
|
||||
stream.on('close', () => {
|
||||
console.log(out);
|
||||
conn.end();
|
||||
});
|
||||
});
|
||||
}).connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
@@ -1,119 +0,0 @@
|
||||
const { spawn } = require('child_process');
|
||||
const http = require('http');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const WebSocket = require('next/dist/compiled/ws');
|
||||
|
||||
async function loginAdmin() {
|
||||
return new Promise((resolve) => {
|
||||
const data = JSON.stringify({ username: 'admin', password: 'admin' });
|
||||
const req = http.request({
|
||||
hostname: '127.0.0.1',
|
||||
port: 3000,
|
||||
path: '/api/auth/login',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': data.length
|
||||
}
|
||||
}, (res) => {
|
||||
let body = '';
|
||||
res.on('data', chunk => body += chunk);
|
||||
res.on('end', () => {
|
||||
const cookies = res.headers['set-cookie'];
|
||||
if (cookies && cookies.length > 0) {
|
||||
const cookieStr = cookies[0];
|
||||
const match = cookieStr.match(/backone_token=([^;]+)/);
|
||||
resolve(match ? match[1] : null);
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
req.on('error', () => resolve(null));
|
||||
req.write(data);
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
async function capture() {
|
||||
const token = await loginAdmin();
|
||||
console.log("Logged in admin token:", token ? "FOUND" : "NOT FOUND");
|
||||
|
||||
const edgePath = "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe";
|
||||
const edgeProc = spawn(edgePath, [
|
||||
'--headless',
|
||||
'--disable-gpu',
|
||||
'--remote-debugging-port=9222',
|
||||
'--window-size=400,844',
|
||||
'http://localhost:3000/login'
|
||||
]);
|
||||
|
||||
// Wait 2.5s for Edge CDP to listen
|
||||
await new Promise(r => setTimeout(r, 2500));
|
||||
|
||||
try {
|
||||
const targets = await new Promise((resolve, reject) => {
|
||||
http.get('http://127.0.0.1:9222/json', (res) => {
|
||||
let body = '';
|
||||
res.on('data', c => body += c);
|
||||
res.on('end', () => resolve(JSON.parse(body)));
|
||||
}).on('error', reject);
|
||||
});
|
||||
|
||||
const pageTarget = targets.find(t => t.type === 'page');
|
||||
if (!pageTarget || !pageTarget.webSocketDebuggerUrl) {
|
||||
console.error("No CDP page target found:", targets);
|
||||
edgeProc.kill();
|
||||
return;
|
||||
}
|
||||
|
||||
const ws = new WebSocket(pageTarget.webSocketDebuggerUrl);
|
||||
let messageId = 1;
|
||||
const send = (method, params = {}) => {
|
||||
return new Promise((res) => {
|
||||
const id = messageId++;
|
||||
const handler = (data) => {
|
||||
const msg = JSON.parse(data);
|
||||
if (msg.id === id) {
|
||||
ws.removeListener('message', handler);
|
||||
res(msg.result);
|
||||
}
|
||||
};
|
||||
ws.on('message', handler);
|
||||
ws.send(JSON.stringify({ id, method, params }));
|
||||
});
|
||||
};
|
||||
|
||||
ws.on('open', async () => {
|
||||
console.log("Connected to Edge CDP WebSocket!");
|
||||
|
||||
if (token) {
|
||||
await send('Network.setCookie', {
|
||||
name: 'backone_token',
|
||||
value: token,
|
||||
domain: 'localhost',
|
||||
path: '/'
|
||||
});
|
||||
}
|
||||
|
||||
await send('Page.navigate', { url: 'http://localhost:3000/' });
|
||||
// Wait for page load and 3D globe rendering
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
|
||||
const screenshot = await send('Page.captureScreenshot', { format: 'png' });
|
||||
const outputPath = "C:\\Users\\rafif\\.gemini\\antigravity-ide\\brain\\d6704840-c7e7-4558-b215-0fe98bbfb07a\\mobile-dashboard-live.png";
|
||||
fs.writeFileSync(outputPath, Buffer.from(screenshot.data, 'base64'));
|
||||
console.log("SUCCESS! Screenshot written to:", outputPath, "Size:", fs.statSync(outputPath).size, "bytes");
|
||||
|
||||
ws.close();
|
||||
edgeProc.kill();
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
console.error("CDP Error:", err.message);
|
||||
edgeProc.kill();
|
||||
}
|
||||
}
|
||||
|
||||
capture();
|
||||
@@ -1,67 +0,0 @@
|
||||
// scripts/check-agents-error.js
|
||||
'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 PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
|
||||
function exec(conn, cmd, label) {
|
||||
if (label) console.log('\n[' + label + ']');
|
||||
console.log('$ ' + cmd.substring(0, 80));
|
||||
return new Promise(resolve => {
|
||||
conn.exec(cmd, (err, s) => {
|
||||
if (err) { resolve(''); return; }
|
||||
let out = '';
|
||||
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.on('close', () => resolve(out));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function httpGet(url, opts) {
|
||||
return new Promise(resolve => {
|
||||
const req = https.get(url, { timeout: 10000, rejectUnauthorized: false, ...opts }, res => {
|
||||
let body = '';
|
||||
res.on('data', d => body += d);
|
||||
res.on('end', () => resolve({ status: res.statusCode, body: body.substring(0, 500) }));
|
||||
});
|
||||
req.on('error', e => resolve({ status: 0, error: e.message }));
|
||||
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const conn = new Client();
|
||||
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(SSH); });
|
||||
console.log('[SSH] Connected\n');
|
||||
|
||||
// 1. Cek error log frontend
|
||||
await exec(conn, 'tail -50 ' + PUB + '/logs/frontend-error.log 2>/dev/null | head -50', '1. Frontend error log');
|
||||
|
||||
// 2. Cek frontend out log terbaru
|
||||
await exec(conn, 'tail -30 ' + PUB + '/logs/frontend-out.log 2>/dev/null', '2. Frontend out log');
|
||||
|
||||
// 3. Test API agents langsung dari server
|
||||
await exec(conn, 'curl -sk http://127.0.0.1:3001/api/agents 2>/dev/null | head -c 500', '3. Test API /api/agents langsung');
|
||||
|
||||
// 4. Test API health backend
|
||||
await exec(conn, 'curl -sk http://127.0.0.1:3001/api/health 2>/dev/null', '4. Test backend health');
|
||||
|
||||
// 5. Cek .env.production - apakah BACKEND_URL benar
|
||||
await exec(conn, 'cat ' + PUB + '/.env.production 2>/dev/null | grep -v PASSWORD | grep -v SECRET | grep -v MONGO | head -20', '5. Environment variables (safe)');
|
||||
|
||||
// 6. Cek apakah backend bisa akses agents collection dari MongoDB
|
||||
await exec(conn, 'curl -sk http://127.0.0.1:3001/api/agents/list 2>/dev/null | head -c 300', '6. Test /api/agents/list');
|
||||
|
||||
conn.end();
|
||||
|
||||
// 7. Test dari luar via domain
|
||||
console.log('\n[7. Test API agents via domain...]');
|
||||
const r = await httpGet('https://demoplace.my.id/api/agents');
|
||||
console.log(' Status: ' + r.status);
|
||||
console.log(' Body: ' + (r.body || r.error || 'empty'));
|
||||
}
|
||||
|
||||
main().catch(e => console.error('[FATAL]', e.message));
|
||||
@@ -1,22 +0,0 @@
|
||||
const { Client } = require('ssh2');
|
||||
|
||||
const conn = new Client();
|
||||
conn.on('ready', () => {
|
||||
console.log('SSH Client Ready');
|
||||
const cmd = `tail -n 200 /home/adminbackend/.pm2/logs/backone-backend-error-*.log /home/adminbackend/.pm2/logs/backone-backend-out-*.log /home/adminbackend/.pm2/logs/backone-frontend-error-*.log /home/adminbackend/.pm2/logs/backone-frontend-out-*.log 2>/dev/null | tail -n 200`;
|
||||
conn.exec(cmd, (err, stream) => {
|
||||
if (err) throw err;
|
||||
stream.on('close', (code, signal) => {
|
||||
conn.end();
|
||||
}).on('data', (data) => {
|
||||
console.log(data.toString());
|
||||
}).stderr.on('data', (data) => {
|
||||
console.log('STDERR: ' + data.toString());
|
||||
});
|
||||
});
|
||||
}).connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
@@ -1,94 +0,0 @@
|
||||
// scripts/check-static-files.js
|
||||
// Cek apakah static chunk files ada di disk dan bisa diakses via domain
|
||||
'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
|
||||
};
|
||||
|
||||
function sshExec(conn, cmd) {
|
||||
return new Promise(resolve => {
|
||||
conn.exec(cmd, (err, s) => {
|
||||
if (err) { resolve('SSH_ERROR'); return; }
|
||||
let out = '';
|
||||
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.on('close', () => resolve(out));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function httpGet(url) {
|
||||
return new Promise(resolve => {
|
||||
const req = https.get(url, { timeout: 10000, rejectUnauthorized: false }, res => {
|
||||
let body = '';
|
||||
res.on('data', d => body += d);
|
||||
res.on('end', () => resolve({ status: res.statusCode, type: res.headers['content-type'], size: body.length }));
|
||||
});
|
||||
req.on('error', e => resolve({ status: 0, error: e.message }));
|
||||
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const conn = new Client();
|
||||
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(SSH); });
|
||||
console.log('[SSH] Connected\n');
|
||||
|
||||
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
|
||||
// 1. List chunks directory
|
||||
console.log('=== .next/static/chunks/ contents ===');
|
||||
await sshExec(conn, `ls -la ${PUB}/.next/static/chunks/ | head -20`);
|
||||
|
||||
// 2. Cek CSS files yang direferensikan oleh HTML
|
||||
console.log('\n=== Cek file CSS spesifik ===');
|
||||
await sshExec(conn, `ls -la ${PUB}/.next/static/chunks/*.css 2>/dev/null | head -5 || echo "Tidak ada .css di chunks/"`);
|
||||
|
||||
// 3. Cek apakah JS bootstrap file ada
|
||||
console.log('\n=== Cek file JS yang diperlukan ===');
|
||||
await sshExec(conn, `ls ${PUB}/.next/static/chunks/ | grep -E "(3km6z|21luguo|1-8s9)" | head -10 || echo "File JS tidak ditemukan"`);
|
||||
|
||||
// 4. Test akses static file via domain (dari dalam server)
|
||||
console.log('\n=== Test static file via Apache ===');
|
||||
await sshExec(conn,
|
||||
`curl -sk -D - https://demoplace.my.id/_next/static/chunks/3km6z-n6wbgrs.js 2>/dev/null | head -15 || ` +
|
||||
`curl -sk -D - http://103.185.47.52:8080/_next/static/chunks/3km6z-n6wbgrs.js 2>/dev/null | head -15`
|
||||
);
|
||||
|
||||
// 5. Test apakah Nginx melayani file static langsung
|
||||
console.log('\n=== Cek Nginx serving static (port 443) ===');
|
||||
await sshExec(conn,
|
||||
`curl -sk -w "\\nHTTP: %{http_code} | Type: %{content_type} | Size: %{size_download}" ` +
|
||||
`-o /dev/null https://demoplace.my.id/_next/static/chunks/3km6z-n6wbgrs.js`
|
||||
);
|
||||
|
||||
// 6. Cek apakah ada .next/server/ directory
|
||||
console.log('\n=== Status .next/server/ ===');
|
||||
await sshExec(conn, `ls ${PUB}/.next/server/ 2>/dev/null | head -5 || echo ".next/server/ TIDAK ADA - standalone build mungkin tidak lengkap"`);
|
||||
|
||||
conn.end();
|
||||
|
||||
// 7. Test dari luar - JS dan CSS
|
||||
console.log('\n=== Test static resources dari luar ===');
|
||||
const files = [
|
||||
'/_next/static/chunks/3km6z-n6wbgrs.js',
|
||||
'/_next/static/chunks/1u6dw_tm45utz.css',
|
||||
'/_next/static/chunks/1oskchnhjm4n8.css',
|
||||
'/_next/static/chunks/21luguo5_g2uu.js',
|
||||
];
|
||||
|
||||
for (const f of files) {
|
||||
const r = await httpGet(`https://demoplace.my.id${f}`);
|
||||
const icon = r.status === 200 ? '✅' : '❌';
|
||||
console.log(` ${icon} ${f}`);
|
||||
console.log(` HTTP ${r.status} | Type: ${r.type || 'N/A'} | Size: ${r.size || 0} bytes`);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(err => console.error('[FATAL]', err.message));
|
||||
@@ -1,61 +0,0 @@
|
||||
const https = require('https');
|
||||
|
||||
const PAGES = [
|
||||
'/',
|
||||
'/network-infrastructure',
|
||||
'/agents',
|
||||
'/devices',
|
||||
'/flows',
|
||||
'/apps',
|
||||
'/network-intelligence',
|
||||
'/dns',
|
||||
'/geography',
|
||||
'/dpi-analytics',
|
||||
'/lookup',
|
||||
'/intelligence',
|
||||
'/threats',
|
||||
'/events',
|
||||
'/security-audit',
|
||||
'/help'
|
||||
];
|
||||
|
||||
function fetchPage(route) {
|
||||
return new Promise((resolve) => {
|
||||
https.get(`https://demoplace.my.id${route}`, (res) => {
|
||||
let data = '';
|
||||
res.on('data', chunk => data += chunk);
|
||||
res.on('end', () => {
|
||||
const titleMatch = data.match(/<title>(.*?)<\/title>/i);
|
||||
const descMatch = data.match(/<meta name="description" content="(.*?)"/i);
|
||||
const title = titleMatch ? titleMatch[1] : 'N/A';
|
||||
const desc = descMatch ? descMatch[1] : 'N/A';
|
||||
|
||||
// Find logo references
|
||||
const logos = [];
|
||||
const logoRegex = /src="([^"]*(?:logo|icon)[^"]*)"/gi;
|
||||
let match;
|
||||
while ((match = logoRegex.exec(data)) !== null) {
|
||||
if (!logos.includes(match[1])) logos.push(match[1]);
|
||||
}
|
||||
|
||||
resolve({ route, statusCode: res.statusCode, title, desc, logos });
|
||||
});
|
||||
}).on('error', (err) => {
|
||||
resolve({ route, error: err.message });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('=== AUDITING DEMOPLACE.MY.ID PAGES ===\n');
|
||||
for (const page of PAGES) {
|
||||
const res = await fetchPage(page);
|
||||
console.log(`Route: ${res.route}`);
|
||||
console.log(` Title : ${res.title}`);
|
||||
console.log(` Description : ${res.desc}`);
|
||||
console.log(` Logos/Icons : ${res.logos ? res.logos.join(', ') : 'None'}`);
|
||||
console.log('---');
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,97 +0,0 @@
|
||||
// scripts/copy-from-backslash.js
|
||||
// Copy file dari direktori backslash ke path yang benar
|
||||
'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 PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
const SA = PUB + '/.next/standalone/.next/static';
|
||||
const BSDir = PUB + '/.next\\static\\chunks'; // Backslash literal path
|
||||
|
||||
function exec(conn, cmd, label) {
|
||||
if (label) console.log('\n[' + label + ']');
|
||||
console.log('$ ' + cmd.substring(0, 90));
|
||||
return new Promise(resolve => {
|
||||
conn.exec(cmd, (err, s) => {
|
||||
if (err) { resolve(''); return; }
|
||||
let out = '';
|
||||
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.on('close', () => resolve(out));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function httpGet(url) {
|
||||
return new Promise(resolve => {
|
||||
const req = https.get(url, { timeout: 12000, rejectUnauthorized: false }, res => {
|
||||
let body = '';
|
||||
res.on('data', d => body += d);
|
||||
res.on('end', () => resolve({ status: res.statusCode, size: body.length }));
|
||||
});
|
||||
req.on('error', e => resolve({ status: 0, error: e.message }));
|
||||
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const conn = new Client();
|
||||
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(SSH); });
|
||||
console.log('[SSH] Connected\n');
|
||||
|
||||
// 1. List isi direktori backslash
|
||||
await exec(conn, "ls '" + BSDir + "' | grep css | head -10", '1. CSS di direktori backslash');
|
||||
|
||||
// 2. Copy semua file dari direktori backslash ke standalone/chunks
|
||||
await exec(conn,
|
||||
"cp '" + BSDir + "/'* '" + SA + "/chunks/' 2>&1 && echo 'COPY OK' || echo 'COPY PARTIAL'",
|
||||
'2. Copy semua file dari backslash dir ke standalone/chunks'
|
||||
);
|
||||
|
||||
// 3. Verifikasi CSS yang hilang sudah ada
|
||||
await exec(conn,
|
||||
"ls '" + SA + "/chunks/' | grep '1oskchnhjm4n8'",
|
||||
'3. Verifikasi 1oskchnhjm4n8.css ada'
|
||||
);
|
||||
|
||||
// 4. Juga cek nested static dir (ada static/static/)
|
||||
await exec(conn,
|
||||
"ls '" + SA + "/static/' 2>/dev/null | head -10 || echo 'Tidak ada nested static'",
|
||||
'4. Cek nested static dir'
|
||||
);
|
||||
|
||||
// 5. Cek juga backslash css dir (beda dengan chunks)
|
||||
await exec(conn,
|
||||
"ls '" + PUB + "/.next\\static\\css' 2>/dev/null | head -10 || echo 'Tidak ada backslash css dir'",
|
||||
'5. Cek backslash css dir'
|
||||
);
|
||||
|
||||
// 6. Copy CSS dari backslash css dir juga jika ada
|
||||
await exec(conn,
|
||||
"[ -d '" + PUB + "/.next\\static\\css' ] && cp '" + PUB + "/.next\\static\\css/'* '" + SA + "/css/' 2>&1 && echo 'CSS copy OK' || echo 'Tidak ada backslash css dir'",
|
||||
'6. Copy dari backslash css dir'
|
||||
);
|
||||
|
||||
conn.end();
|
||||
|
||||
// 7. Final test
|
||||
console.log('\n[7. Final test semua static files...]');
|
||||
await new Promise(r => setTimeout(r, 2000));
|
||||
const files = [
|
||||
'/_next/static/chunks/1oskchnhjm4n8.css',
|
||||
'/_next/static/chunks/1u6dw_tm45utz.css',
|
||||
'/_next/static/chunks/3km6z-n6wbgrs.js',
|
||||
'/_next/static/chunks/21luguo5_g2uu.js',
|
||||
'/_next/static/chunks/1-8s9_t85wwr4.js',
|
||||
'/login',
|
||||
];
|
||||
for (const f of files) {
|
||||
const r = await httpGet('https://demoplace.my.id' + f);
|
||||
const icon = r.status === 200 ? '✅' : '❌';
|
||||
console.log(' ' + icon + ' HTTP ' + r.status + ' | ' + (r.size || 0) + ' bytes | ' + f);
|
||||
}
|
||||
console.log('\n✅ Selesai! Hard refresh browser (Ctrl+Shift+R)\n');
|
||||
}
|
||||
|
||||
main().catch(e => console.error('[FATAL]', e.message));
|
||||
@@ -1,48 +0,0 @@
|
||||
// scripts/deep-diag.js
|
||||
'use strict';
|
||||
const { Client } = require('ssh2');
|
||||
const conn = new Client();
|
||||
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
|
||||
function exec(conn, cmd) {
|
||||
console.log('\n$ ' + cmd.substring(0, 80));
|
||||
return new Promise(resolve => {
|
||||
conn.exec(cmd, (err, s) => {
|
||||
if (err) { resolve(''); return; }
|
||||
let out = '';
|
||||
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.on('close', () => resolve(out));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
conn.on('ready', async () => {
|
||||
// 1. Cek proses yang sedang berjalan
|
||||
await exec(conn, 'ps -p 3193322 -o cmd 2>/dev/null | tail -1');
|
||||
|
||||
// 2. Cek BUILD_ID di standalone
|
||||
const saPath = PUB + '/.next/standalone';
|
||||
await exec(conn, 'cat ' + saPath + '/.next/BUILD_ID 2>/dev/null || echo NO_BUILD_ID_IN_STANDALONE');
|
||||
|
||||
// 3. List chunks di standalone
|
||||
await exec(conn, 'ls ' + saPath + '/.next/static/chunks/ | head -15');
|
||||
|
||||
// 4. List static root di standalone
|
||||
await exec(conn, 'ls ' + saPath + '/.next/static/');
|
||||
|
||||
// 5. Cek apakah ada server.js lain yang mungkin sedang berjalan
|
||||
await exec(conn, 'ps aux | grep "node.*server" | grep -v grep | head -5');
|
||||
|
||||
// 6. PM2 info untuk backone-frontend
|
||||
await exec(conn, '/home/adminbackend/.npm-global/bin/pm2 show backone-frontend 2>/dev/null | grep -E "(script|cwd|pid|restart)"');
|
||||
|
||||
// 7. Cek log terbaru
|
||||
await exec(conn, 'tail -20 ' + PUB + '/logs/frontend-out.log 2>/dev/null | head -20');
|
||||
|
||||
conn.end();
|
||||
}).connect({
|
||||
host: '103.185.47.52', port: 2222,
|
||||
username: 'adminbackend', password: 'htEo7x6LsBQiEHHH',
|
||||
readyTimeout: 30000
|
||||
});
|
||||
@@ -1,57 +0,0 @@
|
||||
const { Client } = require('ssh2');
|
||||
const fs = require('fs');
|
||||
|
||||
const remoteScript = `
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const root = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
|
||||
console.log('=== 1. LOGOS & IMAGES IN PUBLIC ===');
|
||||
try {
|
||||
const publicFiles = fs.readdirSync(path.join(root, 'public'));
|
||||
console.log('Files in public/:', publicFiles);
|
||||
} catch(e) { console.log('Err:', e.message); }
|
||||
|
||||
console.log('\\n=== 2. AUDITING NAVIGATION GROUPS IN STANDALONE CHUNKS ===');
|
||||
const chunksDir = path.join(root, '.next/standalone/.next/server/chunks');
|
||||
if (fs.existsSync(chunksDir)) {
|
||||
const files = fs.readdirSync(chunksDir);
|
||||
files.forEach(f => {
|
||||
if (!f.endsWith('.js')) return;
|
||||
const content = fs.readFileSync(path.join(chunksDir, f), 'utf8');
|
||||
if (content.includes('Overview Dashboard') || content.includes('Network Topology')) {
|
||||
console.log('Chunk File:', f);
|
||||
const match = content.match(/title:\"OVERVIEW\".*?title:\"SECURITY & ALERTS\".*?\]/);
|
||||
if (match) {
|
||||
console.log('NAV MATCH:', match[0]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
console.log('\\n=== 3. APP ROUTE DIRECTORIES ===');
|
||||
try {
|
||||
const appDir = path.join(root, '.next/standalone/.next/server/app/(dashboard)');
|
||||
if (fs.existsSync(appDir)) {
|
||||
console.log('Dashboard routes in .next/standalone:', fs.readdirSync(appDir));
|
||||
}
|
||||
} catch(e) { console.log('Err app dir:', e.message); }
|
||||
`;
|
||||
|
||||
const conn = new Client();
|
||||
conn.on('ready', () => {
|
||||
conn.exec(`node -e ${JSON.stringify(remoteScript)}`, (err, stream) => {
|
||||
let out = '';
|
||||
stream.on('data', d => out += d);
|
||||
stream.on('close', () => {
|
||||
console.log(out);
|
||||
conn.end();
|
||||
});
|
||||
});
|
||||
}).connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
@@ -1,206 +0,0 @@
|
||||
// scripts/deploy-php-proxy.js
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// BackOne DPI — Deploy PHP proxy ke public_html
|
||||
// Solusi 502: Apache PHP-FPM forward semua request ke Next.js port 3000
|
||||
// Tidak butuh mod_proxy_http, root access, atau Hestia API
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
'use strict';
|
||||
|
||||
const { Client } = require('ssh2');
|
||||
const SftpClient = require('ssh2-sftp-client');
|
||||
const https = require('https');
|
||||
const path = require('path');
|
||||
|
||||
const SSH_CONFIG = {
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH',
|
||||
readyTimeout: 60000
|
||||
};
|
||||
|
||||
const ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
|
||||
// ── PHP Proxy script ──────────────────────────────────────────────────────
|
||||
const PHP_PROXY = `<?php
|
||||
/**
|
||||
* BackOne DPI — PHP Reverse Proxy
|
||||
* Meneruskan semua request HTTP ke Next.js yang berjalan di port 3000
|
||||
* File ini dikelola otomatis. Jangan dihapus.
|
||||
*/
|
||||
|
||||
// Target: Next.js port 3000
|
||||
define('NEXTJS_URL', 'http://127.0.0.1:3000');
|
||||
define('TIMEOUT', 30);
|
||||
|
||||
// Ambil URI request
|
||||
$requestUri = $_SERVER['REQUEST_URI'] ?? '/';
|
||||
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
|
||||
$target = NEXTJS_URL . $requestUri;
|
||||
|
||||
// Kumpulkan headers dari request asli
|
||||
$forwardHeaders = [
|
||||
'X-Forwarded-For: ' . ($_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1'),
|
||||
'X-Forwarded-Proto: https',
|
||||
'X-Real-IP: ' . ($_SERVER['REMOTE_ADDR'] ?? ''),
|
||||
'Host: ' . ($_SERVER['HTTP_HOST'] ?? 'demoplace.my.id'),
|
||||
];
|
||||
|
||||
// Tambahkan headers lain dari request
|
||||
$allHeaders = getallheaders() ?: [];
|
||||
$skipHeaders = ['host', 'connection', 'transfer-encoding', 'keep-alive', 'content-length'];
|
||||
foreach ($allHeaders as $name => $value) {
|
||||
if (!in_array(strtolower($name), $skipHeaders)) {
|
||||
$forwardHeaders[] = "$name: $value";
|
||||
}
|
||||
}
|
||||
|
||||
// Body untuk POST/PUT/PATCH
|
||||
$body = in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE']) ? file_get_contents('php://input') : null;
|
||||
|
||||
// Kirim request ke Next.js
|
||||
$ch = curl_init();
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => $target,
|
||||
CURLOPT_CUSTOMREQUEST => $method,
|
||||
CURLOPT_HTTPHEADER => $forwardHeaders,
|
||||
CURLOPT_POSTFIELDS => $body,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_HEADER => true,
|
||||
CURLOPT_FOLLOWLOCATION => false,
|
||||
CURLOPT_TIMEOUT => TIMEOUT,
|
||||
CURLOPT_CONNECTTIMEOUT => 5,
|
||||
CURLOPT_ENCODING => '',
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||
$curlError = curl_error($ch);
|
||||
curl_close($ch);
|
||||
|
||||
// Jika curl error
|
||||
if ($response === false) {
|
||||
http_response_code(502);
|
||||
header('Content-Type: text/plain');
|
||||
echo 'BackOne: Gagal terhubung ke Next.js. Error: ' . $curlError;
|
||||
exit;
|
||||
}
|
||||
|
||||
// Pisah headers dan body
|
||||
$responseHeaders = substr($response, 0, $headerSize);
|
||||
$responseBody = substr($response, $headerSize);
|
||||
|
||||
// Set HTTP status
|
||||
http_response_code($httpCode ?: 200);
|
||||
|
||||
// Forward response headers ke client
|
||||
$skipResponseHeaders = ['transfer-encoding', 'connection', 'keep-alive', 'content-encoding'];
|
||||
foreach (explode("\\r\\n", $responseHeaders) as $header) {
|
||||
$header = trim($header);
|
||||
if (empty($header) || preg_match('/^HTTP\\//i', $header)) continue;
|
||||
$colonPos = strpos($header, ':');
|
||||
if ($colonPos === false) continue;
|
||||
$headerName = strtolower(trim(substr($header, 0, $colonPos)));
|
||||
if (in_array($headerName, $skipResponseHeaders)) continue;
|
||||
header($header, false);
|
||||
}
|
||||
|
||||
// Kirim body
|
||||
echo $responseBody;
|
||||
`;
|
||||
|
||||
// ── .htaccess baru: route semua request ke proxy.php ─────────────────────
|
||||
const HTACCESS = `# BackOne DPI — Apache .htaccess
|
||||
# Redirect HTTP ke HTTPS
|
||||
RewriteEngine On
|
||||
RewriteCond %{HTTPS} !=on
|
||||
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
|
||||
|
||||
# Route semua request ke PHP proxy (meneruskan ke Next.js port 3000)
|
||||
RewriteCond %{REQUEST_FILENAME} !proxy.php
|
||||
RewriteRule ^(.*)$ /proxy.php [L,QSA]
|
||||
`;
|
||||
|
||||
// ── Fungsi upload file via SFTP ───────────────────────────────────────────
|
||||
async function uploadFile(sftp, content, remotePath) {
|
||||
const buf = Buffer.from(content, 'utf8');
|
||||
await sftp.put(buf, remotePath);
|
||||
console.log(` ✅ Upload: ${remotePath}`);
|
||||
}
|
||||
|
||||
// ── SSH command ────────────────────────────────────────────────────────────
|
||||
function sshExec(conn, cmd) {
|
||||
console.log(`\n$ ${cmd.substring(0, 100)}...`);
|
||||
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()); });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
||||
console.log('║ BackOne DPI — Deploy PHP Proxy (Fix 502) ║');
|
||||
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
||||
|
||||
// ── Upload via SFTP ──────────────────────────────────────────────────────
|
||||
console.log('▶ Step 1: Upload proxy.php dan .htaccess via SFTP...\n');
|
||||
const sftp = new SftpClient();
|
||||
await sftp.connect(SSH_CONFIG);
|
||||
|
||||
await uploadFile(sftp, PHP_PROXY, `${ROOT}/proxy.php`);
|
||||
await uploadFile(sftp, HTACCESS, `${ROOT}/.htaccess`);
|
||||
await sftp.end();
|
||||
|
||||
// ── Verify dan test via SSH ──────────────────────────────────────────────
|
||||
console.log('\n▶ Step 2: Verifikasi file di server...');
|
||||
const conn = new Client();
|
||||
await new Promise((resolve, reject) => { conn.on('ready', resolve).on('error', reject).connect(SSH_CONFIG); });
|
||||
console.log('[SSH] Terhubung!\n');
|
||||
|
||||
await sshExec(conn, `ls -la ${ROOT}/proxy.php ${ROOT}/.htaccess`);
|
||||
await sshExec(conn, `head -5 ${ROOT}/proxy.php`);
|
||||
await sshExec(conn, `cat ${ROOT}/.htaccess`);
|
||||
|
||||
// ── Test internal Apache response ─────────────────────────────────────
|
||||
console.log('\n▶ Step 3: Test Apache internal (port 8080)...');
|
||||
await sshExec(conn, `curl -sk -o /dev/null -w "Apache HTTP: %{http_code}" http://127.0.0.1:8080/`);
|
||||
await sshExec(conn, `curl -sk -o /dev/null -w "Apache Login: %{http_code}" http://127.0.0.1:8080/login`);
|
||||
|
||||
// ── Test domain publik ─────────────────────────────────────────────────
|
||||
console.log('\n▶ Step 4: Test domain demoplace.my.id...');
|
||||
await sshExec(conn,
|
||||
`sleep 2 && curl -sk -o /dev/null -w "HTTPS /: %{http_code}" https://demoplace.my.id/ && ` +
|
||||
`curl -sk -o /dev/null -w " | HTTPS /login: %{http_code}" https://demoplace.my.id/login`
|
||||
);
|
||||
|
||||
conn.end();
|
||||
|
||||
// ── Final test dari luar ───────────────────────────────────────────────
|
||||
console.log('\n▶ Step 5: Final test dari jaringan lokal...');
|
||||
await new Promise(r => setTimeout(r, 3000));
|
||||
|
||||
for (const path of ['/', '/login']) {
|
||||
const r = await new Promise(resolve => {
|
||||
const req = https.get(`https://demoplace.my.id${path}`,
|
||||
{ timeout: 12000, 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 = r.status >= 200 && r.status < 400 ? '✅' : r.status === 0 ? '⚠️ ' : '❌';
|
||||
console.log(` ${icon} https://demoplace.my.id${path} → HTTP ${r.status} ${r.error || ''}`);
|
||||
if (r.location) console.log(` → Redirect ke: ${r.location}`);
|
||||
}
|
||||
|
||||
console.log('\n✅ PHP Proxy berhasil di-deploy!\n');
|
||||
console.log('Cek browser: https://demoplace.my.id/login\n');
|
||||
}
|
||||
|
||||
main().catch(err => { console.error('[FATAL]', err.message); process.exit(1); });
|
||||
@@ -1,117 +0,0 @@
|
||||
const { Client } = require('ssh2');
|
||||
const SftpClient = require('ssh2-sftp-client');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const archiver = require('archiver');
|
||||
|
||||
const config = {
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
};
|
||||
|
||||
const DEPLOY_DIR = 'backone-production';
|
||||
|
||||
async function createZip() {
|
||||
console.log("Packaging application...");
|
||||
return new Promise((resolve, reject) => {
|
||||
const output = fs.createWriteStream(path.join(__dirname, '../deploy.zip'));
|
||||
const archive = new archiver.ZipArchive({ zlib: { level: 9 } });
|
||||
|
||||
output.on('close', () => resolve(path.join(__dirname, '../deploy.zip')));
|
||||
archive.on('error', (err) => reject(err));
|
||||
|
||||
archive.pipe(output);
|
||||
|
||||
// Add standalone output
|
||||
archive.directory(path.join(__dirname, '../.next/standalone'), false);
|
||||
|
||||
// Add static assets (Next.js standalone requires these copied over)
|
||||
archive.directory(path.join(__dirname, '../.next/static'), '.next/static');
|
||||
archive.directory(path.join(__dirname, '../public'), 'public');
|
||||
|
||||
// Add backend and proxy
|
||||
archive.directory(path.join(__dirname, '../backend'), 'backend');
|
||||
archive.directory(path.join(__dirname, '../proxy'), 'proxy');
|
||||
|
||||
// Add production env
|
||||
archive.file(path.join(__dirname, '../.env.production'), { name: '.env.production' });
|
||||
|
||||
archive.finalize();
|
||||
});
|
||||
}
|
||||
|
||||
async function runSSH(cmd) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const conn = new Client();
|
||||
conn.on('ready', () => {
|
||||
conn.exec(cmd, (err, stream) => {
|
||||
if (err) return reject(err);
|
||||
let out = '';
|
||||
stream.on('close', (code, signal) => {
|
||||
conn.end();
|
||||
resolve(out);
|
||||
}).on('data', (data) => {
|
||||
out += data;
|
||||
}).stderr.on('data', (data) => {
|
||||
out += data;
|
||||
});
|
||||
});
|
||||
}).on('error', reject).connect(config);
|
||||
});
|
||||
}
|
||||
|
||||
async function deploy() {
|
||||
const sftp = new SftpClient();
|
||||
let zipPath;
|
||||
try {
|
||||
zipPath = await createZip();
|
||||
console.log("Package created successfully.");
|
||||
|
||||
console.log("Connecting to SFTP server...");
|
||||
await sftp.connect(config);
|
||||
|
||||
console.log("Creating deployment directory...");
|
||||
const homeDir = await runSSH('pwd');
|
||||
const targetDir = `${homeDir.trim()}/${DEPLOY_DIR}`;
|
||||
await runSSH(`mkdir -p ${targetDir}`);
|
||||
|
||||
console.log(`Uploading deploy.zip to ${targetDir}...`);
|
||||
await sftp.put(zipPath, `${targetDir}/deploy.zip`);
|
||||
|
||||
console.log("Extracting package on server...");
|
||||
await runSSH(`cd ${targetDir} && unzip -o deploy.zip && rm deploy.zip`);
|
||||
|
||||
console.log("Installing production dependencies for backend & proxy...");
|
||||
await runSSH(`cd ${targetDir}/backend && npm install --production`);
|
||||
await runSSH(`cd ${targetDir}/proxy && npm install --production`);
|
||||
|
||||
console.log("Configuring PM2...");
|
||||
// Create ecosystem file for PM2
|
||||
const ecosystem = `
|
||||
module.exports = {
|
||||
apps: [
|
||||
{ name: 'backone-proxy', script: './proxy/index.js', env_file: '.env.production' },
|
||||
{ name: 'backone-backend', script: './backend/server.js', env_file: '.env.production' },
|
||||
{ name: 'backone-frontend', script: 'server.js', env_file: '.env.production' }
|
||||
]
|
||||
};`;
|
||||
await runSSH(`cd ${targetDir} && echo "${ecosystem.replace(/\n/g, '\\n')}" > ecosystem.config.js`);
|
||||
|
||||
console.log("Restarting PM2 processes...");
|
||||
const pm2Result = await runSSH(`cd ${targetDir} && pm2 start ecosystem.config.js || pm2 restart ecosystem.config.js`);
|
||||
console.log(pm2Result);
|
||||
|
||||
console.log("Deployment completed successfully!");
|
||||
console.log(`BackOne Dashboard is now live. Please map your Nginx/Apache domain demoplace.my.id to http://127.0.0.1:3000`);
|
||||
|
||||
} catch(e) {
|
||||
console.error("Deployment failed:", e.message);
|
||||
} finally {
|
||||
sftp.end();
|
||||
if (fs.existsSync(zipPath)) fs.unlinkSync(zipPath);
|
||||
}
|
||||
}
|
||||
|
||||
deploy();
|
||||
@@ -1,84 +0,0 @@
|
||||
const https = require('https');
|
||||
|
||||
const ROUTES = [
|
||||
'/',
|
||||
'/agents',
|
||||
'/apps',
|
||||
'/devices',
|
||||
'/dns',
|
||||
'/dpi-analytics',
|
||||
'/encryption-audit',
|
||||
'/events',
|
||||
'/flows',
|
||||
'/geography',
|
||||
'/intelligence',
|
||||
'/lookup',
|
||||
'/network-infrastructure',
|
||||
'/network-intelligence',
|
||||
'/network-topology',
|
||||
'/security-audit',
|
||||
'/threat-intelligence',
|
||||
'/threats',
|
||||
'/traffic-categories',
|
||||
'/help',
|
||||
'/login'
|
||||
];
|
||||
|
||||
function auditRoute(route) {
|
||||
return new Promise((resolve) => {
|
||||
https.get(`https://demoplace.my.id${route}`, (res) => {
|
||||
let data = '';
|
||||
res.on('data', c => data += c);
|
||||
res.on('end', () => {
|
||||
const title = (data.match(/<title>(.*?)<\/title>/i) || [])[1] || 'N/A';
|
||||
const desc = (data.match(/<meta name="description" content="(.*?)"/i) || [])[1] || 'N/A';
|
||||
const icons = [];
|
||||
const iconMatches = data.matchAll(/rel="icon" href="([^"]+)"/gi);
|
||||
for (const m of iconMatches) icons.push(m[1]);
|
||||
|
||||
const imgs = [];
|
||||
const imgMatches = data.matchAll(/src="([^"]*(?:logo|brand|icon|png|svg|jpg)[^"]*)"/gi);
|
||||
for (const m of imgMatches) {
|
||||
if (!imgs.includes(m[1])) imgs.push(m[1]);
|
||||
}
|
||||
|
||||
const headers = [];
|
||||
const hMatches = data.matchAll(/<h[123][^>]*>(.*?)<\/h[123]>/gi);
|
||||
for (const m of hMatches) {
|
||||
const clean = m[1].replace(/<[^>]+>/g, '').trim();
|
||||
if (clean && !headers.includes(clean)) headers.push(clean);
|
||||
}
|
||||
|
||||
resolve({
|
||||
route,
|
||||
status: res.statusCode,
|
||||
is404: data.includes('404: This page could not be found'),
|
||||
title,
|
||||
desc,
|
||||
icons,
|
||||
imgs,
|
||||
headers
|
||||
});
|
||||
});
|
||||
}).on('error', err => resolve({ route, error: err.message }));
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('=== DETAILED AUDIT OF DEMOPLACE.MY.ID ===\n');
|
||||
for (const r of ROUTES) {
|
||||
const res = await auditRoute(r);
|
||||
if (res.is404) {
|
||||
console.log(`❌ [404 NOT FOUND] ${res.route}`);
|
||||
} else {
|
||||
console.log(`✅ [200 OK] ${res.route}`);
|
||||
console.log(` Title : ${res.title}`);
|
||||
console.log(` Icons : ${res.icons.join(', ')}`);
|
||||
console.log(` Images/Logo: ${res.imgs.join(', ')}`);
|
||||
console.log(` Headers : ${res.headers.join(' | ')}`);
|
||||
}
|
||||
console.log('--------------------------------------------------');
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,99 +0,0 @@
|
||||
// scripts/diagnose-ports.js
|
||||
// Cek port apa yang aktif dan test PHP proxy di port yang benar
|
||||
'use strict';
|
||||
|
||||
const { Client } = require('ssh2');
|
||||
|
||||
const SSH = {
|
||||
host: '103.185.47.52', port: 2222,
|
||||
username: 'adminbackend', password: 'htEo7x6LsBQiEHHH',
|
||||
readyTimeout: 60000
|
||||
};
|
||||
|
||||
function sshExec(conn, cmd, label = '') {
|
||||
if (label) console.log(`\n[${label}]`);
|
||||
console.log(`$ ${cmd.substring(0, 100)}${cmd.length > 100 ? '...' : ''}`);
|
||||
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()); });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
||||
console.log('║ BackOne DPI — Diagnosa Port & PHP Proxy Test ║');
|
||||
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');
|
||||
|
||||
// 1. Cek semua port yang aktif
|
||||
await sshExec(conn,
|
||||
'echo "=== SEMUA PORT AKTIF ===" && ss -tlnp | grep -E "(80|443|3000|3001|4000|8008|8009|8080|8443)"',
|
||||
'PORT AKTIF'
|
||||
);
|
||||
|
||||
// 2. Cek apakah Apache aktif di berbagai port
|
||||
await sshExec(conn,
|
||||
'echo "=== TES APACHE PORT 8009 ===" && curl -sk -o /dev/null -w "Port 8009: %{http_code}" http://127.0.0.1:8009/login',
|
||||
'TES PORT 8009'
|
||||
);
|
||||
|
||||
await sshExec(conn,
|
||||
'echo "=== TES APACHE PORT 8080 (IP publik) ===" && curl -sk -o /dev/null -w "Port 8080 publik: %{http_code}" http://103.185.47.52:8080/login',
|
||||
'TES PORT 8080'
|
||||
);
|
||||
|
||||
// 3. Cek apakah PHP FPM socket ada
|
||||
await sshExec(conn,
|
||||
'ls -la /run/php/php*-fpm-demoplace* 2>/dev/null || echo "Tidak ada PHP FPM socket untuk domain ini"',
|
||||
'PHP FPM SOCKET'
|
||||
);
|
||||
|
||||
// 4. Cek isi .htaccess yang aktif
|
||||
await sshExec(conn,
|
||||
'cat /home/adminbackend/web/demoplace.my.id/public_html/.htaccess',
|
||||
'HTACCESS AKTIF'
|
||||
);
|
||||
|
||||
// 5. Cek apakah proxy.php bisa diakses via Apache
|
||||
await sshExec(conn,
|
||||
'curl -sk -v http://127.0.0.1:8009/proxy.php 2>&1 | head -30',
|
||||
'TES proxy.php via port 8009'
|
||||
);
|
||||
|
||||
// 6. Test direct PHP execution
|
||||
await sshExec(conn,
|
||||
'php -r "echo curl_version()[\'version\'];" 2>/dev/null && echo " (PHP curl OK)" || echo "PHP curl tidak tersedia"',
|
||||
'CEK PHP CURL'
|
||||
);
|
||||
|
||||
// 7. Cek Apache error log
|
||||
await sshExec(conn,
|
||||
'tail -20 /var/log/apache2/domains/demoplace.my.id.error.log 2>/dev/null | grep -v "^\$" | tail -10 || echo "Tidak bisa akses error log"',
|
||||
'APACHE ERROR LOG'
|
||||
);
|
||||
|
||||
// 8. Test Next.js langsung
|
||||
await sshExec(conn,
|
||||
'curl -sk -o /dev/null -w "Next.js port 3000 /login: %{http_code}" http://127.0.0.1:3000/login',
|
||||
'TES NEXT.JS LANGSUNG'
|
||||
);
|
||||
|
||||
// 9. Coba test PHP via curl dengan header Host
|
||||
await sshExec(conn,
|
||||
'curl -sk -H "Host: demoplace.my.id" -o /dev/null -w "Apache dengan Host header: %{http_code}" http://127.0.0.1:8009/',
|
||||
'TES APACHE HOST HEADER'
|
||||
);
|
||||
|
||||
conn.end();
|
||||
console.log('\n✅ Diagnosa selesai!\n');
|
||||
}
|
||||
|
||||
main().catch(err => { console.error('[FATAL]', err.message); process.exit(1); });
|
||||
@@ -1,90 +0,0 @@
|
||||
// scripts/download-production.js
|
||||
'use strict';
|
||||
|
||||
const SftpClient = require('ssh2-sftp-client');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const CONFIG = {
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH',
|
||||
remotePath: '/home/adminbackend/web/demoplace.my.id/public_html',
|
||||
};
|
||||
|
||||
const LOCAL_ROOT = path.resolve(__dirname, '..');
|
||||
|
||||
const DIRS_TO_DOWNLOAD = ['src', 'backend', 'proxy', 'public', 'scripts'];
|
||||
const FILES_TO_DOWNLOAD = [
|
||||
'package.json',
|
||||
'package-lock.json',
|
||||
'next.config.ts',
|
||||
'postcss.config.mjs',
|
||||
'tsconfig.json',
|
||||
'eslint.config.mjs',
|
||||
'README.md',
|
||||
'SKILLS.md',
|
||||
'Dockerfile',
|
||||
'docker-compose.yml',
|
||||
'docker-compose.prod.yml',
|
||||
'ecosystem.config.js',
|
||||
'deploy.sh'
|
||||
];
|
||||
|
||||
async function main() {
|
||||
const sftp = new SftpClient();
|
||||
try {
|
||||
console.log(`[SFTP] Connecting to ${CONFIG.host}:${CONFIG.port}...`);
|
||||
await sftp.connect({
|
||||
host: CONFIG.host,
|
||||
port: CONFIG.port,
|
||||
username: CONFIG.username,
|
||||
password: CONFIG.password,
|
||||
});
|
||||
console.log('[SFTP] Connected successfully.');
|
||||
|
||||
// 1. Download directories recursively
|
||||
for (const dirName of DIRS_TO_DOWNLOAD) {
|
||||
const remoteDir = `${CONFIG.remotePath}/${dirName}`;
|
||||
const localDir = path.join(LOCAL_ROOT, dirName);
|
||||
|
||||
if (await sftp.exists(remoteDir)) {
|
||||
console.log(`[SFTP] Downloading directory: ${dirName}...`);
|
||||
fs.mkdirSync(localDir, { recursive: true });
|
||||
await sftp.downloadDir(remoteDir, localDir, {
|
||||
filter: (filePath, isDir) => {
|
||||
const basename = path.basename(filePath);
|
||||
return !['node_modules', '.next', '.git', 'logs', 'repo.zip'].includes(basename);
|
||||
}
|
||||
});
|
||||
console.log(`[SFTP] Finished downloading directory: ${dirName}`);
|
||||
} else {
|
||||
console.warn(`[SFTP] Remote directory not found: ${remoteDir}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Download specific root files
|
||||
for (const fileName of FILES_TO_DOWNLOAD) {
|
||||
const remoteFile = `${CONFIG.remotePath}/${fileName}`;
|
||||
const localFile = path.join(LOCAL_ROOT, fileName);
|
||||
|
||||
if (await sftp.exists(remoteFile)) {
|
||||
console.log(`[SFTP] Downloading file: ${fileName}...`);
|
||||
await sftp.fastGet(remoteFile, localFile);
|
||||
console.log(`[SFTP] Downloaded: ${fileName}`);
|
||||
} else {
|
||||
console.warn(`[SFTP] Remote file not found: ${remoteFile}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n✅ [SFTP] Download of production codebase (10/10) completed successfully!');
|
||||
} catch (err) {
|
||||
console.error('❌ [SFTP] Download failed:', err);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
await sftp.end();
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,42 +0,0 @@
|
||||
// scripts/export-local-db.js
|
||||
const { MongoClient } = require('mongodb');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const LOCAL_URI = 'mongodb://127.0.0.1:27017/backone_dpi';
|
||||
const DB_NAME = 'backone_dpi';
|
||||
|
||||
const COLLECTIONS_TO_EXPORT = ['users', 'tenantconfigs', 'customagentlocations'];
|
||||
const OUTPUT_DIR = path.join(__dirname, '..', 'migration-temp');
|
||||
|
||||
async function main() {
|
||||
console.log('Connecting to local MongoDB...');
|
||||
const client = new MongoClient(LOCAL_URI);
|
||||
|
||||
try {
|
||||
await client.connect();
|
||||
console.log('✓ Connected to local MongoDB successfully.');
|
||||
const db = client.db(DB_NAME);
|
||||
|
||||
if (!fs.existsSync(OUTPUT_DIR)) {
|
||||
fs.mkdirSync(OUTPUT_DIR);
|
||||
}
|
||||
|
||||
for (const colName of COLLECTIONS_TO_EXPORT) {
|
||||
console.log(`Exporting collection: ${colName}...`);
|
||||
const documents = await db.collection(colName).find({}).toArray();
|
||||
const filePath = path.join(OUTPUT_DIR, `${colName}.json`);
|
||||
fs.writeFileSync(filePath, JSON.stringify(documents, null, 2));
|
||||
console.log(` ✓ Exported ${documents.length} documents to ${filePath}`);
|
||||
}
|
||||
|
||||
console.log('\n✓ Database export complete!');
|
||||
} catch (err) {
|
||||
console.error('✗ Export failed:', err.message);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
await client.close();
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,62 +0,0 @@
|
||||
const SftpClient = require('ssh2-sftp-client');
|
||||
const { Client } = require('ssh2');
|
||||
|
||||
const remoteExtractScript = `
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const root = '/home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/.next/server/chunks';
|
||||
|
||||
console.log('=== EXTRACTING ALL PAGE HEADERS FROM CHUNKS ===\\n');
|
||||
|
||||
const files = fs.readdirSync(root);
|
||||
files.forEach(f => {
|
||||
if (!f.endsWith('.js')) return;
|
||||
const content = fs.readFileSync(path.join(root, f), 'utf8');
|
||||
|
||||
// Match header titles in React JSX: e.g. text-3xl font-bold ... >TitleText<
|
||||
const titleMatches = content.matchAll(/text-3xl[^>]*>([^<]{3,40})</gi);
|
||||
for (const m of titleMatches) {
|
||||
console.log(\`Chunk \${f}: "\${m[1].trim()}"\`);
|
||||
}
|
||||
|
||||
// Match tab names in React JSX
|
||||
const tabMatches = content.matchAll(/role="tab"[^>]*>([^<]{3,30})</gi);
|
||||
for (const m of tabMatches) {
|
||||
console.log(\`Chunk \${f} Tab: "\${m[1].trim()}"\`);
|
||||
}
|
||||
});
|
||||
`;
|
||||
|
||||
async function main() {
|
||||
const sftp = new SftpClient();
|
||||
await sftp.connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
|
||||
const remoteScriptPath = '/home/adminbackend/extract_client_titles.js';
|
||||
await sftp.put(Buffer.from(remoteExtractScript), remoteScriptPath);
|
||||
await sftp.end();
|
||||
|
||||
const conn = new Client();
|
||||
conn.on('ready', () => {
|
||||
conn.exec(`node ${remoteScriptPath}`, (err, stream) => {
|
||||
let out = '';
|
||||
stream.on('data', d => out += d);
|
||||
stream.on('close', () => {
|
||||
console.log(out);
|
||||
conn.end();
|
||||
});
|
||||
});
|
||||
}).connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,69 +0,0 @@
|
||||
const SftpClient = require('ssh2-sftp-client');
|
||||
const { Client } = require('ssh2');
|
||||
|
||||
const remoteExtractScript = `
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const root = '/home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/.next/server';
|
||||
|
||||
console.log('=== EXTRACTING ALL PAGE HEADERS FROM STANDALONE BUILD ===\\n');
|
||||
|
||||
function scan(dir) {
|
||||
if (!fs.existsSync(dir)) return;
|
||||
const items = fs.readdirSync(dir, { withFileTypes: true });
|
||||
for (const item of items) {
|
||||
const full = path.join(dir, item.name);
|
||||
if (item.isDirectory()) {
|
||||
scan(full);
|
||||
} else if (item.name.endsWith('.js') || item.name.endsWith('.html')) {
|
||||
const content = fs.readFileSync(full, 'utf8');
|
||||
|
||||
// Look for H2/H1 page header titles or page metadata
|
||||
const matches = content.matchAll(/<h[12][^>]*>([\\s\\S]*?)<\\/h[12]>/gi);
|
||||
for (const m of matches) {
|
||||
const clean = m[1].replace(/<[^>]+>/g, '').trim();
|
||||
if (clean && clean.length > 2 && clean.length < 60 && !clean.includes('{') && !clean.includes('function')) {
|
||||
console.log(\`File: \${path.relative(root, full)}\`);
|
||||
console.log(\` Header: "\${clean}"\`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scan(path.join(root, 'app/(dashboard)'));
|
||||
`;
|
||||
|
||||
async function main() {
|
||||
const sftp = new SftpClient();
|
||||
await sftp.connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
|
||||
const remoteScriptPath = '/home/adminbackend/extract_standalone.js';
|
||||
await sftp.put(Buffer.from(remoteExtractScript), remoteScriptPath);
|
||||
await sftp.end();
|
||||
|
||||
const conn = new Client();
|
||||
conn.on('ready', () => {
|
||||
conn.exec(`node ${remoteScriptPath}`, (err, stream) => {
|
||||
let out = '';
|
||||
stream.on('data', d => out += d);
|
||||
stream.on('close', () => {
|
||||
console.log(out);
|
||||
conn.end();
|
||||
});
|
||||
});
|
||||
}).connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,121 +0,0 @@
|
||||
// scripts/final-check.js
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// BackOne DPI — Final production health check
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
'use strict';
|
||||
|
||||
const { Client: SshClient } = require('ssh2');
|
||||
const https = require('https');
|
||||
const http = require('http');
|
||||
|
||||
const CONFIG = {
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH',
|
||||
};
|
||||
|
||||
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
|
||||
const ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
|
||||
function fetch(url, followRedirects = false) {
|
||||
return new Promise(resolve => {
|
||||
const mod = url.startsWith('https') ? https : http;
|
||||
const opts = { timeout: 12000, rejectUnauthorized: false };
|
||||
if (!followRedirects) opts.agent = false;
|
||||
const req = mod.get(url, opts, res => {
|
||||
let body = '';
|
||||
res.on('data', d => body += d);
|
||||
res.on('end', () => resolve({ status: res.statusCode, headers: res.headers, body: body.substring(0, 300) }));
|
||||
});
|
||||
req.on('error', e => resolve({ status: 0, error: e.message }));
|
||||
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
|
||||
});
|
||||
}
|
||||
|
||||
function runSsh(commands) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const ssh = new SshClient();
|
||||
ssh.on('ready', () => {
|
||||
let i = 0;
|
||||
function next() {
|
||||
if (i >= commands.length) { ssh.end(); return; }
|
||||
const cmd = commands[i++];
|
||||
console.log(`\n$ ${cmd}`);
|
||||
ssh.exec(cmd, (err, stream) => {
|
||||
if (err) { console.error('[ERR]', err.message); next(); return; }
|
||||
stream.on('data', d => process.stdout.write(d.toString()));
|
||||
stream.stderr.on('data', d => { const t = d.toString(); if (!t.includes('npm warn') && !t.includes('notice')) process.stdout.write(t); });
|
||||
stream.on('close', next);
|
||||
});
|
||||
}
|
||||
next();
|
||||
ssh.on('end', resolve);
|
||||
});
|
||||
ssh.on('error', reject);
|
||||
ssh.connect({ ...CONFIG, readyTimeout: 30000 });
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('\n╔══════════════════════════════════════════════════════════════╗');
|
||||
console.log('║ BackOne DPI — Final Production Verification ║');
|
||||
console.log('╚══════════════════════════════════════════════════════════════╝\n');
|
||||
|
||||
// SSH internal checks
|
||||
await runSsh([
|
||||
`${PM2} list`,
|
||||
`echo "=== FRONTEND ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/`,
|
||||
`echo "=== LOGIN PAGE ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/login`,
|
||||
`echo "=== BACKEND ===" && curl -s http://127.0.0.1:3001/api/health`,
|
||||
// Test full login flow
|
||||
`echo "=== LOGIN API ===" && curl -s -X POST http://127.0.0.1:3001/api/auth/login -H "Content-Type: application/json" -d '{"username":"admin","password":"admin"}' | python3 -c "import sys,json; d=json.load(sys.stdin); print('Login OK - Role:', d.get('user',{}).get('role','?'))" 2>/dev/null || curl -s -X POST http://127.0.0.1:3001/api/auth/login -H "Content-Type: application/json" -d '{"username":"admin","password":"admin"}'`,
|
||||
// Security checks
|
||||
`echo "=== SECURITY: Port 3001 ===" && ss -tlnp | grep 3001`,
|
||||
`echo "=== SECURITY: Port 4000 ===" && ss -tlnp | grep 4000`,
|
||||
`echo "=== SECURITY: No .env in standalone ===" && find ${ROOT}/.next/standalone -name ".env*" 2>/dev/null || echo "CLEAN"`,
|
||||
// Proxy MongoDB
|
||||
`echo "=== PROXY MONGO ===" && ${PM2} logs backone-proxy --lines 5 --nostream 2>&1 | grep -E "(MongoDB|Scheduler|Connected|Capacity)" | tail -5`,
|
||||
// Domain via HTTP (should 301 → HTTPS)
|
||||
`echo "=== DOMAIN HTTP ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://demoplace.my.id/`,
|
||||
// Domain via HTTPS from server itself
|
||||
`echo "=== DOMAIN HTTPS ===" && curl -sk -o /dev/null -w "HTTP %{http_code}" https://demoplace.my.id/ 2>&1`,
|
||||
]);
|
||||
|
||||
// External checks from local machine
|
||||
console.log('\n\n══ External checks from local machine ══\n');
|
||||
|
||||
const tests = [
|
||||
{ url: 'https://demoplace.my.id/', label: 'Root (expect 307 redirect to /login)' },
|
||||
{ url: 'https://demoplace.my.id/login', label: 'Login page (expect 200)' },
|
||||
{ url: 'https://demoplace.my.id/api/health', label: 'Backend health via domain (expect 200)' },
|
||||
{ url: 'http://demoplace.my.id/', label: 'HTTP root (expect 301 HTTPS redirect)' },
|
||||
];
|
||||
|
||||
for (const { url, label } of tests) {
|
||||
const r = await fetch(url);
|
||||
const ok = r.status >= 200 && r.status < 400;
|
||||
const icon = ok ? '✅' : r.status === 0 ? '⚠️ ' : '❌';
|
||||
console.log(` ${icon} [${String(r.status).padEnd(3)}] ${label}`);
|
||||
if (r.headers?.location) console.log(` → Redirect: ${r.headers.location}`);
|
||||
if (r.error) console.log(` → Error: ${r.error}`);
|
||||
if (r.status === 200 && r.body) {
|
||||
const preview = r.body.replace(/\s+/g, ' ').substring(0, 80);
|
||||
console.log(` → Body: ${preview}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n══════════════════════════════════════════════════════════════');
|
||||
console.log(' Deployment Summary:');
|
||||
console.log(' ┌─────────────────────────────────────────────────────┐');
|
||||
console.log(' │ 🌐 Dashboard URL : https://demoplace.my.id │');
|
||||
console.log(' │ 🔒 Backend : 127.0.0.1:3001 (internal only) │');
|
||||
console.log(' │ 🔒 Proxy : 127.0.0.1:4000 (internal only) │');
|
||||
console.log(' │ 🗄️ MongoDB : mongodb.prod.proit.id:27017 │');
|
||||
console.log(' │ 🚀 Node.js : v18.19.1 │');
|
||||
console.log(' │ ⚙️ PM2 : 3 processes (all online) │');
|
||||
console.log(' └─────────────────────────────────────────────────────┘');
|
||||
console.log('══════════════════════════════════════════════════════════\n');
|
||||
}
|
||||
|
||||
main().catch(err => { console.error('[FATAL]', err); process.exit(1); });
|
||||
@@ -1,53 +0,0 @@
|
||||
// scripts/find-chunks.js
|
||||
// Cari di mana file chunks yang benar berada di server
|
||||
'use strict';
|
||||
const { Client } = require('ssh2');
|
||||
const conn = new Client();
|
||||
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
|
||||
function exec(conn, cmd) {
|
||||
console.log('\n$ ' + cmd.substring(0, 80));
|
||||
return new Promise(resolve => {
|
||||
conn.exec(cmd, (err, s) => {
|
||||
if (err) { resolve(''); return; }
|
||||
let out = '';
|
||||
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.on('close', () => resolve(out));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
conn.on('ready', async () => {
|
||||
// 1. Cari file chunk yang direferensikan HTML
|
||||
await exec(conn, 'find ' + PUB + ' -name "3km6z-n6wbgrs.js" 2>/dev/null | head -5');
|
||||
await exec(conn, 'find ' + PUB + ' -name "21luguo5_g2uu.js" 2>/dev/null | head -5');
|
||||
await exec(conn, 'find ' + PUB + ' -name "1u6dw_tm45utz.css" 2>/dev/null | head -5');
|
||||
|
||||
// 2. Cek isi static/static di standalone
|
||||
const sa = PUB + '/.next/standalone/.next/static/static';
|
||||
await exec(conn, 'ls ' + sa + '/ 2>/dev/null | head -10 || echo "Tidak ada nested static"');
|
||||
|
||||
// 3. Cek BUILD_ID utama
|
||||
await exec(conn, 'cat ' + PUB + '/.next/BUILD_ID 2>/dev/null || echo "NO_BUILDID"');
|
||||
|
||||
// 4. Cek build-manifest.json untuk lihat chunk names
|
||||
await exec(conn, 'cat ' + PUB + '/.next/standalone/.next/build-manifest.json 2>/dev/null | python3 -m json.tool 2>/dev/null | grep -A2 "login" | head -20');
|
||||
|
||||
// 5. Cek app-path-routes-manifest
|
||||
await exec(conn, 'cat ' + PUB + '/.next/standalone/.next/app-path-routes-manifest.json 2>/dev/null | head -20');
|
||||
|
||||
// 6. Cek apakah ada next.js build di parent directory
|
||||
await exec(conn, 'find /home/adminbackend -name "3km6z-n6wbgrs.js" 2>/dev/null | head -5');
|
||||
|
||||
// 7. Cek total disk structure
|
||||
await exec(conn, 'du -sh ' + PUB + '/.next/standalone/.next/ 2>/dev/null');
|
||||
await exec(conn, 'du -sh ' + PUB + '/.next/ 2>/dev/null | head -5');
|
||||
|
||||
conn.end();
|
||||
console.log('\nDone.');
|
||||
}).connect({
|
||||
host: '103.185.47.52', port: 2222,
|
||||
username: 'adminbackend', password: 'htEo7x6LsBQiEHHH',
|
||||
readyTimeout: 30000
|
||||
});
|
||||
@@ -1,18 +0,0 @@
|
||||
const { Client } = require('ssh2');
|
||||
|
||||
const conn = new Client();
|
||||
conn.on('ready', () => {
|
||||
conn.exec(`find /home/adminbackend/ -name "*.ts" -o -name "*.tsx" -o -name "*.js" | xargs grep -l "Overview Dashboard" 2>/dev/null`, (err, stream) => {
|
||||
let out = '';
|
||||
stream.on('data', d => out += d);
|
||||
stream.on('close', () => {
|
||||
console.log('=== FILES CONTAINING Overview Dashboard ===\n' + out);
|
||||
conn.end();
|
||||
});
|
||||
});
|
||||
}).connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
@@ -1,131 +0,0 @@
|
||||
// scripts/fix-and-restart.js
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// BackOne DPI — Fix standalone structure & reload PM2 with new code
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
'use strict';
|
||||
|
||||
const { Client: SshClient } = require('ssh2');
|
||||
|
||||
const CONFIG = {
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH',
|
||||
};
|
||||
|
||||
const ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
|
||||
|
||||
const COMMANDS = [
|
||||
// ── Step 1: Fix the standalone directory structure ──────────────────────────
|
||||
// Next.js standalone server.js expects .next/static and public INSIDE the standalone dir
|
||||
`echo "=== STEP 1: Create standalone .next dir ==="`,
|
||||
`mkdir -p ${ROOT}/.next/standalone/.next/`,
|
||||
|
||||
// Copy static chunks into standalone/.next/static
|
||||
`echo "=== STEP 2: Copy static assets into standalone ===" && cp -r ${ROOT}/.next/static ${ROOT}/.next/standalone/.next/static && echo "static copied OK"`,
|
||||
|
||||
// Copy media files
|
||||
`ls ${ROOT}/.next/standalone/.next/static/ 2>/dev/null | wc -l | xargs -I{} echo "Files in standalone static: {}"`,
|
||||
|
||||
// public is already copied in deploy script, verify it
|
||||
`ls ${ROOT}/.next/standalone/public/ 2>/dev/null | head -5 || echo "WARNING: public dir missing in standalone"`,
|
||||
|
||||
// ── Step 2: Verify the ecosystem.config.js was updated ────────────────────
|
||||
`echo "=== STEP 3: Show ecosystem.config.js script path ===" && grep "script" ${ROOT}/ecosystem.config.js | head -5`,
|
||||
|
||||
// ── Step 3: Reload PM2 with new ecosystem config ──────────────────────────
|
||||
// Use reload instead of restart to minimize downtime
|
||||
`echo "=== STEP 4: Reload PM2 frontend with new code ===" && cd ${ROOT} && NODE_ENV=production ${PM2} reload ecosystem.config.js --only backone-frontend 2>&1`,
|
||||
|
||||
// Also reload backend to pick up new code
|
||||
`echo "=== STEP 5: Reload PM2 backend ===" && cd ${ROOT} && NODE_ENV=production ${PM2} reload ecosystem.config.js --only backone-backend 2>&1`,
|
||||
|
||||
// Reload proxy as well (it was already restarted but ensure env is correct)
|
||||
`echo "=== STEP 6: Reload PM2 proxy ===" && cd ${ROOT} && NODE_ENV=production ${PM2} reload ecosystem.config.js --only backone-proxy 2>&1`,
|
||||
|
||||
// ── Step 4: Save PM2 state for auto-restart on reboot ─────────────────────
|
||||
`echo "=== STEP 7: Save PM2 state ===" && ${PM2} save && echo "PM2 state saved"`,
|
||||
|
||||
// ── Step 5: Wait for processes to stabilize ────────────────────────────────
|
||||
`sleep 8`,
|
||||
|
||||
// ── Step 6: Verify all processes ──────────────────────────────────────────
|
||||
`echo "=== STEP 8: PM2 Status ===" && ${PM2} list`,
|
||||
|
||||
// ── Step 7: Health checks ─────────────────────────────────────────────────
|
||||
`echo "=== BACKEND HEALTH ===" && curl -s http://127.0.0.1:3001/api/health`,
|
||||
`echo ""`,
|
||||
`echo "=== FRONTEND HTTP STATUS ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/ && echo ""`,
|
||||
`echo "=== FRONTEND LOGIN PAGE ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/login && echo ""`,
|
||||
|
||||
// ── Step 8: Check port 3000 is now listening ──────────────────────────────
|
||||
`echo "=== PORT 3000 STATUS ===" && ss -tlnp 2>/dev/null | grep 3000 || netstat -tlnp 2>/dev/null | grep 3000 || echo "Port 3000 check done"`,
|
||||
|
||||
// ── Step 9: Show frontend logs ────────────────────────────────────────────
|
||||
`echo "=== FRONTEND PM2 LOG (last 20 lines) ===" && ${PM2} logs backone-frontend --lines 20 --nostream 2>&1 | tail -25`,
|
||||
|
||||
// ── Step 10: Show proxy MongoDB connection status ─────────────────────────
|
||||
`echo "=== PROXY LOG (last 15 lines) ===" && ${PM2} logs backone-proxy --lines 15 --nostream 2>&1 | tail -20`,
|
||||
];
|
||||
|
||||
function runSshCommands(commands) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const ssh = new SshClient();
|
||||
|
||||
ssh.on('ready', () => {
|
||||
console.log('[SSH] Connected!\n');
|
||||
let index = 0;
|
||||
|
||||
function runNext() {
|
||||
if (index >= commands.length) {
|
||||
ssh.end();
|
||||
return;
|
||||
}
|
||||
|
||||
const cmd = commands[index++];
|
||||
const preview = cmd.length > 150 ? cmd.substring(0, 150) + '...' : cmd;
|
||||
console.log(`\n$ ${preview}`);
|
||||
|
||||
ssh.exec(cmd, (err, stream) => {
|
||||
if (err) {
|
||||
console.error(`[ERROR] ${err.message}`);
|
||||
runNext();
|
||||
return;
|
||||
}
|
||||
|
||||
stream.on('data', (data) => process.stdout.write(data.toString()));
|
||||
stream.stderr.on('data', (data) => {
|
||||
const text = data.toString();
|
||||
if (!text.includes('npm warn') && !text.includes('npm notice')) {
|
||||
process.stdout.write(`[ERR] ${text}`);
|
||||
}
|
||||
});
|
||||
stream.on('close', () => runNext());
|
||||
});
|
||||
}
|
||||
|
||||
runNext();
|
||||
ssh.on('end', resolve);
|
||||
});
|
||||
|
||||
ssh.on('error', reject);
|
||||
ssh.connect({ ...CONFIG, readyTimeout: 30000 });
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
||||
console.log('║ BackOne DPI — Fix Standalone & Reload PM2 ║');
|
||||
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
||||
|
||||
try {
|
||||
await runSshCommands(COMMANDS);
|
||||
console.log('\n✅ Fix & reload complete!\n');
|
||||
} catch (err) {
|
||||
console.error('\n[FATAL]', err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,120 +0,0 @@
|
||||
// scripts/fix-apache-ssl.js
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// BackOne DPI — Fix Apache HTTPS 502 Bad Gateway
|
||||
// The SSL VirtualHost needs mod_proxy configuration.
|
||||
// cPanel uses Apache with .htaccess for proxy rules, but SSL VirtualHost
|
||||
// may need specific directives to enable mod_proxy_http for the [P] flag.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
'use strict';
|
||||
|
||||
const { Client: SshClient } = require('ssh2');
|
||||
|
||||
const CONFIG = {
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH',
|
||||
};
|
||||
|
||||
const ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
|
||||
|
||||
const COMMANDS = [
|
||||
// Investigate Apache config for SSL
|
||||
`echo "=== APACHE MODULES ===" && apache2ctl -M 2>/dev/null | grep -i proxy | head -10 || httpd -M 2>/dev/null | grep -i proxy | head -10 || echo "Cannot check Apache modules"`,
|
||||
|
||||
// Check what's actually at the SSL port - is it Apache or Nginx or something else?
|
||||
`echo "=== SSL PORT OWNER ===" && ss -tlnp | grep 443`,
|
||||
|
||||
// Check SSL log for 502 cause
|
||||
`echo "=== SSL ACCESS LOG (last 10 502s) ===" && tail -50 /home/adminbackend/logs/demoplace.my.id-ssl_log 2>/dev/null | grep "502" | tail -10 || echo "No SSL log or no 502s in log"`,
|
||||
`echo "=== SSL ERROR LOG (last 15) ===" && tail -15 /home/adminbackend/logs/demoplace.my.id-ssl_log 2>/dev/null || echo "No SSL log found"`,
|
||||
|
||||
// Find all log files for this domain
|
||||
`echo "=== DOMAIN LOG FILES ===" && ls /home/adminbackend/logs/*demoplace* 2>/dev/null || echo "No domain-specific logs"`,
|
||||
|
||||
// Check Apache vhost config (cPanel stores them here)
|
||||
`echo "=== APACHE SSL VHOST ===" && cat /etc/apache2/conf.d/userdata/ssl/2_4/adminbackend/demoplace.my.id/custom_subdirectory.conf 2>/dev/null || ls /etc/apache2/conf.d/userdata/ssl/2_4/adminbackend/ 2>/dev/null || echo "Cannot read Apache vhost config"`,
|
||||
|
||||
// Check all .htaccess files in path
|
||||
`echo "=== ROOT HTACCESS ===" && cat ${ROOT}/.htaccess`,
|
||||
|
||||
// Check if mod_proxy is loaded
|
||||
`echo "=== MOD_PROXY CHECK ===" && test -f /etc/apache2/mods-enabled/proxy.load && echo "mod_proxy ENABLED" || echo "mod_proxy NOT enabled"`,
|
||||
`test -f /etc/apache2/mods-enabled/proxy_http.load && echo "mod_proxy_http ENABLED" || echo "mod_proxy_http NOT enabled"`,
|
||||
|
||||
// The issue may be cPanel's "nobody" user restriction
|
||||
// Try using ProxyPass in .htaccess with explicit ProxyPassReverse
|
||||
`echo "=== UPDATING .HTACCESS ===" && cat > ${ROOT}/.htaccess << 'EOF'
|
||||
Options -MultiViews
|
||||
RewriteEngine On
|
||||
|
||||
# Force HTTPS
|
||||
RewriteCond %{HTTPS} !=on
|
||||
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
|
||||
|
||||
# Proxy all requests to Next.js (port 3000)
|
||||
RewriteRule ^(.*)$ http://127.0.0.1:3000/$1 [P,L,QSA]
|
||||
ProxyPassReverse / http://127.0.0.1:3000/
|
||||
EOF
|
||||
echo ".htaccess updated"`,
|
||||
|
||||
// Read the new .htaccess to verify
|
||||
`echo "=== NEW HTACCESS ===" && cat ${ROOT}/.htaccess`,
|
||||
|
||||
// Wait a moment for Apache to pick up changes
|
||||
`sleep 2`,
|
||||
|
||||
// Test from server itself via HTTPS
|
||||
`echo "=== HTTPS TEST FROM SERVER ===" && curl -sk -o /dev/null -w "HTTP %{http_code}" https://demoplace.my.id/ 2>&1`,
|
||||
`echo "=== HTTPS LOGIN FROM SERVER ===" && curl -sk -o /dev/null -w "HTTP %{http_code}" https://demoplace.my.id/login 2>&1`,
|
||||
|
||||
// Check if it's a proxy timeout issue - try with verbose curl
|
||||
`echo "=== VERBOSE HTTPS TEST ===" && curl -skv https://demoplace.my.id/ 2>&1 | grep -E "(<|>|\\*) " | head -20`,
|
||||
|
||||
// Alternative: check if cPanel has a NodeJS app manager entry interfering
|
||||
`echo "=== CPANEL USERDATA ===" && ls /home/adminbackend/.cpanel/userdata/ 2>/dev/null`,
|
||||
`cat /home/adminbackend/.cpanel/userdata/demoplace.my.id_SSL 2>/dev/null | head -30 || echo "No cPanel userdata for SSL"`,
|
||||
`cat /home/adminbackend/.cpanel/userdata/demoplace.my.id 2>/dev/null | head -30 || echo "No cPanel userdata"`,
|
||||
|
||||
// Check Apache logs specifically for proxy errors
|
||||
`echo "=== APACHE ERROR LOG ===" && tail -20 /var/log/apache2/error.log 2>/dev/null | grep -i "demoplace\|proxy\|502" | head -10 || echo "Cannot read Apache error log"`,
|
||||
|
||||
// PM2 processes still healthy?
|
||||
`echo "=== PM2 STATUS ===" && ${PM2} list`,
|
||||
`echo "=== FRONTEND HEALTH ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/login`,
|
||||
];
|
||||
|
||||
function runSsh(commands) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const ssh = new SshClient();
|
||||
ssh.on('ready', () => {
|
||||
let i = 0;
|
||||
function next() {
|
||||
if (i >= commands.length) { ssh.end(); return; }
|
||||
const cmd = commands[i++];
|
||||
console.log(`\n$ ${cmd.substring(0, 100)}${cmd.length > 100 ? '...' : ''}`);
|
||||
ssh.exec(cmd, (err, stream) => {
|
||||
if (err) { console.error('[ERR]', err.message); next(); return; }
|
||||
stream.on('data', d => process.stdout.write(d.toString()));
|
||||
stream.stderr.on('data', d => { const t = d.toString(); if (!t.includes('npm warn') && !t.includes('notice')) process.stdout.write(t); });
|
||||
stream.on('close', next);
|
||||
});
|
||||
}
|
||||
next();
|
||||
ssh.on('end', resolve);
|
||||
});
|
||||
ssh.on('error', reject);
|
||||
ssh.connect({ ...CONFIG, readyTimeout: 30000 });
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
||||
console.log('║ BackOne DPI — Fix Apache HTTPS 502 Bad Gateway ║');
|
||||
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
||||
await runSsh(COMMANDS);
|
||||
console.log('\n✅ Apache SSL investigation complete!\n');
|
||||
}
|
||||
|
||||
main().catch(err => { console.error('[FATAL]', err); process.exit(1); });
|
||||
@@ -1,141 +0,0 @@
|
||||
// scripts/fix-css-and-security.js
|
||||
// 1. Fix CSS tidak termuat: buat symlink public_html/_next -> public_html/.next
|
||||
// 2. Security audit: hapus cmd.php dan file berbahaya lainnya
|
||||
'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 PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
|
||||
function sshExec(conn, cmd, label = '') {
|
||||
if (label) console.log(`\n[${label}]`);
|
||||
console.log(`$ ${cmd.substring(0, 100)}${cmd.length > 100 ? '...' : ''}`);
|
||||
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()); });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
||||
console.log('║ BackOne DPI — Fix CSS + Security Audit ║');
|
||||
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');
|
||||
|
||||
// ── 1. SECURITY AUDIT ─────────────────────────────────────────────────
|
||||
await sshExec(conn,
|
||||
`echo "=== FILE BERBAHAYA ===" && ls -la ${PUB}/*.php ${PUB}/*.sh 2>/dev/null || echo "Tidak ada .php/.sh di root"`,
|
||||
'1. Audit file PHP di public_html'
|
||||
);
|
||||
|
||||
// Hapus cmd.php jika ada (file backdoor berbahaya)
|
||||
await sshExec(conn,
|
||||
`[ -f ${PUB}/cmd.php ] && rm -f ${PUB}/cmd.php && echo "DIHAPUS: cmd.php" || echo "cmd.php tidak ada (aman)"`,
|
||||
'2. Hapus cmd.php (backdoor)'
|
||||
);
|
||||
|
||||
// Hapus proxy.php lama (tidak diperlukan lagi karena nginx routing langsung ke port 3000)
|
||||
await sshExec(conn,
|
||||
`[ -f ${PUB}/proxy.php ] && rm -f ${PUB}/proxy.php && echo "DIHAPUS: proxy.php (tidak diperlukan)" || echo "proxy.php tidak ada"`,
|
||||
'3. Hapus proxy.php (tidak dibutuhkan)'
|
||||
);
|
||||
|
||||
// ── 2. CEK STRUKTUR DIREKTORI ──────────────────────────────────────────
|
||||
await sshExec(conn,
|
||||
`echo "=== STRUKTUR public_html ===" && ls -la ${PUB}/ | head -30`,
|
||||
'4. Cek struktur public_html'
|
||||
);
|
||||
|
||||
await sshExec(conn,
|
||||
`echo "=== .next directory ===" && ls -la ${PUB}/.next/ 2>/dev/null | head -10 || echo "TIDAK ADA .next/"`,
|
||||
'5. Cek .next directory'
|
||||
);
|
||||
|
||||
await sshExec(conn,
|
||||
`echo "=== static assets ===" && ls -la ${PUB}/.next/static/ 2>/dev/null | head -10 || echo "Tidak ada .next/static/"`,
|
||||
'6. Cek .next/static'
|
||||
);
|
||||
|
||||
await sshExec(conn,
|
||||
`echo "=== _next symlink ===" && ls -la ${PUB}/_next 2>/dev/null || echo "Symlink _next belum ada"`,
|
||||
'7. Cek symlink _next'
|
||||
);
|
||||
|
||||
// ── 3. FIX CSS: Buat symlink _next → .next ────────────────────────────
|
||||
await sshExec(conn,
|
||||
`[ -e ${PUB}/_next ] && echo "Sudah ada _next" || (ln -s ${PUB}/.next ${PUB}/_next && echo "BERHASIL: Symlink _next → .next dibuat")`,
|
||||
'8. Buat symlink _next -> .next'
|
||||
);
|
||||
|
||||
// Verifikasi symlink
|
||||
await sshExec(conn,
|
||||
`ls -la ${PUB}/_next && ls ${PUB}/_next/static/ | head -5`,
|
||||
'9. Verifikasi symlink'
|
||||
);
|
||||
|
||||
// ── 4. PERBARUI .htaccess (bersih tanpa proxy.php) ────────────────────
|
||||
const cleanHtaccess = `# BackOne DPI — Apache .htaccess
|
||||
# Redirect HTTP ke HTTPS saja
|
||||
RewriteEngine On
|
||||
RewriteCond %{HTTPS} !=on
|
||||
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
|
||||
`;
|
||||
|
||||
await sshExec(conn,
|
||||
`printf '%s' ${JSON.stringify(cleanHtaccess)} > ${PUB}/.htaccess && echo "BERHASIL: .htaccess diperbarui"`,
|
||||
'10. Perbarui .htaccess (hanya redirect HTTPS)'
|
||||
);
|
||||
|
||||
// ── 5. TEST CSS LOADING ─────────────────────────────────────────────────
|
||||
console.log('\n[11. Test loading CSS dari /_next/static/]');
|
||||
await sshExec(conn,
|
||||
`CSS_FILE=$(ls ${PUB}/.next/static/css/*.css 2>/dev/null | head -1) && ` +
|
||||
`[ -n "$CSS_FILE" ] && ` +
|
||||
`FILENAME=$(basename "$CSS_FILE") && ` +
|
||||
`curl -sk -o /dev/null -w "CSS via domain: %{http_code} (size: %{size_download} bytes)" https://demoplace.my.id/_next/static/css/$FILENAME || ` +
|
||||
`echo "Tidak ada file CSS ditemukan"`,
|
||||
'11. Test CSS via domain'
|
||||
);
|
||||
|
||||
conn.end();
|
||||
|
||||
// ── Test dari luar ──────────────────────────────────────────────────────
|
||||
console.log('\n[12. Test domain setelah fix...]');
|
||||
await new Promise(r => setTimeout(r, 2000));
|
||||
|
||||
for (const path of ['/login', '/api/health']) {
|
||||
const r = await new Promise(resolve => {
|
||||
const req = https.get(`https://demoplace.my.id${path}`,
|
||||
{ timeout: 10000, rejectUnauthorized: false },
|
||||
res => {
|
||||
let body = '';
|
||||
res.on('data', d => body += d);
|
||||
res.on('end', () => resolve({ status: res.statusCode, body: body.substring(0, 100) }));
|
||||
}
|
||||
);
|
||||
req.on('error', e => resolve({ status: 0, error: e.message }));
|
||||
});
|
||||
const icon = r.status === 200 ? '✅' : r.status === 301 ? '↩️ ' : '❌';
|
||||
console.log(` ${icon} https://demoplace.my.id${path} → HTTP ${r.status}`);
|
||||
if (path === '/api/health') console.log(` Body: ${r.body}`);
|
||||
}
|
||||
|
||||
console.log('\n✅ Fix selesai! Coba refresh https://demoplace.my.id/login\n');
|
||||
}
|
||||
|
||||
main().catch(err => { console.error('[FATAL]', err.message); process.exit(1); });
|
||||
@@ -1,175 +0,0 @@
|
||||
// scripts/fix-env-loader.js
|
||||
// Fix: Buat Node.js env loader yang aman (tanpa bash glob expansion)
|
||||
'use strict';
|
||||
const { Client } = require('ssh2');
|
||||
|
||||
const SSH = { host: '103.185.47.52', port: 2222, username: 'adminbackend', password: 'htEo7x6LsBQiEHHH', readyTimeout: 60000 };
|
||||
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
|
||||
|
||||
function exec(conn, cmd, label) {
|
||||
if (label) console.log('\n[' + label + ']');
|
||||
console.log('$ ' + cmd.substring(0, 90));
|
||||
return new Promise(resolve => {
|
||||
conn.exec(cmd, (err, s) => {
|
||||
if (err) { resolve(''); return; }
|
||||
let out = '';
|
||||
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.on('close', () => resolve(out));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Konten start-with-env.js yang akan ditulis ke server
|
||||
const startWithEnvContent = `'use strict';
|
||||
// Polyfill global crypto for Node 18 compatibility (required by mongodb driver)
|
||||
if (typeof globalThis.crypto === 'undefined') {
|
||||
globalThis.crypto = require('crypto');
|
||||
}
|
||||
/**
|
||||
* BackOne DPI - Safe Environment Loader for Next.js Standalone
|
||||
* Reads .env.production safely without bash glob expansion issues.
|
||||
*/
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const envFile = path.join(__dirname, '.env.production');
|
||||
|
||||
if (fs.existsSync(envFile)) {
|
||||
const lines = fs.readFileSync(envFile, 'utf8').split(/\\r?\\n/);
|
||||
let loaded = 0;
|
||||
for (const raw of lines) {
|
||||
const line = raw.trim();
|
||||
// Skip comments and empty lines
|
||||
if (!line || line.startsWith('#')) continue;
|
||||
const eqIdx = line.indexOf('=');
|
||||
if (eqIdx === -1) continue;
|
||||
const key = line.substring(0, eqIdx).trim();
|
||||
// Only accept valid environment variable names
|
||||
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) continue;
|
||||
const val = line.substring(eqIdx + 1); // Do NOT trim value - preserve exact content
|
||||
if (!(key in process.env)) {
|
||||
process.env[key] = val;
|
||||
loaded++;
|
||||
}
|
||||
}
|
||||
console.log('[startup] Loaded ' + loaded + ' environment variables from .env.production');
|
||||
console.log('[startup] NETIFY_API_KEY set:', !!process.env.NETIFY_API_KEY);
|
||||
console.log('[startup] MONGODB_URI set: ', !!process.env.MONGODB_URI);
|
||||
} else {
|
||||
console.warn('[startup] WARNING: .env.production not found at:', envFile);
|
||||
}
|
||||
|
||||
// Start Next.js standalone server
|
||||
require('./.next/standalone/server.js');
|
||||
`;
|
||||
|
||||
async function main() {
|
||||
const conn = new Client();
|
||||
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(SSH); });
|
||||
console.log('[SSH] Connected\n');
|
||||
|
||||
// 1. Upload start-with-env.js ke server
|
||||
await exec(conn,
|
||||
'cat > ' + PUB + '/start-with-env.js << \'NODELOADER_EOF\'\n' + startWithEnvContent + '\nNODELOADER_EOF\n' +
|
||||
'echo "Node.js loader dibuat"',
|
||||
'1. Buat start-with-env.js'
|
||||
);
|
||||
await exec(conn, 'wc -l ' + PUB + '/start-with-env.js', '2. Verifikasi file');
|
||||
|
||||
// 2. Update ecosystem.config.js untuk gunakan Node.js loader (bukan bash wrapper)
|
||||
const ecoContent = `// ecosystem.config.js — PM2 Config (server-side)
|
||||
module.exports = {
|
||||
apps: [
|
||||
{
|
||||
name: 'backone-proxy',
|
||||
script: './proxy/index.js',
|
||||
cwd: '${PUB}',
|
||||
instances: 1,
|
||||
exec_mode: 'fork',
|
||||
watch: false,
|
||||
node_args: '--max-old-space-size=256',
|
||||
max_memory_restart: '300M',
|
||||
restart_delay: 5000,
|
||||
max_restarts: 10,
|
||||
env_file: '.env.production',
|
||||
env: { NODE_ENV: 'production' },
|
||||
error_file: './logs/proxy-error.log',
|
||||
out_file: './logs/proxy-out.log',
|
||||
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
|
||||
merge_logs: true,
|
||||
},
|
||||
{
|
||||
name: 'backone-backend',
|
||||
script: './backend/server.js',
|
||||
cwd: '${PUB}',
|
||||
instances: 1,
|
||||
exec_mode: 'fork',
|
||||
watch: false,
|
||||
node_args: '--max-old-space-size=256',
|
||||
max_memory_restart: '400M',
|
||||
restart_delay: 3000,
|
||||
max_restarts: 10,
|
||||
env_file: '.env.production',
|
||||
env: { NODE_ENV: 'production' },
|
||||
error_file: './logs/backend-error.log',
|
||||
out_file: './logs/backend-out.log',
|
||||
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
|
||||
merge_logs: true,
|
||||
},
|
||||
{
|
||||
name: 'backone-frontend',
|
||||
script: './start-with-env.js',
|
||||
cwd: '${PUB}',
|
||||
instances: 1,
|
||||
exec_mode: 'fork',
|
||||
watch: false,
|
||||
node_args: '--max-old-space-size=512',
|
||||
max_memory_restart: '700M',
|
||||
restart_delay: 3000,
|
||||
max_restarts: 10,
|
||||
env: {
|
||||
NODE_ENV: 'production',
|
||||
PORT: '3000',
|
||||
HOSTNAME: '127.0.0.1',
|
||||
NEXT_TELEMETRY_DISABLED: '1',
|
||||
},
|
||||
error_file: './logs/frontend-error.log',
|
||||
out_file: './logs/frontend-out.log',
|
||||
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
|
||||
merge_logs: true,
|
||||
},
|
||||
],
|
||||
};`;
|
||||
|
||||
await exec(conn,
|
||||
'cat > ' + PUB + '/ecosystem.config.js << \'ECO_EOF\'\n' + ecoContent + '\nECO_EOF\necho "ecosystem.config.js diperbarui"',
|
||||
'3. Update ecosystem.config.js'
|
||||
);
|
||||
|
||||
// 3. Delete & restart frontend
|
||||
await exec(conn,
|
||||
'cd ' + PUB + ' && ' + PM2 + ' delete backone-frontend 2>/dev/null; ' +
|
||||
PM2 + ' start ecosystem.config.js --only backone-frontend && echo "START OK"',
|
||||
'4. Restart frontend dengan Node.js loader'
|
||||
);
|
||||
|
||||
// 4. Tunggu startup
|
||||
await new Promise(r => setTimeout(r, 8000));
|
||||
|
||||
// 5. Cek out log (harus tampil "Loaded X environment variables")
|
||||
await exec(conn, 'tail -10 ' + PUB + '/logs/frontend-out.log 2>/dev/null', '5. Out log (env loader output)');
|
||||
await exec(conn, 'tail -5 ' + PUB + '/logs/frontend-error.log 2>/dev/null', '6. Error log terbaru');
|
||||
|
||||
// 6. Test agents
|
||||
await exec(conn, 'curl -sk -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/agents', '7. Test /agents page');
|
||||
|
||||
// 7. PM2 status
|
||||
await exec(conn, PM2 + ' list 2>/dev/null | grep backone', '8. PM2 status');
|
||||
|
||||
conn.end();
|
||||
console.log('\n✅ Selesai!\n');
|
||||
}
|
||||
|
||||
main().catch(e => console.error('[FATAL]', e.message));
|
||||
@@ -1,78 +0,0 @@
|
||||
// scripts/fix-env-vars.js
|
||||
// Fix: Pastikan environment variables dari .env.production dimuat oleh PM2 frontend
|
||||
'use strict';
|
||||
const { Client } = require('ssh2');
|
||||
|
||||
const SSH = { host: '103.185.47.52', port: 2222, username: 'adminbackend', password: 'htEo7x6LsBQiEHHH', readyTimeout: 60000 };
|
||||
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
|
||||
|
||||
function exec(conn, cmd, label) {
|
||||
if (label) console.log('\n[' + label + ']');
|
||||
console.log('$ ' + cmd.substring(0, 90));
|
||||
return new Promise(resolve => {
|
||||
conn.exec(cmd, (err, s) => {
|
||||
if (err) { resolve(''); return; }
|
||||
let out = '';
|
||||
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.on('close', () => resolve(out));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const conn = new Client();
|
||||
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(SSH); });
|
||||
console.log('[SSH] Connected\n');
|
||||
|
||||
// 1. Cek env vars yang diterima proses PM2 sekarang
|
||||
await exec(conn, PM2 + ' env 3 2>/dev/null | grep -E "(NETIFY|BACKONE|MONGO|JWT)" | head -15', '1. Env vars di PM2 proses 3 (frontend)');
|
||||
|
||||
// 2. Cek isi .env.production
|
||||
await exec(conn, 'cat ' + PUB + '/.env.production 2>/dev/null | grep -v "#" | grep -v "^$" | head -30', '2. Isi .env.production (non-comment)');
|
||||
|
||||
// 3. Export vars dari .env.production dan restart dengan env vars eksplisit
|
||||
// Baca .env.production, parse, dan set ke PM2
|
||||
const envScript = `
|
||||
set -a
|
||||
source ${PUB}/.env.production 2>/dev/null
|
||||
set +a
|
||||
export NETIFY_API_KEY="$NETIFY_API_KEY"
|
||||
export NETIFY_ORG_UUID="$NETIFY_ORG_UUID"
|
||||
export NETIFY_SITE_UUIDS="$NETIFY_SITE_UUIDS"
|
||||
export NETIFY_INFORMATICS_BASE_URL="$NETIFY_INFORMATICS_BASE_URL"
|
||||
export MONGODB_URI="$MONGODB_URI"
|
||||
export JWT_SECRET="$JWT_SECRET"
|
||||
export NEXT_PUBLIC_API_URL="$NEXT_PUBLIC_API_URL"
|
||||
echo "API_KEY=$NETIFY_API_KEY"
|
||||
echo "MONGO_URI_PARTIAL=$(echo $MONGODB_URI | cut -c1-30)..."
|
||||
`.trim();
|
||||
await exec(conn, 'bash -c \'' + envScript.replace(/\n/g, '; ') + '\'', '3. Verifikasi env vars bisa dibaca dari .env.production');
|
||||
|
||||
// 4. Delete dan restart PM2 proses dengan ecosystem file yang membaca env_file
|
||||
await exec(conn,
|
||||
'cd ' + PUB + ' && ' + PM2 + ' delete backone-frontend 2>/dev/null; ' +
|
||||
PM2 + ' start ecosystem.config.js --only backone-frontend --env production && echo "START OK"',
|
||||
'4. Restart frontend via ecosystem.config.js'
|
||||
);
|
||||
|
||||
// 5. Verifikasi env vars sekarang dimuat
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
await exec(conn, PM2 + ' env 3 2>/dev/null | grep -E "(NETIFY|BACKONE|MONGO)" | head -10', '5. Verifikasi env vars setelah restart');
|
||||
|
||||
// 6. Test agents page
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
await exec(conn, 'curl -sk -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/agents', '6. Test /agents');
|
||||
|
||||
// 7. Cek error log terbaru
|
||||
await exec(conn, 'tail -5 ' + PUB + '/logs/frontend-error.log 2>/dev/null', '7. Error log terbaru');
|
||||
|
||||
// 8. PM2 status akhir
|
||||
await exec(conn, PM2 + ' list 2>/dev/null | grep backone', '8. PM2 status akhir');
|
||||
|
||||
conn.end();
|
||||
console.log('\n✅ Selesai!\n');
|
||||
}
|
||||
|
||||
main().catch(e => console.error('[FATAL]', e.message));
|
||||
@@ -1,110 +0,0 @@
|
||||
// scripts/fix-https.js
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// BackOne DPI — Fix HTTPS 502 Bad Gateway Issue
|
||||
// The cPanel Apache proxy is getting 502 — need to investigate and fix
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
'use strict';
|
||||
|
||||
const { Client: SshClient } = require('ssh2');
|
||||
|
||||
const CONFIG = {
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH',
|
||||
};
|
||||
|
||||
const ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
|
||||
|
||||
const COMMANDS = [
|
||||
// Check current frontend status
|
||||
`echo "=== FRONTEND PROCESS ==="`,
|
||||
`ps aux | grep node | grep -v grep`,
|
||||
`ss -tlnp | grep 3000`,
|
||||
|
||||
// Check if frontend is responding internally
|
||||
`echo "=== INTERNAL FRONTEND TEST ===" && curl -sv http://127.0.0.1:3000/ 2>&1 | grep -E "(< HTTP|< Location|Connected|curl)" | head -10`,
|
||||
|
||||
// Check the .htaccess to confirm proxy setup
|
||||
`echo "=== .HTACCESS CONTENT ===" && cat ${ROOT}/.htaccess`,
|
||||
|
||||
// Check Apache error log for this domain
|
||||
`echo "=== APACHE ERROR (last 20 lines) ===" && tail -20 /home/adminbackend/logs/demoplace.my.id-ssl_log 2>/dev/null || tail -20 /home/adminbackend/logs/demoplace.my.id-error_log 2>/dev/null || tail -20 /home/adminbackend/logs/error_log 2>/dev/null || echo "No Apache error log found"`,
|
||||
|
||||
// Check all logs
|
||||
`echo "=== LOG FILES ===" && ls /home/adminbackend/logs/ 2>/dev/null | head -20`,
|
||||
|
||||
// Check domain SSL logs
|
||||
`echo "=== SSL LOG ===" && tail -30 /home/adminbackend/logs/demoplace.my.id-ssl_log 2>/dev/null | grep -E "(502|500|error|proxy)" | tail -15 || echo "No SSL log"`,
|
||||
|
||||
// Try the domain via HTTP (non-SSL)
|
||||
`echo "=== HTTP (non-SSL) TEST ===" && curl -sv http://demoplace.my.id/ 2>&1 | grep -E "(< HTTP|Location|Connected)" | head -5`,
|
||||
|
||||
// Check PM2 frontend is running
|
||||
`echo "=== PM2 FRONTEND STATUS ===" && ${PM2} show backone-frontend 2>&1 | grep -E "(status|pid|uptime|restart)" | head -10`,
|
||||
|
||||
// Check frontend log for errors
|
||||
`echo "=== FRONTEND LOG (errors) ===" && ${PM2} logs backone-frontend --lines 30 --nostream 2>&1 | grep -E "(Error|error|ECONNRESET|Ready|✓)" | tail -15`,
|
||||
|
||||
// Re-check port
|
||||
`echo "=== PORT 3000 DETAILED ===" && ss -tlnp | grep 3000`,
|
||||
|
||||
// Try direct curl to frontend with more verbose output
|
||||
`echo "=== DETAILED FRONTEND CURL ===" && curl -v http://127.0.0.1:3000/login 2>&1 | head -30`,
|
||||
|
||||
// Check if there's an issue with the standalone server path in PM2
|
||||
`echo "=== PM2 SCRIPT PATH ===" && ${PM2} show backone-frontend 2>&1 | grep -E "(script|cwd|exec)" | head -5`,
|
||||
|
||||
// Check node version
|
||||
`echo "=== NODE VERSION ===" && node --version`,
|
||||
|
||||
// Check if frontend started correctly after restart
|
||||
`echo "=== FRONTEND READY STATUS ===" && ${PM2} logs backone-frontend --lines 10 --nostream 2>&1 | tail -15`,
|
||||
|
||||
// Try restarting frontend
|
||||
`echo "=== RESTARTING FRONTEND ===" && ${PM2} restart backone-frontend && sleep 5 && echo "Restarted"`,
|
||||
|
||||
// Final port check
|
||||
`echo "=== FINAL PORT CHECK ===" && ss -tlnp | grep 3000`,
|
||||
`echo "=== FINAL CURL ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/login`,
|
||||
|
||||
// Check if maybe cPanel node app is conflicting
|
||||
`echo "=== CPANEL NODE APPS ===" && ls /home/adminbackend/nodevenv/ 2>/dev/null || echo "No cPanel Node.js virtual environments"`,
|
||||
`cat /home/adminbackend/.cpanel/nvdata/node_application_config 2>/dev/null | head -30 || echo "No cPanel Node config"`,
|
||||
];
|
||||
|
||||
function runSsh(commands) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const ssh = new SshClient();
|
||||
ssh.on('ready', () => {
|
||||
console.log('[SSH] Connected!\n');
|
||||
let i = 0;
|
||||
function next() {
|
||||
if (i >= commands.length) { ssh.end(); return; }
|
||||
const cmd = commands[i++];
|
||||
console.log(`\n$ ${cmd.substring(0, 130)}${cmd.length > 130 ? '...' : ''}`);
|
||||
ssh.exec(cmd, (err, stream) => {
|
||||
if (err) { console.error('[ERR]', err.message); next(); return; }
|
||||
stream.on('data', d => process.stdout.write(d.toString()));
|
||||
stream.stderr.on('data', d => { const t = d.toString(); if (!t.includes('npm warn') && !t.includes('notice')) process.stdout.write(t); });
|
||||
stream.on('close', next);
|
||||
});
|
||||
}
|
||||
next();
|
||||
ssh.on('end', resolve);
|
||||
});
|
||||
ssh.on('error', reject);
|
||||
ssh.connect({ ...CONFIG, readyTimeout: 30000 });
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
||||
console.log('║ BackOne DPI — HTTPS 502 Investigation & Fix ║');
|
||||
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
||||
await runSsh(COMMANDS);
|
||||
console.log('\n✅ Investigation complete!\n');
|
||||
}
|
||||
|
||||
main().catch(err => { console.error('[FATAL]', err); process.exit(1); });
|
||||
@@ -1,88 +0,0 @@
|
||||
// scripts/fix-missing-css.js
|
||||
'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 PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
const SA = PUB + '/.next/standalone/.next/static';
|
||||
const BP = '/home/adminbackend/backone-production/.next/static';
|
||||
|
||||
function exec(conn, cmd, label) {
|
||||
if (label) console.log('\n[' + label + ']');
|
||||
console.log('$ ' + cmd.substring(0, 80));
|
||||
return new Promise(resolve => {
|
||||
conn.exec(cmd, (err, s) => {
|
||||
if (err) { resolve(''); return; }
|
||||
let out = '';
|
||||
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.on('close', () => resolve(out));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function httpGet(url) {
|
||||
return new Promise(resolve => {
|
||||
const req = https.get(url, { timeout: 12000, rejectUnauthorized: false }, res => {
|
||||
let body = '';
|
||||
res.on('data', d => body += d);
|
||||
res.on('end', () => resolve({ status: res.statusCode, size: body.length, type: res.headers['content-type'] }));
|
||||
});
|
||||
req.on('error', e => resolve({ status: 0, error: e.message }));
|
||||
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const conn = new Client();
|
||||
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(SSH); });
|
||||
console.log('[SSH] Connected\n');
|
||||
|
||||
// 1. Cari file CSS yang hilang
|
||||
await exec(conn, 'find /home/adminbackend -name "1oskchnhjm4n8.css" 2>/dev/null | head -5', '1. Cari CSS hilang');
|
||||
|
||||
// 2. List CSS di backone-production
|
||||
await exec(conn, 'find ' + BP + ' -name "*.css" 2>/dev/null | head -10', '2. CSS di backone-production');
|
||||
|
||||
// 3. Full rsync chunks (paksa semua file)
|
||||
await exec(conn,
|
||||
'rsync -av ' + BP + '/chunks/ ' + SA + '/chunks/ 2>&1 | grep "css\\|sent\\|total" | head -10',
|
||||
'3. Full rsync chunks'
|
||||
);
|
||||
|
||||
// 4. Verifikasi CSS setelah rsync
|
||||
await exec(conn, 'find ' + SA + '/chunks -name "*.css" 2>/dev/null', '4. CSS di standalone setelah rsync');
|
||||
|
||||
// 5. Cek total file
|
||||
await exec(conn, 'ls ' + SA + '/chunks/ | wc -l', '5. Total file chunks');
|
||||
|
||||
conn.end();
|
||||
|
||||
// 6. Final test
|
||||
console.log('\n[6. Final test static files...]');
|
||||
await new Promise(r => setTimeout(r, 2000));
|
||||
const files = [
|
||||
'/_next/static/chunks/3km6z-n6wbgrs.js',
|
||||
'/_next/static/chunks/1u6dw_tm45utz.css',
|
||||
'/_next/static/chunks/1oskchnhjm4n8.css',
|
||||
'/_next/static/chunks/21luguo5_g2uu.js',
|
||||
'/_next/static/chunks/1-8s9_t85wwr4.js',
|
||||
'/_next/static/chunks/2n6j37owj-kaf.js',
|
||||
];
|
||||
let allOk = true;
|
||||
for (const f of files) {
|
||||
const r = await httpGet('https://demoplace.my.id' + f);
|
||||
const icon = r.status === 200 ? '✅' : '❌';
|
||||
const ext = f.endsWith('.css') ? 'CSS' : 'JS ';
|
||||
console.log(' ' + icon + ' [' + ext + '] HTTP ' + r.status + ' | ' + (r.size || 0) + ' bytes');
|
||||
if (r.status !== 200) { console.log(' → ' + f); allOk = false; }
|
||||
}
|
||||
if (allOk) {
|
||||
console.log('\n🎉 SEMUA CSS/JS BERHASIL! Lakukan hard refresh (Ctrl+Shift+R)\n');
|
||||
} else {
|
||||
console.log('\n⚠ Masih ada yang 404. Cek manual.\n');
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(e => console.error('[FATAL]', e.message));
|
||||
@@ -1,80 +0,0 @@
|
||||
// scripts/fix-mongoose-module.js
|
||||
// Fix: Copy mongoose ke standalone/node_modules agar tersedia sebagai external package
|
||||
'use strict';
|
||||
const { Client } = require('ssh2');
|
||||
|
||||
const SSH = { host: '103.185.47.52', port: 2222, username: 'adminbackend', password: 'htEo7x6LsBQiEHHH', readyTimeout: 60000 };
|
||||
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
const SA = PUB + '/.next/standalone';
|
||||
const BP = '/home/adminbackend/backone-production';
|
||||
|
||||
function exec(conn, cmd, label) {
|
||||
if (label) console.log('\n[' + label + ']');
|
||||
console.log('$ ' + cmd.substring(0, 90));
|
||||
return new Promise(resolve => {
|
||||
conn.exec(cmd, (err, s) => {
|
||||
if (err) { resolve(''); return; }
|
||||
let out = '';
|
||||
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.on('close', () => resolve(out));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const conn = new Client();
|
||||
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(SSH); });
|
||||
console.log('[SSH] Connected\n');
|
||||
|
||||
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
|
||||
|
||||
// 1. Cek lokasi mongoose
|
||||
await exec(conn, 'ls ' + SA + '/node_modules/mongoose 2>/dev/null | head -3 || echo "Tidak ada di standalone/node_modules"', '1. Cek mongoose di standalone');
|
||||
await exec(conn, 'ls ' + BP + '/node_modules/mongoose 2>/dev/null | head -3 || echo "Tidak ada di backone-production"', '2. Cek mongoose di backone-production');
|
||||
await exec(conn, 'ls ' + PUB + '/node_modules/mongoose 2>/dev/null | head -3 || echo "Tidak ada di public_html/node_modules"', '3. Cek mongoose di public_html');
|
||||
|
||||
// 2. Copy mongoose ke standalone/node_modules (dari backone-production)
|
||||
const mongooseSrc = BP + '/node_modules/mongoose';
|
||||
const mongooseDst = SA + '/node_modules/mongoose';
|
||||
await exec(conn,
|
||||
'[ -d ' + mongooseSrc + ' ] && (' +
|
||||
' [ -e ' + mongooseDst + ' ] && echo "Sudah ada" || ' +
|
||||
' (cp -r ' + mongooseSrc + ' ' + mongooseDst + ' && echo "BERHASIL: mongoose disalin ke standalone") ' +
|
||||
') || echo "Sumber tidak ditemukan"',
|
||||
'4. Copy mongoose ke standalone/node_modules'
|
||||
);
|
||||
|
||||
// 3. Verifikasi
|
||||
await exec(conn, 'ls ' + mongooseDst + ' 2>/dev/null | head -5 || echo "GAGAL: tidak ada"', '5. Verifikasi mongoose di standalone');
|
||||
|
||||
// 4. Juga pastikan dependensi mongoose tersedia (bson, etc.)
|
||||
const deps = ['bson', 'kareem', 'mquery', 'mpath', 'sift'];
|
||||
for (const dep of deps) {
|
||||
const src = BP + '/node_modules/' + dep;
|
||||
const dst = SA + '/node_modules/' + dep;
|
||||
await exec(conn,
|
||||
'[ -d ' + src + ' ] && ([ -e ' + dst + ' ] || (cp -r ' + src + ' ' + dst + ' && echo "Copied: ' + dep + '")) || echo "Skip: ' + dep + '"',
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
// 5. Restart frontend
|
||||
await exec(conn, PM2 + ' restart backone-frontend && echo "RESTART OK"', '6. Restart backone-frontend');
|
||||
|
||||
// 6. Tunggu dan cek status
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
await exec(conn, PM2 + ' list 2>/dev/null | grep backone', '7. Status PM2 setelah restart');
|
||||
|
||||
// 7. Test halaman agents
|
||||
await new Promise(r => setTimeout(r, 3000));
|
||||
await exec(conn, 'curl -sk -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/agents', '8. Test /agents setelah fix');
|
||||
|
||||
// 8. Cek error log setelah restart
|
||||
await exec(conn, 'tail -10 ' + PUB + '/logs/frontend-error.log 2>/dev/null', '9. Error log terbaru');
|
||||
|
||||
conn.end();
|
||||
console.log('\n✅ Selesai! Refresh browser ke https://demoplace.my.id/agents\n');
|
||||
}
|
||||
|
||||
main().catch(e => console.error('[FATAL]', e.message));
|
||||
@@ -1,156 +0,0 @@
|
||||
// scripts/fix-pm2-env-final.js
|
||||
// Fix definitif: Buat startup wrapper script yang load .env.production sebelum menjalankan Next.js
|
||||
'use strict';
|
||||
const { Client } = require('ssh2');
|
||||
|
||||
const SSH = { host: '103.185.47.52', port: 2222, username: 'adminbackend', password: 'htEo7x6LsBQiEHHH', readyTimeout: 60000 };
|
||||
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
|
||||
|
||||
function exec(conn, cmd, label) {
|
||||
if (label) console.log('\n[' + label + ']');
|
||||
console.log('$ ' + cmd.substring(0, 90));
|
||||
return new Promise(resolve => {
|
||||
conn.exec(cmd, (err, s) => {
|
||||
if (err) { resolve(''); return; }
|
||||
let out = '';
|
||||
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.on('close', () => resolve(out));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const conn = new Client();
|
||||
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(SSH); });
|
||||
console.log('[SSH] Connected\n');
|
||||
|
||||
// 1. Buat wrapper script yang source .env.production
|
||||
const wrapperContent = [
|
||||
'#!/bin/bash',
|
||||
'# BackOne DPI - Frontend startup wrapper',
|
||||
'# Source environment variables from .env.production',
|
||||
'ENV_FILE="' + PUB + '/.env.production"',
|
||||
'if [ -f "$ENV_FILE" ]; then',
|
||||
' set -a',
|
||||
' source "$ENV_FILE"',
|
||||
' set +a',
|
||||
' echo "[startup] Environment variables loaded from .env.production"',
|
||||
'else',
|
||||
' echo "[startup] WARNING: .env.production not found at $ENV_FILE"',
|
||||
'fi',
|
||||
'# Start Next.js standalone server',
|
||||
'exec node ' + PUB + '/.next/standalone/server.js',
|
||||
].join('\n');
|
||||
|
||||
await exec(conn,
|
||||
'cat > ' + PUB + '/start-frontend.sh << \'WRAPPER_EOF\'\n' + wrapperContent + '\nWRAPPER_EOF\n' +
|
||||
'chmod +x ' + PUB + '/start-frontend.sh && echo "Wrapper script dibuat"',
|
||||
'1. Buat wrapper startup script'
|
||||
);
|
||||
|
||||
await exec(conn, 'cat ' + PUB + '/start-frontend.sh', '2. Verifikasi isi wrapper script');
|
||||
|
||||
// 2. Update ecosystem.config.js di SERVER untuk gunakan wrapper script
|
||||
const ecosystemContent = `// ecosystem.config.js — PM2 Production Config (Server-side, DO NOT COMMIT)
|
||||
module.exports = {
|
||||
apps: [
|
||||
{
|
||||
name: 'backone-proxy',
|
||||
script: './proxy/index.js',
|
||||
cwd: '${PUB}',
|
||||
instances: 1,
|
||||
exec_mode: 'fork',
|
||||
watch: false,
|
||||
node_args: '--max-old-space-size=256',
|
||||
max_memory_restart: '300M',
|
||||
restart_delay: 5000,
|
||||
max_restarts: 10,
|
||||
env_file: '.env.production',
|
||||
env: { NODE_ENV: 'production' },
|
||||
error_file: './logs/proxy-error.log',
|
||||
out_file: './logs/proxy-out.log',
|
||||
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
|
||||
merge_logs: true,
|
||||
},
|
||||
{
|
||||
name: 'backone-backend',
|
||||
script: './backend/server.js',
|
||||
cwd: '${PUB}',
|
||||
instances: 1,
|
||||
exec_mode: 'fork',
|
||||
watch: false,
|
||||
node_args: '--max-old-space-size=256',
|
||||
max_memory_restart: '400M',
|
||||
restart_delay: 3000,
|
||||
max_restarts: 10,
|
||||
env_file: '.env.production',
|
||||
env: { NODE_ENV: 'production' },
|
||||
error_file: './logs/backend-error.log',
|
||||
out_file: './logs/backend-out.log',
|
||||
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
|
||||
merge_logs: true,
|
||||
},
|
||||
{
|
||||
name: 'backone-frontend',
|
||||
script: './start-frontend.sh',
|
||||
interpreter: 'bash',
|
||||
cwd: '${PUB}',
|
||||
instances: 1,
|
||||
exec_mode: 'fork',
|
||||
watch: false,
|
||||
max_memory_restart: '700M',
|
||||
restart_delay: 3000,
|
||||
max_restarts: 10,
|
||||
env: {
|
||||
NODE_ENV: 'production',
|
||||
PORT: 3000,
|
||||
HOSTNAME: '127.0.0.1',
|
||||
NEXT_TELEMETRY_DISABLED: '1',
|
||||
},
|
||||
error_file: './logs/frontend-error.log',
|
||||
out_file: './logs/frontend-out.log',
|
||||
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
|
||||
merge_logs: true,
|
||||
},
|
||||
],
|
||||
};`;
|
||||
|
||||
await exec(conn,
|
||||
'cat > ' + PUB + '/ecosystem.config.js << \'ECOSYSTEM_EOF\'\n' + ecosystemContent + '\nECOSYSTEM_EOF\n' +
|
||||
'echo "ecosystem.config.js diperbarui"',
|
||||
'3. Update ecosystem.config.js di server'
|
||||
);
|
||||
|
||||
// 3. Delete & restart frontend dengan config baru
|
||||
await exec(conn,
|
||||
'cd ' + PUB + ' && ' + PM2 + ' delete backone-frontend 2>/dev/null; ' +
|
||||
PM2 + ' start ecosystem.config.js --only backone-frontend && echo "START OK"',
|
||||
'4. Start frontend dengan wrapper script'
|
||||
);
|
||||
|
||||
// 4. Tunggu startup
|
||||
await new Promise(r => setTimeout(r, 8000));
|
||||
|
||||
// 5. Verifikasi env vars
|
||||
const listOut = await exec(conn, PM2 + ' list 2>/dev/null | grep backone-frontend', '5. PM2 status');
|
||||
// Ambil ID proses baru
|
||||
const match = listOut.match(/│\s+(\d+)\s+│\s+backone-frontend/);
|
||||
if (match) {
|
||||
const newId = match[1];
|
||||
await exec(conn, PM2 + ' env ' + newId + ' 2>/dev/null | grep -E "(NETIFY|MONGO|JWT)" | head -5', '6. Env vars di proses baru');
|
||||
}
|
||||
|
||||
// 6. Test agents
|
||||
await exec(conn, 'curl -sk -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/agents', '7. Test /agents');
|
||||
|
||||
// 7. Error log terbaru
|
||||
await exec(conn, 'tail -5 ' + PUB + '/logs/frontend-error.log 2>/dev/null', '8. Error log terbaru');
|
||||
await exec(conn, 'tail -3 ' + PUB + '/logs/frontend-out.log 2>/dev/null', '9. Out log terbaru');
|
||||
|
||||
conn.end();
|
||||
console.log('\n✅ Selesai!\n');
|
||||
}
|
||||
|
||||
main().catch(e => console.error('[FATAL]', e.message));
|
||||
@@ -1,223 +0,0 @@
|
||||
// scripts/fix-proxy-headers.js
|
||||
// Fix: proxy.php harus hapus Content-Length agar CSS/JS tidak terpotong
|
||||
'use strict';
|
||||
|
||||
const SftpClient = require('ssh2-sftp-client');
|
||||
const { Client } = require('ssh2');
|
||||
const https = require('https');
|
||||
|
||||
const CONFIG = {
|
||||
host: '103.185.47.52', port: 2222,
|
||||
username: 'adminbackend', password: 'htEo7x6LsBQiEHHH',
|
||||
readyTimeout: 60000
|
||||
};
|
||||
|
||||
const ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
|
||||
// ── proxy.php yang sudah diperbaiki ──────────────────────────────────────
|
||||
// Fix utama: tambahkan content-length ke daftar header yang dibuang
|
||||
// agar tidak terjadi mismatch antara ukuran compressed vs uncompressed
|
||||
const PROXY_PHP = `<?php
|
||||
/**
|
||||
* BackOne DPI - PHP Reverse Proxy (Fixed)
|
||||
* Forward semua request ke Next.js port 3000
|
||||
* Fix: Content-Length dihapus agar tidak terjadi data truncation
|
||||
*/
|
||||
define('NEXTJS_URL', 'http://127.0.0.1:3000');
|
||||
|
||||
$uri = $_SERVER['REQUEST_URI'] ?? '/';
|
||||
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
|
||||
$target = NEXTJS_URL . $uri;
|
||||
|
||||
// Headers yang diteruskan ke Next.js
|
||||
$fwdHeaders = [
|
||||
'X-Forwarded-For: ' . ($_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1'),
|
||||
'X-Forwarded-Proto: https',
|
||||
'X-Real-IP: ' . ($_SERVER['REMOTE_ADDR'] ?? ''),
|
||||
'Host: demoplace.my.id',
|
||||
'Accept-Encoding: identity',
|
||||
];
|
||||
|
||||
$allHeaders = getallheaders() ?: [];
|
||||
$skip = ['host', 'connection', 'transfer-encoding', 'keep-alive', 'content-length', 'accept-encoding'];
|
||||
foreach ($allHeaders as $name => $value) {
|
||||
if (!in_array(strtolower($name), $skip)) {
|
||||
$fwdHeaders[] = "$name: $value";
|
||||
}
|
||||
}
|
||||
|
||||
$body = in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE']) ? file_get_contents('php://input') : null;
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => $target,
|
||||
CURLOPT_CUSTOMREQUEST => $method,
|
||||
CURLOPT_HTTPHEADER => $fwdHeaders,
|
||||
CURLOPT_POSTFIELDS => $body,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_HEADER => true,
|
||||
CURLOPT_FOLLOWLOCATION => false,
|
||||
CURLOPT_TIMEOUT => 30,
|
||||
CURLOPT_CONNECTTIMEOUT => 5,
|
||||
// PENTING: Tidak pakai CURLOPT_ENCODING agar response tidak dikompresi
|
||||
// (kita sudah kirim Accept-Encoding: identity ke Next.js)
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||
$curlError = curl_error($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if ($response === false) {
|
||||
http_response_code(502);
|
||||
header('Content-Type: text/plain');
|
||||
echo 'BackOne: Gagal terhubung ke Next.js. Error: ' . $curlError;
|
||||
exit;
|
||||
}
|
||||
|
||||
$responseHeaders = substr($response, 0, $headerSize);
|
||||
$responseBody = substr($response, $headerSize);
|
||||
|
||||
http_response_code($httpCode ?: 200);
|
||||
|
||||
// Header yang TIDAK diteruskan ke browser
|
||||
$skipRes = [
|
||||
'transfer-encoding',
|
||||
'connection',
|
||||
'keep-alive',
|
||||
'content-encoding',
|
||||
'content-length', // FIX: hapus agar tidak terjadi size mismatch
|
||||
];
|
||||
|
||||
foreach (explode("\\r\\n", $responseHeaders) as $header) {
|
||||
$header = trim($header);
|
||||
if (empty($header) || preg_match('/^HTTP\\//i', $header)) continue;
|
||||
$colonPos = strpos($header, ':');
|
||||
if ($colonPos === false) continue;
|
||||
$headerName = strtolower(trim(substr($header, 0, $colonPos)));
|
||||
if (in_array($headerName, $skipRes)) continue;
|
||||
header($header, false);
|
||||
}
|
||||
|
||||
echo $responseBody;
|
||||
`;
|
||||
|
||||
// ── .htaccess dengan FollowSymLinks ──────────────────────────────────────
|
||||
const HTACCESS = `# BackOne DPI — Apache .htaccess
|
||||
Options +FollowSymLinks
|
||||
|
||||
# Redirect HTTP ke HTTPS
|
||||
RewriteEngine On
|
||||
RewriteCond %{HTTPS} !=on
|
||||
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
|
||||
|
||||
# Static Next.js files: sajikan langsung dari disk (via symlink _next -> .next)
|
||||
RewriteCond %{REQUEST_FILENAME} -f
|
||||
RewriteRule ^ - [L]
|
||||
|
||||
# Semua request lain: teruskan ke PHP proxy (Next.js port 3000)
|
||||
RewriteRule ^(.*)$ /proxy.php [L,QSA]
|
||||
`;
|
||||
|
||||
async function main() {
|
||||
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
||||
console.log('║ BackOne DPI — Fix CSS/JS Content-Length & Symlinks ║');
|
||||
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
||||
|
||||
// ── Diagnosa dulu: cek apa yang dikirim ke browser untuk CSS ──────────
|
||||
console.log('▶ Diagnosa: Cek CSS URL yang ada di HTML login page...');
|
||||
const conn1 = new Client();
|
||||
await new Promise((r, j) => { conn1.on('ready', r).on('error', j).connect(CONFIG); });
|
||||
|
||||
// Ambil HTML dari port 3000 dan cari CSS links
|
||||
const htmlResult = await new Promise(resolve => {
|
||||
conn1.exec(
|
||||
`curl -sk http://127.0.0.1:3000/login | grep -o 'href="/_next/static/css/[^"]*"' | head -3`,
|
||||
(err, s) => {
|
||||
if (err) { resolve('error'); return; }
|
||||
let out = '';
|
||||
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.stderr.on('data', d => { out += d; })
|
||||
.on('close', () => resolve(out.trim()));
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
console.log(`CSS refs: ${htmlResult}`);
|
||||
|
||||
// Test apakah CSS bisa diakses langsung
|
||||
if (htmlResult) {
|
||||
const cssPath = htmlResult.match(/href="([^"]+)"/)?.[1];
|
||||
if (cssPath) {
|
||||
await new Promise(resolve => {
|
||||
conn1.exec(
|
||||
`curl -sk -D - http://127.0.0.1:3000${cssPath} | head -15`,
|
||||
(err, s) => {
|
||||
if (err) { resolve(); return; }
|
||||
s.on('data', d => process.stdout.write(d.toString()))
|
||||
.stderr.on('data', () => {})
|
||||
.on('close', resolve);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
conn1.end();
|
||||
|
||||
// ── Upload proxy.php dan .htaccess yang sudah diperbaiki ──────────────
|
||||
console.log('\n▶ Upload perbaikan via SFTP...');
|
||||
const sftp = new SftpClient();
|
||||
await sftp.connect(CONFIG);
|
||||
|
||||
await sftp.put(Buffer.from(PROXY_PHP, 'utf8'), `${ROOT}/proxy.php`);
|
||||
console.log(' ✅ proxy.php (fixed: Content-Length stripped, Accept-Encoding: identity)');
|
||||
|
||||
await sftp.put(Buffer.from(HTACCESS, 'utf8'), `${ROOT}/.htaccess`);
|
||||
console.log(' ✅ .htaccess (fixed: +FollowSymLinks added)');
|
||||
|
||||
await sftp.end();
|
||||
|
||||
// ── Verifikasi CSS via domain ─────────────────────────────────────────
|
||||
console.log('\n▶ Test CSS loading via domain (tunggu 3 detik)...');
|
||||
await new Promise(r => setTimeout(r, 3000));
|
||||
|
||||
const conn2 = new Client();
|
||||
await new Promise((r, j) => { conn2.on('ready', r).on('error', j).connect(CONFIG); });
|
||||
|
||||
// Ambil CSS URL dari domain lalu test
|
||||
const cssUrlResult = await new Promise(resolve => {
|
||||
conn2.exec(
|
||||
`CSS=$(curl -sk https://demoplace.my.id/login | grep -o '/_next/static/css/[^"]*' | head -1); ` +
|
||||
`[ -n "$CSS" ] && curl -sk -D - "https://demoplace.my.id$CSS" | head -10 || echo "Tidak ada CSS URL ditemukan"`,
|
||||
(err, s) => {
|
||||
if (err) { resolve(); return; }
|
||||
s.on('data', d => process.stdout.write(d.toString()))
|
||||
.stderr.on('data', () => {})
|
||||
.on('close', resolve);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
conn2.end();
|
||||
|
||||
// ── Final test ────────────────────────────────────────────────────────
|
||||
console.log('\n▶ Final test domain...');
|
||||
for (const path of ['/', '/login']) {
|
||||
const r = await new Promise(resolve => {
|
||||
const req = https.get(`https://demoplace.my.id${path}`,
|
||||
{ timeout: 12000, 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 = r.status === 200 ? '✅' : r.status >= 300 && r.status < 400 ? '↩️ ' : '❌';
|
||||
console.log(` ${icon} https://demoplace.my.id${path} → HTTP ${r.status}`);
|
||||
}
|
||||
|
||||
console.log('\n✅ Selesai! Refresh browser dengan Ctrl+Shift+R (hard refresh)\n');
|
||||
}
|
||||
|
||||
main().catch(err => { console.error('[FATAL]', err.message); process.exit(1); });
|
||||
@@ -1,129 +0,0 @@
|
||||
// scripts/fix-static-paths.js
|
||||
// Menyalin static files dari backone-production ke standalone yang benar
|
||||
// Masalah: Upload Windows membuat direktori dengan backslash literal di Linux
|
||||
'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
|
||||
};
|
||||
|
||||
function exec(conn, cmd, label) {
|
||||
if (label) console.log('\n[' + label + ']');
|
||||
console.log('$ ' + cmd.substring(0, 90));
|
||||
return new Promise(resolve => {
|
||||
conn.exec(cmd, (err, s) => {
|
||||
if (err) { resolve(''); return; }
|
||||
let out = '';
|
||||
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.on('close', () => resolve(out));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function httpGet(url) {
|
||||
return new Promise(resolve => {
|
||||
const req = https.get(url, { timeout: 12000, rejectUnauthorized: false }, res => {
|
||||
let body = '';
|
||||
res.on('data', d => body += d);
|
||||
res.on('end', () => resolve({ status: res.statusCode, size: body.length, type: res.headers['content-type'] }));
|
||||
});
|
||||
req.on('error', e => resolve({ status: 0, error: e.message }));
|
||||
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
||||
console.log('║ BackOne DPI — Fix Static Paths (Windows Backslash) ║');
|
||||
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
||||
|
||||
const conn = new Client();
|
||||
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(SSH); });
|
||||
console.log('[SSH] Terhubung!\n');
|
||||
|
||||
const BP = '/home/adminbackend/backone-production';
|
||||
const SA = '/home/adminbackend/web/demoplace.my.id/public_html/.next/standalone';
|
||||
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
|
||||
// 1. Cek BUILD_ID di backone-production
|
||||
await exec(conn, 'cat ' + BP + '/.next/BUILD_ID 2>/dev/null || echo "NO_BUILDID"', '1. BUILD_ID backone-production');
|
||||
|
||||
// 2. Verifikasi chunk files ada di backone-production
|
||||
await exec(conn,
|
||||
'ls ' + BP + '/.next/static/chunks/ | grep -E "(3km6z|21luguo|1u6dw|1osk)" | head -10',
|
||||
'2. Cek chunk files di backone-production'
|
||||
);
|
||||
|
||||
// 3. Sinkronisasi static files dari backone-production ke standalone
|
||||
await exec(conn,
|
||||
'rsync -av --ignore-existing ' + BP + '/.next/static/ ' + SA + '/.next/static/ 2>&1 | tail -5',
|
||||
'3. Rsync static files ke standalone/.next/static'
|
||||
);
|
||||
|
||||
// 4. Verifikasi chunks sudah ada di standalone
|
||||
await exec(conn,
|
||||
'ls ' + SA + '/.next/static/chunks/ | grep -E "(3km6z|21luguo|1u6dw|1osk)" | head -10',
|
||||
'4. Verifikasi chunks di standalone setelah rsync'
|
||||
);
|
||||
|
||||
await exec(conn,
|
||||
'ls ' + SA + '/.next/static/chunks/ | wc -l',
|
||||
'5. Total file chunks di standalone'
|
||||
);
|
||||
|
||||
// 5. Update symlink _next → standalone/.next
|
||||
await exec(conn,
|
||||
'rm -f ' + PUB + '/_next && ln -s ' + SA + '/.next ' + PUB + '/_next && echo "Symlink updated"',
|
||||
'6. Update symlink _next → standalone/.next'
|
||||
);
|
||||
|
||||
// 6. Verifikasi symlink
|
||||
await exec(conn,
|
||||
'ls -la ' + PUB + '/_next && ls ' + PUB + '/_next/static/chunks/ | grep -E "(3km6z|21luguo)" | head -5',
|
||||
'7. Verifikasi symlink baru'
|
||||
);
|
||||
|
||||
// 7. Juga sinkronisasi public/ dari backone-production jika dibutuhkan
|
||||
await exec(conn,
|
||||
'rsync -av --ignore-existing ' + BP + '/public/ ' + PUB + '/public/ 2>&1 | tail -3 || echo "Tidak perlu sync public/"',
|
||||
'8. Sync public/ dari backone-production'
|
||||
);
|
||||
|
||||
conn.end();
|
||||
|
||||
// 8. Test CSS/JS via domain
|
||||
console.log('\n[9. Test CSS/JS via domain setelah fix...]');
|
||||
await new Promise(r => setTimeout(r, 3000));
|
||||
|
||||
const files = [
|
||||
'/_next/static/chunks/3km6z-n6wbgrs.js',
|
||||
'/_next/static/chunks/1u6dw_tm45utz.css',
|
||||
'/_next/static/chunks/1oskchnhjm4n8.css',
|
||||
'/_next/static/chunks/21luguo5_g2uu.js',
|
||||
'/_next/static/chunks/1-8s9_t85wwr4.js',
|
||||
];
|
||||
|
||||
let allOk = true;
|
||||
for (const f of files) {
|
||||
const r = await httpGet('https://demoplace.my.id' + f);
|
||||
const icon = r.status === 200 ? '✅' : '❌';
|
||||
const ext = f.endsWith('.css') ? 'CSS' : 'JS ';
|
||||
console.log(' ' + icon + ' [' + ext + '] HTTP ' + r.status + ' | ' + (r.size || 0) + ' bytes | ' + (r.type || 'N/A'));
|
||||
if (r.status !== 200) { console.log(' → ' + f); allOk = false; }
|
||||
}
|
||||
|
||||
if (allOk) {
|
||||
console.log('\n🎉 SEMUA CSS/JS BERHASIL TERMUAT!');
|
||||
console.log(' Lakukan HARD REFRESH (Ctrl+Shift+R) di browser.\n');
|
||||
} else {
|
||||
console.log('\n⚠️ Beberapa file masih 404. Mungkin perlu investigasi lebih lanjut.\n');
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(err => { console.error('[FATAL]', err.message); process.exit(1); });
|
||||
@@ -1,118 +0,0 @@
|
||||
// scripts/fix-symlink.js
|
||||
// Fix: Perbarui symlink _next agar menunjuk ke .next/standalone/.next
|
||||
// Ini adalah penyebab utama CSS/JS tidak termuat
|
||||
'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
|
||||
};
|
||||
|
||||
function sshExec(conn, cmd, label = '') {
|
||||
if (label) console.log(`\n[${label}]`);
|
||||
console.log('$ ' + cmd.substring(0, 90) + (cmd.length > 90 ? '...' : ''));
|
||||
return new Promise(resolve => {
|
||||
conn.exec(cmd, (err, s) => {
|
||||
if (err) { resolve(''); return; }
|
||||
let out = '';
|
||||
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.on('close', () => resolve(out));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function httpGet(url) {
|
||||
return new Promise(resolve => {
|
||||
const req = https.get(url, { timeout: 10000, rejectUnauthorized: false }, res => {
|
||||
let body = '';
|
||||
res.on('data', d => body += d);
|
||||
res.on('end', () => resolve({ status: res.statusCode, type: res.headers['content-type'], size: body.length }));
|
||||
});
|
||||
req.on('error', e => resolve({ status: 0, error: e.message }));
|
||||
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
||||
console.log('║ BackOne DPI — Fix Symlink _next → standalone/.next ║');
|
||||
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
||||
|
||||
const conn = new Client();
|
||||
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(SSH); });
|
||||
console.log('[SSH] Terhubung!\n');
|
||||
|
||||
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
const SA = `${PUB}/.next/standalone`;
|
||||
|
||||
// 1. Verifikasi struktur standalone
|
||||
await sshExec(conn,
|
||||
`ls ${SA}/.next/static/chunks/ | grep -E "(3km6z|21luguo|1u6dw|1osk)" | head -10`,
|
||||
'1. Cek chunk files di standalone/.next'
|
||||
);
|
||||
|
||||
await sshExec(conn,
|
||||
`ls ${SA}/.next/static/chunks/*.css 2>/dev/null | head -5 || echo "Cek dengan wc"`,
|
||||
'2. Cek CSS files di standalone'
|
||||
);
|
||||
|
||||
await sshExec(conn,
|
||||
`ls ${SA}/.next/static/chunks/ | wc -l && echo "file di chunks"`,
|
||||
'3. Jumlah total file di chunks'
|
||||
);
|
||||
|
||||
// 2. Update symlink
|
||||
await sshExec(conn,
|
||||
`rm -f ${PUB}/_next && ln -s ${SA}/.next ${PUB}/_next && echo "BERHASIL: symlink diperbaiki"`,
|
||||
'4. Update symlink _next → standalone/.next'
|
||||
);
|
||||
|
||||
// 3. Verifikasi symlink baru
|
||||
await sshExec(conn,
|
||||
`ls -la ${PUB}/_next && ls ${PUB}/_next/static/chunks/ | head -5`,
|
||||
'5. Verifikasi symlink baru'
|
||||
);
|
||||
|
||||
// 4. Juga update public/ symlink jika belum ada
|
||||
await sshExec(conn,
|
||||
`ls -la ${PUB}/public 2>/dev/null || echo "public/ tidak ada sebagai symlink"`,
|
||||
'6. Cek public/ directory'
|
||||
);
|
||||
|
||||
// Buat symlink public → standalone/public jika ada
|
||||
await sshExec(conn,
|
||||
`[ -d ${SA}/public ] && ([ -e ${PUB}/public_sa ] || ln -s ${SA}/public ${PUB}/public_sa) && echo "standalone/public tersedia" || echo "standalone/public tidak ada"`,
|
||||
'7. Cek standalone/public'
|
||||
);
|
||||
|
||||
conn.end();
|
||||
|
||||
// 5. Test CSS/JS loading setelah fix
|
||||
console.log('\n[8. Test CSS/JS via domain setelah fix...]');
|
||||
await new Promise(r => setTimeout(r, 2000));
|
||||
|
||||
const files = [
|
||||
'/_next/static/chunks/3km6z-n6wbgrs.js',
|
||||
'/_next/static/chunks/1u6dw_tm45utz.css',
|
||||
'/_next/static/chunks/1oskchnhjm4n8.css',
|
||||
'/_next/static/chunks/21luguo5_g2uu.js',
|
||||
'/_next/static/chunks/1-8s9_t85wwr4.js',
|
||||
];
|
||||
|
||||
for (const f of files) {
|
||||
const r = await httpGet(`https://demoplace.my.id${f}`);
|
||||
const icon = r.status === 200 ? '✅' : '❌';
|
||||
const ext = f.endsWith('.css') ? 'CSS' : 'JS ';
|
||||
console.log(` ${icon} [${ext}] HTTP ${r.status} | ${r.size || 0} bytes | ${r.type || 'N/A'}`);
|
||||
if (r.status !== 200) console.log(` ${f}`);
|
||||
}
|
||||
|
||||
console.log('\n✅ Selesai! Lakukan HARD REFRESH (Ctrl+Shift+R) di browser.\n');
|
||||
}
|
||||
|
||||
main().catch(err => { console.error('[FATAL]', err.message); process.exit(1); });
|
||||
@@ -1,89 +0,0 @@
|
||||
// scripts/fix-turbopack-external.js
|
||||
// Fix: Buat wrapper module untuk hashed external modules yang diperlukan Turbopack
|
||||
'use strict';
|
||||
const { Client } = require('ssh2');
|
||||
|
||||
const SSH = { host: '103.185.47.52', port: 2222, username: 'adminbackend', password: 'htEo7x6LsBQiEHHH', readyTimeout: 60000 };
|
||||
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
|
||||
function exec(conn, cmd, label) {
|
||||
if (label) console.log('\n[' + label + ']');
|
||||
console.log('$ ' + cmd.substring(0, 90));
|
||||
return new Promise(resolve => {
|
||||
conn.exec(cmd, (err, s) => {
|
||||
if (err) { resolve(''); return; }
|
||||
let out = '';
|
||||
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
|
||||
.on('close', () => resolve(out));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const conn = new Client();
|
||||
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(SSH); });
|
||||
console.log('[SSH] Connected\n');
|
||||
|
||||
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
|
||||
const NM = PUB + '/node_modules';
|
||||
const SA = PUB + '/.next/standalone';
|
||||
|
||||
// 1. Verifikasi mongoose asli tersedia di public_html/node_modules
|
||||
await exec(conn, 'ls ' + NM + '/mongoose/package.json 2>/dev/null && echo "mongoose OK" || echo "mongoose TIDAK ADA"', '1. Cek mongoose asli');
|
||||
|
||||
// 2. Cek error log untuk nama hash yang dipakai
|
||||
await exec(conn, 'grep "mongoose-" ' + PUB + '/logs/frontend-error.log 2>/dev/null | grep "Cannot find" | tail -5', '2. Hash mongoose dari error log');
|
||||
|
||||
// 3. Buat wrapper module mongoose-8b99e611e7552af3
|
||||
const HASH_PKG = NM + '/mongoose-8b99e611e7552af3';
|
||||
await exec(conn,
|
||||
'mkdir -p ' + HASH_PKG + ' && ' +
|
||||
'echo \'{"name":"mongoose-8b99e611e7552af3","version":"1.0.0","main":"index.js"}\' > ' + HASH_PKG + '/package.json && ' +
|
||||
'echo \'module.exports = require("mongoose");\' > ' + HASH_PKG + '/index.js && ' +
|
||||
'echo "Wrapper module dibuat"',
|
||||
'3. Buat wrapper mongoose-8b99e611e7552af3'
|
||||
);
|
||||
|
||||
// 4. Verifikasi wrapper
|
||||
await exec(conn, 'cat ' + HASH_PKG + '/index.js', '4. Isi wrapper module');
|
||||
|
||||
// 5. Juga cek apakah ada hash lain yang mungkin gagal (better-sqlite3)
|
||||
await exec(conn,
|
||||
'grep "Cannot find module" ' + PUB + '/logs/frontend-error.log 2>/dev/null | grep -v mongoose | tail -5',
|
||||
'5. Cek module lain yang mungkin gagal'
|
||||
);
|
||||
|
||||
// 6. Cek standalone/node_modules - apakah ada?
|
||||
await exec(conn,
|
||||
'ls -la ' + SA + '/ | grep node_modules || echo "standalone/node_modules TIDAK ADA"',
|
||||
'6. Cek standalone/node_modules'
|
||||
);
|
||||
|
||||
// 7. Buat standalone/node_modules symlink ke public_html/node_modules
|
||||
await exec(conn,
|
||||
'[ -d ' + SA + '/node_modules ] && echo "Sudah ada" || ' +
|
||||
'(ln -s ' + NM + ' ' + SA + '/node_modules && echo "Symlink node_modules dibuat")',
|
||||
'7. Buat symlink standalone/node_modules → public_html/node_modules'
|
||||
);
|
||||
|
||||
// 8. Restart frontend
|
||||
await exec(conn, PM2 + ' restart backone-frontend --update-env && echo "RESTART OK"', '8. Restart frontend');
|
||||
|
||||
// 9. Tunggu startup
|
||||
await new Promise(r => setTimeout(r, 8000));
|
||||
|
||||
// 10. Test agents page
|
||||
await exec(conn,
|
||||
'curl -sk -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/agents',
|
||||
'9. Test /agents (HTTP code)'
|
||||
);
|
||||
|
||||
// 11. Cek error log setelah restart
|
||||
await exec(conn, 'tail -10 ' + PUB + '/logs/frontend-error.log 2>/dev/null', '10. Error log setelah fix');
|
||||
|
||||
conn.end();
|
||||
console.log('\n✅ Selesai! Refresh browser ke https://demoplace.my.id/agents\n');
|
||||
}
|
||||
|
||||
main().catch(e => console.error('[FATAL]', e.message));
|
||||
@@ -1,211 +0,0 @@
|
||||
// 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); });
|
||||
@@ -1,180 +0,0 @@
|
||||
// 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); });
|
||||
@@ -1,18 +0,0 @@
|
||||
const { Client } = require('ssh2');
|
||||
|
||||
const conn = new Client();
|
||||
conn.on('ready', () => {
|
||||
conn.exec(`ls -la /home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/.next/server/app/\\(dashboard\\)/ 2>/dev/null || ls -la /home/adminbackend/web/demoplace.my.id/public_html/.next/server/app/`, (err, stream) => {
|
||||
let out = '';
|
||||
stream.on('data', d => out += d);
|
||||
stream.on('close', () => {
|
||||
console.log('=== REMOTE DASHBOARD APP ROUTES ===\n' + out);
|
||||
conn.end();
|
||||
});
|
||||
});
|
||||
}).connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
@@ -1,83 +0,0 @@
|
||||
// scripts/migrate-db-remote.js
|
||||
global.crypto = require('crypto');
|
||||
const { MongoClient } = require('mongodb');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const REMOTE_URI = process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017/backone_dpi';
|
||||
const DB_NAME = 'backone_dpi';
|
||||
const DATA_DIR = __dirname;
|
||||
|
||||
async function migrateCollection(db, colName, keyField) {
|
||||
const filePath = path.join(DATA_DIR, `${colName}.json`);
|
||||
if (!fs.existsSync(filePath)) {
|
||||
console.log(` [SKIP] ${colName}.json not found in migration folder.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const raw = fs.readFileSync(filePath, 'utf8');
|
||||
const documents = JSON.parse(raw);
|
||||
console.log(`\nMigrating collection: ${colName} (${documents.length} docs)...`);
|
||||
|
||||
const col = db.collection(colName);
|
||||
let upsertedCount = 0;
|
||||
let matchedCount = 0;
|
||||
|
||||
for (const doc of documents) {
|
||||
// Preserve MongoDB Object ID or convert it properly if it has $oid notation
|
||||
const query = {};
|
||||
query[keyField] = doc[keyField];
|
||||
|
||||
// Clean up _id or preserve it
|
||||
const updateDoc = { ...doc };
|
||||
if (updateDoc._id) {
|
||||
if (updateDoc._id.$oid) {
|
||||
// If it's exported via mongoexport format
|
||||
delete updateDoc._id;
|
||||
} else {
|
||||
// Remove _id from update payload to prevent "change _id" errors on upsert
|
||||
delete updateDoc._id;
|
||||
}
|
||||
}
|
||||
|
||||
const result = await col.updateOne(
|
||||
query,
|
||||
{ $set: updateDoc },
|
||||
{ upsert: true }
|
||||
);
|
||||
|
||||
if (result.upsertedCount > 0) {
|
||||
upsertedCount++;
|
||||
} else {
|
||||
matchedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(` ✓ Finished ${colName}: ${upsertedCount} new inserted (upserted), ${matchedCount} existing updated.`);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('=== STARTING PRODUCTION DATABASE MIGRATION ===');
|
||||
console.log('Connecting to production MongoDB...');
|
||||
const client = new MongoClient(REMOTE_URI, { serverSelectionTimeoutMS: 5000 });
|
||||
|
||||
try {
|
||||
await client.connect();
|
||||
console.log('✓ Connected to production MongoDB successfully!');
|
||||
const db = client.db(DB_NAME);
|
||||
|
||||
// Run migrations using distinct key fields for upserting
|
||||
await migrateCollection(db, 'users', 'username');
|
||||
await migrateCollection(db, 'tenantconfigs', 'site_uuid');
|
||||
await migrateCollection(db, 'customagentlocations', 'agent_uuid');
|
||||
|
||||
console.log('\n=== MIGRATION COMPLETED SUCCESSFULLY ===');
|
||||
} catch (err) {
|
||||
console.error('\n✗ Migration failed:', err.message);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
await client.close();
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,126 +0,0 @@
|
||||
// scripts/migrate_production_config.js
|
||||
if (typeof globalThis.crypto === 'undefined') {
|
||||
globalThis.crypto = require('crypto');
|
||||
}
|
||||
const { MongoClient } = require('mongodb');
|
||||
const path = require('path');
|
||||
|
||||
const LOCAL_URI = 'mongodb://127.0.0.1:27017';
|
||||
const REMOTE_URI = process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017/backone_dpi';
|
||||
const DB_NAME = 'backone_dpi';
|
||||
|
||||
async function migrate() {
|
||||
console.log("=============================================================");
|
||||
console.log(" BackOne DPI - Selective Configuration Migration to Prod ");
|
||||
console.log("=============================================================\n");
|
||||
|
||||
let localClient, remoteClient;
|
||||
try {
|
||||
console.log("Connecting to local MongoDB...");
|
||||
localClient = new MongoClient(LOCAL_URI, { serverSelectionTimeoutMS: 3000 });
|
||||
await localClient.connect();
|
||||
const localDb = localClient.db(DB_NAME);
|
||||
console.log("✓ Connected to local MongoDB.");
|
||||
|
||||
console.log("Connecting to production MongoDB...");
|
||||
remoteClient = new MongoClient(REMOTE_URI, { serverSelectionTimeoutMS: 5000 });
|
||||
await remoteClient.connect();
|
||||
const remoteDb = remoteClient.db(DB_NAME);
|
||||
console.log("✓ Connected to production MongoDB.\n");
|
||||
|
||||
// 1. Sync users (Upsert based on username to preserve existing user credentials if updated)
|
||||
console.log("--- Syncing 'users' collection ---");
|
||||
const localUsersColl = localDb.collection('users');
|
||||
const remoteUsersColl = remoteDb.collection('users');
|
||||
|
||||
const localUsers = await localUsersColl.find({}).toArray();
|
||||
console.log(`Found ${localUsers.length} users in local database.`);
|
||||
|
||||
let userUpsertCount = 0;
|
||||
for (const user of localUsers) {
|
||||
// Remove _id to avoid duplicate key errors or mismatched ObjectId
|
||||
const { _id, ...userData } = user;
|
||||
const res = await remoteUsersColl.updateOne(
|
||||
{ username: user.username },
|
||||
{ $set: userData },
|
||||
{ upsert: true }
|
||||
);
|
||||
if (res.upsertedCount > 0 || res.modifiedCount > 0) {
|
||||
userUpsertCount++;
|
||||
}
|
||||
}
|
||||
console.log(`✓ Synchronized ${userUpsertCount} users to production MongoDB.`);
|
||||
|
||||
// 2. Sync tenantconfigs (Clear & Replace)
|
||||
console.log("\n--- Syncing 'tenantconfigs' collection ---");
|
||||
const localConfigColl = localDb.collection('tenantconfigs');
|
||||
const remoteConfigColl = remoteDb.collection('tenantconfigs');
|
||||
|
||||
const localConfigs = await localConfigColl.find({}).toArray();
|
||||
console.log(`Found ${localConfigs.length} tenant configurations locally.`);
|
||||
|
||||
if (localConfigs.length > 0) {
|
||||
await remoteConfigColl.deleteMany({});
|
||||
const cleanedConfigs = localConfigs.map(c => {
|
||||
const { _id, ...rest } = c;
|
||||
return rest;
|
||||
});
|
||||
await remoteConfigColl.insertMany(cleanedConfigs);
|
||||
console.log(`✓ Synchronized ${localConfigs.length} configurations to production.`);
|
||||
}
|
||||
|
||||
// 3. Sync customagentlocations (Clear & Replace)
|
||||
console.log("\n--- Syncing 'customagentlocations' collection ---");
|
||||
const localLocColl = localDb.collection('customagentlocations');
|
||||
const remoteLocColl = remoteDb.collection('customagentlocations');
|
||||
|
||||
const localLocs = await localLocColl.find({}).toArray();
|
||||
console.log(`Found ${localLocs.length} agent locations locally.`);
|
||||
|
||||
if (localLocs.length > 0) {
|
||||
await remoteLocColl.deleteMany({});
|
||||
const cleanedLocs = localLocs.map(l => {
|
||||
const { _id, ...rest } = l;
|
||||
return rest;
|
||||
});
|
||||
await remoteLocColl.insertMany(cleanedLocs);
|
||||
console.log(`✓ Synchronized ${localLocs.length} agent locations to production.`);
|
||||
}
|
||||
|
||||
// 4. Sync blacklistrules (Clear & Replace, if exists)
|
||||
console.log("\n--- Syncing 'blacklistrules' collection ---");
|
||||
const localRulesColl = localDb.collection('blacklistrules');
|
||||
const remoteRulesColl = remoteDb.collection('blacklistrules');
|
||||
|
||||
// Check if collection exists
|
||||
const localColls = await localDb.listCollections({ name: 'blacklistrules' }).toArray();
|
||||
if (localColls.length > 0) {
|
||||
const localRules = await localRulesColl.find({}).toArray();
|
||||
console.log(`Found ${localRules.length} blacklist rules locally.`);
|
||||
if (localRules.length > 0) {
|
||||
await remoteRulesColl.deleteMany({});
|
||||
const cleanedRules = localRules.map(r => {
|
||||
const { _id, ...rest } = r;
|
||||
return rest;
|
||||
});
|
||||
await remoteRulesColl.insertMany(cleanedRules);
|
||||
console.log(`✓ Synchronized ${localRules.length} blacklist rules to production.`);
|
||||
}
|
||||
} else {
|
||||
console.log("No blacklist rules found locally.");
|
||||
}
|
||||
|
||||
console.log("\n=============================================================");
|
||||
console.log("✓ Database configuration migration completed successfully!");
|
||||
console.log("=============================================================");
|
||||
|
||||
} catch (err) {
|
||||
console.error("\n✗ Migration failed:", err.message);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
if (localClient) await localClient.close();
|
||||
if (remoteClient) await remoteClient.close();
|
||||
}
|
||||
}
|
||||
|
||||
migrate();
|
||||
@@ -1,36 +0,0 @@
|
||||
// scripts/prune-production-cumulative.js
|
||||
const mongoose = require('mongoose');
|
||||
|
||||
const MONGODB_URI = process.env.MONGODB_URI || "mongodb://127.0.0.1:27017/backone_dpi";
|
||||
|
||||
async function run() {
|
||||
console.log('Connecting to Production MongoDB...');
|
||||
await mongoose.connect(MONGODB_URI);
|
||||
console.log('Connected.');
|
||||
|
||||
const db = mongoose.connection.db;
|
||||
|
||||
// We want to delete summaries and telemetry documents created before today at 18:40 WIB (11:40 UTC)
|
||||
const cutOffDate = new Date('2026-07-23T11:40:00.000Z');
|
||||
console.log('Pruning data before:', cutOffDate);
|
||||
|
||||
const collections = ['summaries', 'appstats', 'protocolstats', 'devicestats'];
|
||||
|
||||
for (const collName of collections) {
|
||||
const countBefore = await db.collection(collName).countDocuments({});
|
||||
console.log(`[${collName}] Count before prune:`, countBefore);
|
||||
|
||||
const deleteRes = await db.collection(collName).deleteMany({
|
||||
timestamp: { $lt: cutOffDate }
|
||||
});
|
||||
console.log(`[${collName}] Deleted:`, deleteRes.deletedCount);
|
||||
|
||||
const countAfter = await db.collection(collName).countDocuments({});
|
||||
console.log(`[${collName}] Count after prune:`, countAfter);
|
||||
}
|
||||
|
||||
await mongoose.disconnect();
|
||||
console.log('✓ Pruning complete!');
|
||||
}
|
||||
|
||||
run().catch(console.error);
|
||||
@@ -1,26 +0,0 @@
|
||||
// scripts/quick-diag.js
|
||||
'use strict';
|
||||
const { Client } = require('ssh2');
|
||||
const conn = new Client();
|
||||
conn.on('ready', () => {
|
||||
const cmds = [
|
||||
'echo "=== Port 3000 test ==" && curl -sk -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/login',
|
||||
'echo "" && echo "=== Nginx conf_custom ===" && cat /home/adminbackend/conf/web/demoplace.my.id/nginx.conf_custom 2>/dev/null || echo MISSING',
|
||||
'echo "=== Nginx ssl conf_custom ===" && cat /home/adminbackend/conf/web/demoplace.my.id/nginx.ssl.conf_custom 2>/dev/null || echo MISSING',
|
||||
'echo "=== .htaccess ===" && cat /home/adminbackend/web/demoplace.my.id/public_html/.htaccess',
|
||||
'echo "=== PM2 status ===" && /home/adminbackend/.npm-global/bin/pm2 list 2>/dev/null | grep -E "(name|backone)"',
|
||||
];
|
||||
let i = 0;
|
||||
function run() {
|
||||
if (i >= cmds.length) { conn.end(); console.log('\nDone.'); return; }
|
||||
const cmd = cmds[i++];
|
||||
conn.exec(cmd, (err, s) => {
|
||||
if (err) { console.error(err.message); run(); return; }
|
||||
s.on('data', d => process.stdout.write(d.toString()))
|
||||
.stderr.on('data', d => process.stdout.write(d.toString()))
|
||||
.on('close', run);
|
||||
});
|
||||
}
|
||||
run();
|
||||
}).on('error', e => console.error(e.message))
|
||||
.connect({ host: '103.185.47.52', port: 2222, username: 'adminbackend', password: 'htEo7x6LsBQiEHHH', readyTimeout: 30000 });
|
||||
@@ -1,44 +0,0 @@
|
||||
const { Client } = require('ssh2');
|
||||
|
||||
const conn = new Client();
|
||||
conn.on('ready', () => {
|
||||
// Execute a shell script on remote server
|
||||
conn.exec(`python3 -c "
|
||||
import os, re
|
||||
|
||||
root = '/home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/.next/server/app/(dashboard)'
|
||||
|
||||
for dirpath, dirnames, filenames in os.walk(root):
|
||||
for f in filenames:
|
||||
if f.endswith('.html') or f.endswith('.js'):
|
||||
full = os.path.join(dirpath, f)
|
||||
rel = os.path.relpath(full, root)
|
||||
try:
|
||||
content = open(full, 'r', encoding='utf-8', errors='ignore').read()
|
||||
|
||||
h2s = re.findall(r'<h[12][^>]*>(.*?)</h[12]>', content)
|
||||
clean_h2s = [re.sub(r'<[^>]+>', '', h).strip() for h in h2s if h.strip()]
|
||||
|
||||
has_learn = 'Learn This Page' in content
|
||||
|
||||
if clean_h2s or has_learn:
|
||||
print(f'Route File: {rel}')
|
||||
print(f' Headers: {\" | \".join(clean_h2s)}')
|
||||
print(f' Learn This Page Button: {has_learn}')
|
||||
print('-' * 40)
|
||||
except Exception as e:
|
||||
pass
|
||||
"`, (err, stream) => {
|
||||
let out = '';
|
||||
stream.on('data', d => out += d);
|
||||
stream.on('close', () => {
|
||||
console.log(out);
|
||||
conn.end();
|
||||
});
|
||||
});
|
||||
}).connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
@@ -1,95 +0,0 @@
|
||||
const { spawn } = require('child_process');
|
||||
const http = require('http');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const jwt = require('jsonwebtoken');
|
||||
const mongoose = require('mongoose');
|
||||
const WebSocket = require('next/dist/compiled/ws');
|
||||
|
||||
require('dotenv').config({ path: path.join(__dirname, '..', '.env.local') });
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'backone-dpi-secret-jwt-key-2024';
|
||||
const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017/backone_dpi';
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
await mongoose.connect(MONGODB_URI);
|
||||
const db = mongoose.connection.db;
|
||||
const users = db.collection('users');
|
||||
|
||||
let adminUser = await users.findOne({ username: 'admin' });
|
||||
const payload = {
|
||||
userId: adminUser._id.toString(),
|
||||
username: adminUser.username,
|
||||
role: adminUser.role,
|
||||
site_uuid: adminUser.site_uuid || 'default',
|
||||
agent_uuid: adminUser.agent_uuid || null
|
||||
};
|
||||
|
||||
const token = jwt.sign(payload, JWT_SECRET, { expiresIn: '1h' });
|
||||
await mongoose.disconnect();
|
||||
|
||||
const edgePath = "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe";
|
||||
const edgeProc = spawn(edgePath, [
|
||||
'--headless',
|
||||
'--disable-gpu',
|
||||
'--remote-debugging-port=9222',
|
||||
'--window-size=400,844',
|
||||
'http://localhost:3000/'
|
||||
]);
|
||||
|
||||
await new Promise(r => setTimeout(r, 2500));
|
||||
|
||||
const targets = await new Promise((resolve, reject) => {
|
||||
http.get('http://127.0.0.1:9222/json', (res) => {
|
||||
let body = '';
|
||||
res.on('data', c => body += c);
|
||||
res.on('end', () => resolve(JSON.parse(body)));
|
||||
}).on('error', reject);
|
||||
});
|
||||
|
||||
const pageTarget = targets.find(t => t.type === 'page');
|
||||
if (!pageTarget || !pageTarget.webSocketDebuggerUrl) {
|
||||
edgeProc.kill();
|
||||
return;
|
||||
}
|
||||
|
||||
const ws = new WebSocket(pageTarget.webSocketDebuggerUrl);
|
||||
let messageId = 1;
|
||||
const send = (method, params = {}) => {
|
||||
return new Promise((res) => {
|
||||
const id = messageId++;
|
||||
const handler = (data) => {
|
||||
const msg = JSON.parse(data);
|
||||
if (msg.id === id) {
|
||||
ws.removeListener('message', handler);
|
||||
res(msg.result);
|
||||
}
|
||||
};
|
||||
ws.on('message', handler);
|
||||
ws.send(JSON.stringify({ id, method, params }));
|
||||
});
|
||||
};
|
||||
|
||||
ws.on('open', async () => {
|
||||
await send('Network.setCookie', { name: 'token', value: token, domain: 'localhost', path: '/' });
|
||||
await send('Network.setCookie', { name: 'backone_token', value: token, domain: 'localhost', path: '/' });
|
||||
|
||||
await send('Page.navigate', { url: 'http://localhost:3000/' });
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
|
||||
const screenshot = await send('Page.captureScreenshot', { format: 'png', captureBeyondViewport: true });
|
||||
const outputPath = "C:\\Users\\rafif\\.gemini\\antigravity-ide\\brain\\d6704840-c7e7-4558-b215-0fe98bbfb07a\\mobile-full-dashboard-live.png";
|
||||
fs.writeFileSync(outputPath, Buffer.from(screenshot.data, 'base64'));
|
||||
console.log("Full page screenshot saved to:", outputPath, "Size:", fs.statSync(outputPath).size, "bytes");
|
||||
|
||||
ws.close();
|
||||
edgeProc.kill();
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
console.error("Error:", err.message);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,174 +0,0 @@
|
||||
// scripts/restore-proxy.js
|
||||
// Pulihkan proxy.php + htaccess yang rusak via SFTP
|
||||
'use strict';
|
||||
|
||||
const SftpClient = require('ssh2-sftp-client');
|
||||
const { Client } = require('ssh2');
|
||||
const https = require('https');
|
||||
|
||||
const CONFIG = {
|
||||
host: '103.185.47.52', port: 2222,
|
||||
username: 'adminbackend', password: 'htEo7x6LsBQiEHHH',
|
||||
readyTimeout: 60000
|
||||
};
|
||||
|
||||
const ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
|
||||
// ── PHP Proxy (forward semua ke Next.js port 3000) ──────────────────────
|
||||
const PROXY_PHP = `<?php
|
||||
/**
|
||||
* BackOne DPI - PHP Reverse Proxy
|
||||
* Meneruskan semua request ke Next.js port 3000
|
||||
*/
|
||||
define('NEXTJS_URL', 'http://127.0.0.1:3000');
|
||||
|
||||
$uri = $_SERVER['REQUEST_URI'] ?? '/';
|
||||
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
|
||||
$target = NEXTJS_URL . $uri;
|
||||
|
||||
$fwdHeaders = [
|
||||
'X-Forwarded-For: ' . ($_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1'),
|
||||
'X-Forwarded-Proto: https',
|
||||
'X-Real-IP: ' . ($_SERVER['REMOTE_ADDR'] ?? ''),
|
||||
'Host: ' . ($_SERVER['HTTP_HOST'] ?? 'demoplace.my.id'),
|
||||
];
|
||||
|
||||
$allHeaders = getallheaders() ?: [];
|
||||
$skip = ['host','connection','transfer-encoding','keep-alive','content-length'];
|
||||
foreach ($allHeaders as $name => $value) {
|
||||
if (!in_array(strtolower($name), $skip)) {
|
||||
$fwdHeaders[] = "$name: $value";
|
||||
}
|
||||
}
|
||||
|
||||
$body = in_array($method, ['POST','PUT','PATCH','DELETE']) ? file_get_contents('php://input') : null;
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => $target,
|
||||
CURLOPT_CUSTOMREQUEST => $method,
|
||||
CURLOPT_HTTPHEADER => $fwdHeaders,
|
||||
CURLOPT_POSTFIELDS => $body,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_HEADER => true,
|
||||
CURLOPT_FOLLOWLOCATION => false,
|
||||
CURLOPT_TIMEOUT => 30,
|
||||
CURLOPT_CONNECTTIMEOUT => 5,
|
||||
CURLOPT_ENCODING => '',
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||
$curlError = curl_error($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if ($response === false) {
|
||||
http_response_code(502);
|
||||
header('Content-Type: text/plain');
|
||||
echo 'BackOne: Gagal terhubung ke Next.js. Error: ' . $curlError;
|
||||
exit;
|
||||
}
|
||||
|
||||
$responseHeaders = substr($response, 0, $headerSize);
|
||||
$responseBody = substr($response, $headerSize);
|
||||
|
||||
http_response_code($httpCode ?: 200);
|
||||
|
||||
$skipRes = ['transfer-encoding','connection','keep-alive','content-encoding'];
|
||||
foreach (explode("\\r\\n", $responseHeaders) as $header) {
|
||||
$header = trim($header);
|
||||
if (empty($header) || preg_match('/^HTTP\\//i', $header)) continue;
|
||||
$colonPos = strpos($header, ':');
|
||||
if ($colonPos === false) continue;
|
||||
$headerName = strtolower(trim(substr($header, 0, $colonPos)));
|
||||
if (in_array($headerName, $skipRes)) continue;
|
||||
header($header, false);
|
||||
}
|
||||
|
||||
echo $responseBody;
|
||||
`;
|
||||
|
||||
// ── .htaccess (routing ke proxy.php) ──────────────────────────────────
|
||||
const HTACCESS = `# BackOne DPI — Apache .htaccess
|
||||
# Redirect HTTP ke HTTPS
|
||||
RewriteEngine On
|
||||
RewriteCond %{HTTPS} !=on
|
||||
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
|
||||
|
||||
# Static Next.js files: sajikan langsung dari disk
|
||||
RewriteCond %{REQUEST_FILENAME} -f
|
||||
RewriteRule ^ - [L]
|
||||
|
||||
# Semua request lain: teruskan ke PHP proxy (Next.js port 3000)
|
||||
RewriteRule ^(.*)$ /proxy.php [L,QSA]
|
||||
`;
|
||||
|
||||
async function main() {
|
||||
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
||||
console.log('║ BackOne DPI — Pulihkan proxy.php & .htaccess ║');
|
||||
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
||||
|
||||
// ── Upload via SFTP ──────────────────────────────────────────────────
|
||||
console.log('▶ Upload proxy.php dan .htaccess via SFTP...');
|
||||
const sftp = new SftpClient();
|
||||
await sftp.connect(CONFIG);
|
||||
|
||||
await sftp.put(Buffer.from(PROXY_PHP, 'utf8'), `${ROOT}/proxy.php`);
|
||||
console.log(' ✅ proxy.php diupload');
|
||||
|
||||
await sftp.put(Buffer.from(HTACCESS, 'utf8'), `${ROOT}/.htaccess`);
|
||||
console.log(' ✅ .htaccess diupload (dengan newline yang benar)');
|
||||
|
||||
await sftp.end();
|
||||
|
||||
// ── Verifikasi via SSH ───────────────────────────────────────────────
|
||||
console.log('\n▶ Verifikasi di server...');
|
||||
const conn = new Client();
|
||||
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(CONFIG); });
|
||||
console.log('[SSH] Terhubung!\n');
|
||||
|
||||
await new Promise((resolve) => {
|
||||
conn.exec(
|
||||
`echo "=== .htaccess ===" && cat ${ROOT}/.htaccess && ` +
|
||||
`echo "" && echo "=== proxy.php (5 baris awal) ===" && head -5 ${ROOT}/proxy.php && ` +
|
||||
`echo "" && echo "=== Test port 3000 ===" && curl -sk -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/login && echo "" && ` +
|
||||
`echo "=== Test port 8009/8080 ===" && curl -sk -o /dev/null -w "Apache 8009: %{http_code}" http://127.0.0.1:8009/ && echo "" && curl -sk -o /dev/null -w "Apache 8080: %{http_code}" http://103.185.47.52:8080/login && echo ""`,
|
||||
(err, s) => {
|
||||
if (err) { resolve(); return; }
|
||||
s.on('data', d => process.stdout.write(d.toString()))
|
||||
.stderr.on('data', d => process.stdout.write(d.toString()))
|
||||
.on('close', () => { resolve(); });
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
conn.end();
|
||||
|
||||
// ── Test external ────────────────────────────────────────────────────
|
||||
console.log('\n▶ Test domain dari luar (tunggu 3 detik)...');
|
||||
await new Promise(r => setTimeout(r, 3000));
|
||||
|
||||
for (const path of ['/', '/login', '/api/health']) {
|
||||
const r = await new Promise(resolve => {
|
||||
const req = https.get(`https://demoplace.my.id${path}`,
|
||||
{ timeout: 12000, rejectUnauthorized: false },
|
||||
res => {
|
||||
let body = '';
|
||||
res.on('data', d => body += d);
|
||||
res.on('end', () => resolve({ status: res.statusCode, body: body.substring(0, 80), 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 = r.status === 200 ? '✅' : r.status === 301 || r.status === 307 ? '↩️ ' : '❌';
|
||||
console.log(` ${icon} https://demoplace.my.id${path} → HTTP ${r.status} ${r.error || ''}`);
|
||||
if (r.location) console.log(` → ${r.location}`);
|
||||
}
|
||||
|
||||
console.log('\n✅ Selesai! Refresh https://demoplace.my.id/login\n');
|
||||
}
|
||||
|
||||
main().catch(err => { console.error('[FATAL]', err.message); process.exit(1); });
|
||||
@@ -1,80 +0,0 @@
|
||||
const SftpClient = require('ssh2-sftp-client');
|
||||
const { Client } = require('ssh2');
|
||||
|
||||
const remoteScanScript = `
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const root = '/home/adminbackend/web/demoplace.my.id/public_html/.next';
|
||||
|
||||
const targetTitles = [
|
||||
'Overview Dashboard',
|
||||
'Summary Overview',
|
||||
'DPI MetaData',
|
||||
'BackOne Metadata',
|
||||
'Network Topology',
|
||||
'Network Infrastructure',
|
||||
'Traffic Categories',
|
||||
'Threat Intelligence',
|
||||
'Detected Threats',
|
||||
'App Lookup',
|
||||
'Application Database',
|
||||
'Encryption Audit',
|
||||
'Security & Encryption Audit'
|
||||
];
|
||||
|
||||
console.log('=== MATCHING TARGET TITLES IN REMOTE NEXT BUILD ===\\n');
|
||||
|
||||
function scan(dir) {
|
||||
if (!fs.existsSync(dir)) return;
|
||||
const items = fs.readdirSync(dir, { withFileTypes: true });
|
||||
for (const item of items) {
|
||||
const full = path.join(dir, item.name);
|
||||
if (item.isDirectory()) {
|
||||
scan(full);
|
||||
} else if (item.name.endsWith('.js') || item.name.endsWith('.html')) {
|
||||
const content = fs.readFileSync(full, 'utf8');
|
||||
targetTitles.forEach(t => {
|
||||
if (content.includes(t)) {
|
||||
console.log(\`Found "\${t}" in file: \${path.relative(root, full)}\`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scan(root);
|
||||
`;
|
||||
|
||||
async function main() {
|
||||
const sftp = new SftpClient();
|
||||
await sftp.connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
|
||||
const remoteScriptPath = '/home/adminbackend/scan_strings.js';
|
||||
await sftp.put(Buffer.from(remoteScanScript), remoteScriptPath);
|
||||
await sftp.end();
|
||||
|
||||
const conn = new Client();
|
||||
conn.on('ready', () => {
|
||||
conn.exec(`node ${remoteScriptPath}`, (err, stream) => {
|
||||
let out = '';
|
||||
stream.on('data', d => out += d);
|
||||
stream.on('close', () => {
|
||||
console.log(out);
|
||||
conn.end();
|
||||
});
|
||||
});
|
||||
}).connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,26 +0,0 @@
|
||||
const { Client } = require('ssh2');
|
||||
|
||||
const conn = new Client();
|
||||
conn.on('ready', () => {
|
||||
conn.exec(`grep -rn "Overview Dashboard" /home/adminbackend/web/demoplace.my.id/public_html/ /home/adminbackend/backone-production/ 2>/dev/null | head -n 30`, (err, stream) => {
|
||||
let out = '';
|
||||
stream.on('data', d => out += d);
|
||||
stream.on('close', () => {
|
||||
console.log('=== SEARCH Overview Dashboard ===\n' + out);
|
||||
|
||||
conn.exec(`grep -rn "DPI MetaData" /home/adminbackend/web/demoplace.my.id/public_html/ /home/adminbackend/backone-production/ 2>/dev/null | head -n 30`, (err2, stream2) => {
|
||||
let out2 = '';
|
||||
stream2.on('data', d => out2 += d);
|
||||
stream2.on('close', () => {
|
||||
console.log('=== SEARCH DPI MetaData ===\n' + out2);
|
||||
conn.end();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}).connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
@@ -1,153 +0,0 @@
|
||||
// scripts/security-fix.js
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// BackOne DPI — Security fix & final production configuration
|
||||
// 1. Remove .env.production from standalone directory (security)
|
||||
// 2. Fix PM2 to use new ecosystem config properly
|
||||
// 3. Verify HTTPS redirect and domain reachability
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
'use strict';
|
||||
|
||||
const { Client: SshClient } = require('ssh2');
|
||||
const https = require('https');
|
||||
const http = require('http');
|
||||
|
||||
const CONFIG = {
|
||||
host: process.env.SSH_HOST || '127.0.0.1',
|
||||
port: parseInt(process.env.SSH_PORT || '2222'),
|
||||
username: process.env.SSH_USER || 'adminbackend',
|
||||
password: process.env.SSH_PASSWORD || '',
|
||||
};
|
||||
|
||||
const ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
|
||||
|
||||
const COMMANDS = [
|
||||
// ── CRITICAL SECURITY: Remove .env files from Next.js standalone build ────
|
||||
`echo "=== SECURITY FIX: Remove .env from standalone ==="`,
|
||||
`rm -f ${ROOT}/.next/standalone/.env.production && echo "REMOVED: .env.production from standalone"`,
|
||||
`rm -f ${ROOT}/.next/standalone/.env.local && echo "REMOVED: .env.local from standalone (if existed)"`,
|
||||
|
||||
// Verify removal
|
||||
`echo "=== VERIFY: No .env in standalone ===" && find ${ROOT}/.next/standalone -name ".env*" 2>/dev/null | head -5 || echo "CLEAN: No .env files in standalone"`,
|
||||
|
||||
// Also check if any secrets in the static JS bundles (client-side code)
|
||||
`echo "=== VERIFY: No API key in client JS ===" && grep -r "sk_db_live" ${ROOT}/.next/static/ 2>/dev/null | head -3 || echo "CLEAN: No Netify API key in client-side JS"`,
|
||||
`echo "=== VERIFY: No MongoDB creds in client JS ===" && grep -r "SusuKudaLiar" ${ROOT}/.next/static/ 2>/dev/null | head -3 || echo "CLEAN: No MongoDB password in client-side JS"`,
|
||||
`echo "=== VERIFY: No JWT_SECRET in client JS ===" && grep -r "1a1716874d7576" ${ROOT}/.next/static/ 2>/dev/null | head -3 || echo "CLEAN: No JWT secret in client-side JS"`,
|
||||
|
||||
// ── Update the deploy script to prevent future accidental uploads ─────────
|
||||
// Make .env.production NOT included in standalone (it shouldn't be anyway)
|
||||
`echo "=== Checking if standalone has package.json with correct env ===" && cat ${ROOT}/.next/standalone/package.json 2>/dev/null | head -5`,
|
||||
|
||||
// ── Fix ecosystem.config.js to use correct cwd and path ──────────────────
|
||||
// The PM2 frontend shows version 0.1.0 (old package.json from inside standalone)
|
||||
// The cwd in ecosystem.config.js points to the root, which is correct
|
||||
`echo "=== Current ecosystem.config.js ===" && cat ${ROOT}/ecosystem.config.js`,
|
||||
|
||||
// ── Restart PM2 frontend with updated ecosystem config ────────────────────
|
||||
`echo "=== Restart frontend with updated config ===" && cd ${ROOT} && NODE_ENV=production ${PM2} restart backone-frontend --update-env && echo "Frontend restarted"`,
|
||||
|
||||
// Wait for stabilization
|
||||
`sleep 5`,
|
||||
|
||||
// ── Full health check ─────────────────────────────────────────────────────
|
||||
`echo "=== FINAL PM2 STATUS ===" && ${PM2} list`,
|
||||
|
||||
// Internal endpoint checks
|
||||
`echo "=== BACKEND /api/health ===" && curl -s http://127.0.0.1:3001/api/health`,
|
||||
`echo "=== FRONTEND / ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/`,
|
||||
`echo "=== FRONTEND /login ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/login`,
|
||||
|
||||
// ── Test login API endpoint ────────────────────────────────────────────────
|
||||
`echo ""`,
|
||||
`echo "=== TEST LOGIN API ===" && curl -s -X POST http://127.0.0.1:3001/api/auth/login -H "Content-Type: application/json" -d '{"username":"admin","password":"admin"}' | head -c 200`,
|
||||
|
||||
// ── Show proxy MongoDB connection ─────────────────────────────────────────
|
||||
`echo ""`,
|
||||
`echo "=== PROXY MONGODB STATUS ===" && ${PM2} logs backone-proxy --lines 20 --nostream 2>&1 | grep -E "(MongoDB|Connected|Capacity|Scheduler|Started|Mode)" | tail -10`,
|
||||
|
||||
// ── Check if cPanel is configured to serve on port 8083 ──────────────────
|
||||
`echo "=== CPANEL PORT CHECK ===" && ss -tlnp 2>/dev/null | grep -E "(8083|80|443|3000)" | head -10`,
|
||||
|
||||
// ── Check Apache/nginx proxy config ──────────────────────────────────────
|
||||
`echo "=== CHECK PROXY CONFIG ===" && cat /home/adminbackend/.htaccess 2>/dev/null | head -20 || echo "No .htaccess at home"`,
|
||||
`echo "=== CHECK WEB ROOT HTACCESS ===" && cat ${ROOT}/.htaccess 2>/dev/null | head -20 || echo "No .htaccess in web root"`,
|
||||
|
||||
// ── Summary ───────────────────────────────────────────────────────────────
|
||||
`echo ""`,
|
||||
`echo "╔══════════════════════════════════════════════════════╗"`,
|
||||
`echo "║ BackOne DPI — Security & Health Verification ║"`,
|
||||
`echo "╠══════════════════════════════════════════════════════╣"`,
|
||||
`echo "║ ✅ Backend : http://127.0.0.1:3001 (internal) ║"`,
|
||||
`echo "║ ✅ Proxy : http://127.0.0.1:4000 (internal) ║"`,
|
||||
`echo "║ ✅ Frontend : http://127.0.0.1:3000 (internal) ║"`,
|
||||
`echo "║ ✅ MongoDB : mongodb.prod.proit.id:27017 ║"`,
|
||||
`echo "║ 🌐 Domain : https://demoplace.my.id ║"`,
|
||||
`echo "╚══════════════════════════════════════════════════════╝"`,
|
||||
];
|
||||
|
||||
function runSsh(commands) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const ssh = new SshClient();
|
||||
ssh.on('ready', () => {
|
||||
console.log('[SSH] Connected!\n');
|
||||
let i = 0;
|
||||
function next() {
|
||||
if (i >= commands.length) { ssh.end(); return; }
|
||||
const cmd = commands[i++];
|
||||
console.log(`\n$ ${cmd.substring(0, 130)}${cmd.length > 130 ? '...' : ''}`);
|
||||
ssh.exec(cmd, (err, stream) => {
|
||||
if (err) { console.error('[ERR]', err.message); next(); return; }
|
||||
stream.on('data', d => process.stdout.write(d.toString()));
|
||||
stream.stderr.on('data', d => { const t = d.toString(); if (!t.includes('npm warn') && !t.includes('notice')) process.stdout.write(t); });
|
||||
stream.on('close', next);
|
||||
});
|
||||
}
|
||||
next();
|
||||
ssh.on('end', resolve);
|
||||
});
|
||||
ssh.on('error', reject);
|
||||
ssh.connect({ ...CONFIG, readyTimeout: 30000 });
|
||||
});
|
||||
}
|
||||
|
||||
// Check HTTPS domain
|
||||
function checkHttps(url) {
|
||||
return new Promise(resolve => {
|
||||
const req = https.get(url, { timeout: 10000, rejectUnauthorized: false }, res => {
|
||||
let body = '';
|
||||
res.on('data', d => body += d);
|
||||
res.on('end', () => resolve({ status: res.statusCode, body: body.substring(0, 200), location: res.headers.location }));
|
||||
});
|
||||
req.on('error', e => resolve({ status: 0, error: e.message }));
|
||||
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
||||
console.log('║ BackOne DPI — Security Fix & Final Verification ║');
|
||||
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
||||
|
||||
await runSsh(COMMANDS);
|
||||
|
||||
// Check HTTPS
|
||||
console.log('\n▶ Testing HTTPS access...\n');
|
||||
const urls = [
|
||||
'https://demoplace.my.id/',
|
||||
'https://demoplace.my.id/login',
|
||||
'https://demoplace.my.id/api/health',
|
||||
];
|
||||
|
||||
for (const url of urls) {
|
||||
const r = await checkHttps(url);
|
||||
const icon = r.status >= 200 && r.status < 400 ? '✅' : r.status === 0 ? '⚠️' : '❌';
|
||||
console.log(` ${icon} ${url} → HTTP ${r.status} ${r.error || ''}`);
|
||||
if (r.location) console.log(` Redirects to: ${r.location}`);
|
||||
if (r.body && r.status === 200) console.log(` Body: ${r.body.substring(0, 80)}...`);
|
||||
}
|
||||
|
||||
console.log('\n✅ Security fix & verification complete!\n');
|
||||
}
|
||||
|
||||
main().catch(err => { console.error('[FATAL]', err); process.exit(1); });
|
||||
@@ -1,123 +0,0 @@
|
||||
// scripts/server-setup.js
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// BackOne DPI — Server Investigation & PM2 Setup Script
|
||||
// Runs SSH commands to check server state and install PM2 locally
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
'use strict';
|
||||
|
||||
const { Client: SshClient } = require('ssh2');
|
||||
|
||||
const CONFIG = {
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH',
|
||||
};
|
||||
|
||||
const REMOTE_ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
|
||||
// Commands to investigate server state, install PM2 locally, and start all services
|
||||
const COMMANDS = [
|
||||
// 1. Check Node.js version and PATH
|
||||
'echo "=== NODE VERSION ===" && node --version 2>&1 || echo "node not in PATH"',
|
||||
'echo "=== NPM VERSION ===" && npm --version 2>&1 || echo "npm not in PATH"',
|
||||
'echo "=== CURRENT PATH ===" && echo $PATH',
|
||||
'echo "=== HOME DIR ===" && echo $HOME',
|
||||
|
||||
// 2. Find any existing pm2 installation
|
||||
'echo "=== FIND PM2 ===" && which pm2 2>/dev/null || find /home/adminbackend -name "pm2" -type f 2>/dev/null | head -5 || echo "pm2 not found"',
|
||||
'echo "=== NPM GLOBAL LIST ===" && npm list -g --depth=0 2>&1 | head -20',
|
||||
|
||||
// 3. Check currently running Node.js processes
|
||||
'echo "=== RUNNING NODE PROCESSES ===" && ps aux | grep node | grep -v grep || echo "No node processes running"',
|
||||
|
||||
// 4. Check if cPanel Node.js App is configured
|
||||
'echo "=== CPANEL NODEAPP CONFIG ===" && ls /home/adminbackend/.cpanel/ 2>/dev/null || ls /home/adminbackend/nodevenv/ 2>/dev/null || echo "No cPanel node venv found"',
|
||||
'echo "=== NODE VENV CHECK ===" && ls /home/adminbackend/nodevenv/ 2>/dev/null | head -10 || echo "No nodevenv"',
|
||||
|
||||
// 5. Install PM2 locally to user home prefix (no root needed)
|
||||
'echo "=== INSTALLING PM2 LOCALLY ===" && npm install pm2 --prefix /home/adminbackend/.local 2>&1 | tail -5',
|
||||
'echo "=== PM2 PATH ===" && /home/adminbackend/.local/bin/pm2 --version 2>&1 || echo "pm2 local install failed"',
|
||||
|
||||
// 6. Kill any existing BackOne processes to avoid port conflicts
|
||||
`echo "=== KILLING EXISTING PROCESSES ===" && pkill -f "proxy/index.js" 2>/dev/null || true && pkill -f "backend/server.js" 2>/dev/null || true && pkill -f "standalone/server.js" 2>/dev/null || true && sleep 2 && echo "Done"`,
|
||||
|
||||
// 7. Start backend server
|
||||
`echo "=== STARTING BACKEND ===" && cd ${REMOTE_ROOT} && NODE_ENV=production $(cat .env.production | grep -v '^#' | grep -v '^$' | xargs) node backend/server.js > logs/backend-out.log 2>logs/backend-error.log &`,
|
||||
|
||||
// 8. Start proxy server
|
||||
`echo "=== STARTING PROXY ===" && cd ${REMOTE_ROOT} && NODE_ENV=production node proxy/index.js > logs/proxy-out.log 2>logs/proxy-error.log &`,
|
||||
|
||||
// 9. Start Next.js frontend
|
||||
`echo "=== STARTING FRONTEND ===" && cd ${REMOTE_ROOT} && NODE_ENV=production PORT=3000 HOSTNAME=127.0.0.1 node .next/standalone/server.js > logs/frontend-out.log 2>logs/frontend-error.log &`,
|
||||
|
||||
// 10. Wait and verify
|
||||
'sleep 6',
|
||||
|
||||
// 11. Check processes
|
||||
'echo "=== RUNNING PROCESSES AFTER START ===" && ps aux | grep node | grep -v grep',
|
||||
|
||||
// 12. Test health endpoints
|
||||
'echo "=== BACKEND HEALTH ===" && curl -s http://127.0.0.1:3001/api/health 2>&1 || echo "Backend not responding"',
|
||||
'echo "=== FRONTEND HEALTH ===" && curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:3000/ 2>&1 || echo "Frontend not responding"',
|
||||
|
||||
// 13. Show recent logs
|
||||
'echo "=== BACKEND LOG (last 10 lines) ===" && tail -10 /home/adminbackend/web/demoplace.my.id/public_html/logs/backend-out.log 2>/dev/null || echo "No backend log"',
|
||||
'echo "=== PROXY LOG (last 5 lines) ===" && tail -5 /home/adminbackend/web/demoplace.my.id/public_html/logs/proxy-out.log 2>/dev/null || echo "No proxy log"',
|
||||
];
|
||||
|
||||
function runSshCommands(commands) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const ssh = new SshClient();
|
||||
|
||||
ssh.on('ready', () => {
|
||||
console.log('[SSH] Connected to server!\n');
|
||||
let index = 0;
|
||||
|
||||
function runNext() {
|
||||
if (index >= commands.length) {
|
||||
console.log('\n[SSH] All commands complete. Disconnecting...');
|
||||
ssh.end();
|
||||
return;
|
||||
}
|
||||
|
||||
const cmd = commands[index++];
|
||||
console.log(`\n$ ${cmd.substring(0, 100)}${cmd.length > 100 ? '...' : ''}`);
|
||||
|
||||
ssh.exec(cmd, (err, stream) => {
|
||||
if (err) {
|
||||
console.error(`[ERROR] ${err.message}`);
|
||||
runNext();
|
||||
return;
|
||||
}
|
||||
|
||||
stream.on('data', (data) => process.stdout.write(data.toString()));
|
||||
stream.stderr.on('data', (data) => process.stdout.write(`[ERR] ${data}`));
|
||||
stream.on('close', () => runNext());
|
||||
});
|
||||
}
|
||||
|
||||
runNext();
|
||||
ssh.on('end', resolve);
|
||||
});
|
||||
|
||||
ssh.on('error', reject);
|
||||
ssh.connect({ ...CONFIG, readyTimeout: 30000 });
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('\n╔══════════════════════════════════════════════════╗');
|
||||
console.log('║ BackOne DPI — Server Setup & Process Manager ║');
|
||||
console.log('╚══════════════════════════════════════════════════╝\n');
|
||||
|
||||
try {
|
||||
await runSshCommands(COMMANDS);
|
||||
console.log('\n✅ Server setup complete!\n');
|
||||
} catch (err) {
|
||||
console.error('\n[FATAL]', err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,133 +0,0 @@
|
||||
// scripts/start-frontend.js
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// BackOne DPI — Start Frontend & Fix PM2 Setup on Server
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
'use strict';
|
||||
|
||||
const { Client: SshClient } = require('ssh2');
|
||||
|
||||
const CONFIG = {
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH',
|
||||
};
|
||||
|
||||
const REMOTE_ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
|
||||
const COMMANDS = [
|
||||
// Check what's currently running on port 3000
|
||||
'echo "=== PORT 3000 CHECK ===" && ss -tlnp 2>/dev/null | grep 3000 || netstat -tlnp 2>/dev/null | grep 3000 || echo "Port 3000 not in use"',
|
||||
|
||||
// Check if standalone server.js exists
|
||||
`echo "=== STANDALONE CHECK ===" && ls -la ${REMOTE_ROOT}/.next/standalone/server.js 2>/dev/null || echo "standalone server.js NOT FOUND"`,
|
||||
|
||||
// List standalone directory structure
|
||||
`echo "=== STANDALONE DIRECTORY ===" && ls ${REMOTE_ROOT}/.next/standalone/ 2>/dev/null | head -20`,
|
||||
|
||||
// Check static assets copied correctly
|
||||
`echo "=== STATIC IN STANDALONE ===" && ls ${REMOTE_ROOT}/.next/standalone/.next/ 2>/dev/null || echo "No .next dir in standalone"`,
|
||||
|
||||
// Find the correct npm bin directory for npx pm2
|
||||
'echo "=== NPM BIN DIR ===" && npm bin 2>/dev/null || npm config get prefix',
|
||||
|
||||
// Check npx pm2 path
|
||||
'echo "=== NPX PM2 PATH ===" && find /home/adminbackend/.npm -name "pm2" -type f 2>/dev/null | grep "/bin/pm2" | head -3',
|
||||
|
||||
// Install PM2 using npm to user's npm prefix
|
||||
'echo "=== SET NPM PREFIX ===" && npm config set prefix /home/adminbackend/.npm-global && npm install -g pm2 2>&1 | tail -5',
|
||||
'echo "=== PM2 INSTALLED ===" && /home/adminbackend/.npm-global/bin/pm2 --version 2>&1 || echo "Still not found"',
|
||||
|
||||
// Try npx approach
|
||||
`echo "=== USING NPX PM2 ===" && cd ${REMOTE_ROOT} && npx pm2 --version 2>&1`,
|
||||
|
||||
// Start frontend standalone server if not running
|
||||
`echo "=== CHECKING STANDALONE SERVER ===" && ls -la ${REMOTE_ROOT}/.next/standalone/server.js`,
|
||||
|
||||
// Start with nohup (works on cPanel)
|
||||
`echo "=== STARTING FRONTEND NOHUP ===" && cd ${REMOTE_ROOT} && NODE_ENV=production PORT=3000 HOSTNAME=0.0.0.0 NEXT_PUBLIC_API_URL=http://127.0.0.1:3001 nohup node .next/standalone/server.js >> logs/frontend-out.log 2>&1 & echo "PID: $!"`,
|
||||
|
||||
// Wait and check
|
||||
'sleep 5',
|
||||
|
||||
// Verify port 3000 is now listening
|
||||
'echo "=== PORT 3000 AFTER START ===" && ss -tlnp | grep 3000 || netstat -tlnp | grep 3000 || echo "Port 3000 still not in use"',
|
||||
|
||||
// Check all running processes
|
||||
'echo "=== ALL NODE PROCESSES ===" && ps aux | grep node | grep -v grep',
|
||||
|
||||
// Test all endpoints
|
||||
'echo "=== BACKEND HEALTH ===" && curl -s http://127.0.0.1:3001/api/health',
|
||||
'echo "=== FRONTEND RESPONSE ===" && curl -s -o /dev/null -w "HTTP Status: %{http_code}" http://127.0.0.1:3000/ 2>&1',
|
||||
|
||||
// Show frontend log
|
||||
`echo "=== FRONTEND LOG ===" && tail -20 ${REMOTE_ROOT}/logs/frontend-out.log 2>/dev/null || echo "No frontend log"`,
|
||||
|
||||
// Check proxy connection to MongoDB
|
||||
`echo "=== PROXY LOG ===" && tail -10 ${REMOTE_ROOT}/logs/proxy-out.log 2>/dev/null || echo "No proxy log"`,
|
||||
|
||||
// Show existing pm2 in npx cache and start all services via npx pm2
|
||||
`echo "=== STARTING WITH NPX PM2 ===" && cd ${REMOTE_ROOT} && NODE_ENV=production npx pm2 list 2>&1 | head -20`,
|
||||
];
|
||||
|
||||
function runSshCommands(commands) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const ssh = new SshClient();
|
||||
const results = [];
|
||||
|
||||
ssh.on('ready', () => {
|
||||
console.log('[SSH] Connected!\n');
|
||||
let index = 0;
|
||||
|
||||
function runNext() {
|
||||
if (index >= commands.length) {
|
||||
ssh.end();
|
||||
return;
|
||||
}
|
||||
|
||||
const cmd = commands[index++];
|
||||
const preview = cmd.length > 120 ? cmd.substring(0, 120) + '...' : cmd;
|
||||
console.log(`\n$ ${preview}`);
|
||||
|
||||
ssh.exec(cmd, { env: { PATH: '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' } }, (err, stream) => {
|
||||
if (err) {
|
||||
console.error(`[ERROR] ${err.message}`);
|
||||
runNext();
|
||||
return;
|
||||
}
|
||||
|
||||
stream.on('data', (data) => process.stdout.write(data.toString()));
|
||||
stream.stderr.on('data', (data) => {
|
||||
const text = data.toString();
|
||||
if (!text.includes('npm warn') && !text.includes('npm notice')) {
|
||||
process.stdout.write(`[ERR] ${text}`);
|
||||
}
|
||||
});
|
||||
stream.on('close', () => runNext());
|
||||
});
|
||||
}
|
||||
|
||||
runNext();
|
||||
ssh.on('end', () => resolve(results));
|
||||
});
|
||||
|
||||
ssh.on('error', reject);
|
||||
ssh.connect({ ...CONFIG, readyTimeout: 30000 });
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('\n╔══════════════════════════════════════════════════╗');
|
||||
console.log('║ BackOne DPI — Frontend Startup & PM2 Fix ║');
|
||||
console.log('╚══════════════════════════════════════════════════╝\n');
|
||||
|
||||
try {
|
||||
await runSshCommands(COMMANDS);
|
||||
console.log('\n✅ Frontend startup attempt complete!\n');
|
||||
} catch (err) {
|
||||
console.error('\n[FATAL]', err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,93 +0,0 @@
|
||||
const { spawnSync } = require('child_process');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const http = require('http');
|
||||
|
||||
function loginAndGetCookie() {
|
||||
return new Promise((resolve) => {
|
||||
const data = JSON.stringify({ username: 'admin', password: 'admin' });
|
||||
const req = http.request({
|
||||
hostname: '127.0.0.1',
|
||||
port: 3000,
|
||||
path: '/api/auth/login',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': data.length
|
||||
}
|
||||
}, (res) => {
|
||||
let body = '';
|
||||
res.on('data', chunk => body += chunk);
|
||||
res.on('end', () => {
|
||||
console.log("Login HTTP Status:", res.statusCode);
|
||||
const setCookieHeader = res.headers['set-cookie'];
|
||||
if (setCookieHeader && setCookieHeader.length > 0) {
|
||||
const cookieVal = setCookieHeader[0].split(';')[0];
|
||||
console.log("Authenticated Cookie:", cookieVal);
|
||||
resolve(cookieVal);
|
||||
} else {
|
||||
console.log("No Set-Cookie header returned:", body);
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (err) => {
|
||||
console.error("Login request error:", err.message);
|
||||
resolve(null);
|
||||
});
|
||||
|
||||
req.write(data);
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
async function run() {
|
||||
const cookieHeader = await loginAndGetCookie();
|
||||
if (!cookieHeader) {
|
||||
console.error("Failed to authenticate with admin/admin");
|
||||
return;
|
||||
}
|
||||
|
||||
// We can write a small local page or fetch the authenticated pages
|
||||
// Or launch edge with cookie set via devtools protocol or curl
|
||||
console.log("Fetching authenticated HTML for / ...");
|
||||
|
||||
const req = http.request({
|
||||
hostname: '127.0.0.1',
|
||||
port: 3000,
|
||||
path: '/',
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Cookie': cookieHeader
|
||||
}
|
||||
}, (res) => {
|
||||
console.log("Dashboard GET Status:", res.statusCode);
|
||||
});
|
||||
req.end();
|
||||
|
||||
// Save cookie into edge user data folder or launch edge with custom session
|
||||
const userDataDir = path.join(__dirname, 'edge_session_dir');
|
||||
if (!fs.existsSync(userDataDir)) {
|
||||
fs.mkdirSync(userDataDir, { recursive: true });
|
||||
}
|
||||
|
||||
const edgePath = "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe";
|
||||
const outputDir = "C:\\Users\\rafif\\.gemini\\antigravity-ide\\brain\\d6704840-c7e7-4558-b215-0fe98bbfb07a";
|
||||
const outputFile = path.join(outputDir, "mobile-dashboard-overview.png");
|
||||
|
||||
// In order to inject cookie into headless Edge, we can pass --app with cookie or use curl/chrome-remote-interface
|
||||
console.log("Executing Edge capture...");
|
||||
const res = spawnSync(edgePath, [
|
||||
'--headless',
|
||||
'--disable-gpu',
|
||||
`--user-data-dir=${userDataDir}`,
|
||||
'--window-size=400,844',
|
||||
`--screenshot=${outputFile}`,
|
||||
'http://localhost:3000/'
|
||||
], { encoding: 'utf-8', timeout: 15000 });
|
||||
|
||||
console.log("Done! Exit code:", res.status);
|
||||
}
|
||||
|
||||
run();
|
||||
@@ -1,24 +0,0 @@
|
||||
const { spawnSync } = require('child_process');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const edgePath = "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe";
|
||||
const outputDir = "C:\\Users\\rafif\\.gemini\\antigravity-ide\\brain\\d6704840-c7e7-4558-b215-0fe98bbfb07a";
|
||||
const outputFile = path.join(outputDir, "mobile-localhost.png");
|
||||
|
||||
console.log("Launching Edge headless to capture screenshot of http://localhost:3000 ...");
|
||||
|
||||
const res = spawnSync(edgePath, [
|
||||
'--headless',
|
||||
'--disable-gpu',
|
||||
'--window-size=400,844',
|
||||
`--screenshot=${outputFile}`,
|
||||
'http://localhost:3000'
|
||||
], { encoding: 'utf-8', timeout: 15000 });
|
||||
|
||||
console.log("Exit code:", res.status);
|
||||
if (fs.existsSync(outputFile)) {
|
||||
console.log("Screenshot successfully saved to:", outputFile, "Size:", fs.statSync(outputFile).size, "bytes");
|
||||
} else {
|
||||
console.log("Screenshot file not found.");
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
const http = require('http');
|
||||
|
||||
function testUrl(url) {
|
||||
return new Promise((resolve) => {
|
||||
const start = Date.now();
|
||||
console.log(`[TEST] Fetching ${url}...`);
|
||||
const req = http.get(url, { timeout: 5000 }, (res) => {
|
||||
let data = '';
|
||||
res.on('data', (chunk) => { data += chunk; });
|
||||
res.on('end', () => {
|
||||
const duration = Date.now() - start;
|
||||
console.log(`[TEST] ${url} -> Status: ${res.statusCode}, Time: ${duration}ms, Bytes: ${data.length}`);
|
||||
resolve({ url, status: res.statusCode, duration, bytes: data.length });
|
||||
});
|
||||
});
|
||||
req.on('error', (err) => {
|
||||
const duration = Date.now() - start;
|
||||
console.log(`[TEST] ${url} -> ERROR: ${err.message}, Time: ${duration}ms`);
|
||||
resolve({ url, error: err.message, duration });
|
||||
});
|
||||
req.on('timeout', () => {
|
||||
req.destroy();
|
||||
const duration = Date.now() - start;
|
||||
console.log(`[TEST] ${url} -> TIMEOUT after ${duration}ms`);
|
||||
resolve({ url, timeout: true, duration });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function run() {
|
||||
console.log('=== STARTING DASHBOARD ROUTE SPEED TEST ===');
|
||||
await testUrl('http://127.0.0.1:3001/api/dashboard/devices');
|
||||
await testUrl('http://127.0.0.1:3001/api/dashboard/summary');
|
||||
console.log('=== TEST COMPLETE ===');
|
||||
}
|
||||
|
||||
run();
|
||||
@@ -1,28 +0,0 @@
|
||||
|
||||
if (typeof globalThis.crypto === 'undefined') {
|
||||
globalThis.crypto = require('crypto');
|
||||
}
|
||||
const mongoose = require('mongoose');
|
||||
const path = require('path');
|
||||
require('dotenv').config({ path: path.join(__dirname, '..', '.env.production') });
|
||||
|
||||
const MONGODB_URI = process.env.MONGODB_URI;
|
||||
const { collectAllAgents } = require('../proxy/collector');
|
||||
|
||||
async function run() {
|
||||
console.log('[Trigger] Connecting to MongoDB...');
|
||||
await mongoose.connect(MONGODB_URI);
|
||||
console.log('[Trigger] Connected. Starting collection cycle...');
|
||||
try {
|
||||
const res = await collectAllAgents();
|
||||
console.log('[Trigger] Collection cycle finished successfully:', res);
|
||||
} catch (err) {
|
||||
console.error('[Trigger] Collection cycle failed:', err);
|
||||
} finally {
|
||||
await mongoose.connection.close();
|
||||
console.log('[Trigger] MongoDB connection closed.');
|
||||
}
|
||||
}
|
||||
|
||||
run();
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
// scripts/update-pm2-config.js
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// BackOne DPI — Update PM2 to use correct standalone script path
|
||||
// The frontend PM2 process is currently running the OLD server.js from root.
|
||||
// We need to delete and re-create the PM2 process with the correct script.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
'use strict';
|
||||
|
||||
const { Client: SshClient } = require('ssh2');
|
||||
const https = require('https');
|
||||
|
||||
const CONFIG = {
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH',
|
||||
};
|
||||
|
||||
const ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
|
||||
|
||||
const COMMANDS = [
|
||||
// Show current PM2 state
|
||||
`echo "=== CURRENT PM2 STATE ===" && ${PM2} list`,
|
||||
`echo "=== CURRENT FRONTEND SCRIPT ===" && ${PM2} show backone-frontend 2>&1 | grep -E "(script|cwd)" | head -5`,
|
||||
|
||||
// Delete old frontend process and start fresh with correct script
|
||||
`echo "=== DELETING OLD FRONTEND PROCESS ===" && ${PM2} delete backone-frontend && echo "Deleted"`,
|
||||
|
||||
// Start frontend using the new ecosystem config (which points to .next/standalone/server.js)
|
||||
`echo "=== STARTING FRONTEND WITH NEW CONFIG ===" && cd ${ROOT} && NODE_ENV=production ${PM2} start ecosystem.config.js --only backone-frontend && echo "Started"`,
|
||||
|
||||
// Wait for startup
|
||||
`sleep 6`,
|
||||
|
||||
// Verify new process
|
||||
`echo "=== NEW PM2 STATUS ===" && ${PM2} list`,
|
||||
`echo "=== NEW FRONTEND SCRIPT ===" && ${PM2} show backone-frontend 2>&1 | grep -E "(script|cwd|version|status)" | head -8`,
|
||||
|
||||
// Test frontend response
|
||||
`echo "=== FRONTEND INTERNAL TEST ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/`,
|
||||
`echo "=== FRONTEND LOGIN TEST ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/login`,
|
||||
|
||||
// Save PM2 state
|
||||
`echo "=== SAVING PM2 STATE ===" && ${PM2} save && echo "PM2 state saved"`,
|
||||
|
||||
// Show frontend log to confirm new code
|
||||
`echo "=== FRONTEND LOG ===" && ${PM2} logs backone-frontend --lines 10 --nostream 2>&1 | tail -15`,
|
||||
|
||||
// Check HTTPS now
|
||||
`echo "=== HTTPS VIA CURL ===" && curl -s -o /dev/null -w "HTTP %{http_code}" -L --max-redirs 3 https://demoplace.my.id/ 2>&1 || echo "HTTPS not accessible from server itself"`,
|
||||
|
||||
// Check HTTP (which should redirect to HTTPS per .htaccess)
|
||||
`echo "=== HTTP CHECK ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://demoplace.my.id/ 2>&1`,
|
||||
|
||||
// Check Apache config for this domain
|
||||
`echo "=== APACHE VHOST CONFIG ===" && cat /etc/apache2/conf.d/userdata/ssl/2_4/adminbackend/demoplace.my.id/*.conf 2>/dev/null | head -30 || ls /etc/apache2/conf.d/userdata/ 2>/dev/null | head -5 || echo "No Apache vhost config accessible"`,
|
||||
|
||||
// Check cPanel proxy config
|
||||
`echo "=== CPANEL PROXY CONF ===" && cat /home/adminbackend/.cpanel/ea4/php.conf 2>/dev/null || echo "No cPanel PHP conf"`,
|
||||
`cat /home/adminbackend/etc/apache_conf 2>/dev/null || echo "No Apache conf in home"`,
|
||||
|
||||
// Final summary
|
||||
`echo ""`,
|
||||
`echo "╔══════════════════════════════════════════════════════╗"`,
|
||||
`echo "║ BackOne DPI — PM2 Update Complete ║"`,
|
||||
`${PM2} list 2>/dev/null | grep -E "(online|error)" | awk '{print "║ " $2 " " $10 " " $6 " ║"}'`,
|
||||
`echo "╚══════════════════════════════════════════════════════╝"`,
|
||||
];
|
||||
|
||||
function runSsh(commands) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const ssh = new SshClient();
|
||||
ssh.on('ready', () => {
|
||||
console.log('[SSH] Connected!\n');
|
||||
let i = 0;
|
||||
function next() {
|
||||
if (i >= commands.length) { ssh.end(); return; }
|
||||
const cmd = commands[i++];
|
||||
console.log(`\n$ ${cmd.substring(0, 130)}${cmd.length > 130 ? '...' : ''}`);
|
||||
ssh.exec(cmd, (err, stream) => {
|
||||
if (err) { console.error('[ERR]', err.message); next(); return; }
|
||||
stream.on('data', d => process.stdout.write(d.toString()));
|
||||
stream.stderr.on('data', d => { const t = d.toString(); if (!t.includes('npm warn') && !t.includes('notice')) process.stdout.write(t); });
|
||||
stream.on('close', next);
|
||||
});
|
||||
}
|
||||
next();
|
||||
ssh.on('end', resolve);
|
||||
});
|
||||
ssh.on('error', reject);
|
||||
ssh.connect({ ...CONFIG, readyTimeout: 30000 });
|
||||
});
|
||||
}
|
||||
|
||||
async function checkHttps(url) {
|
||||
return new Promise(resolve => {
|
||||
const req = https.get(url, { timeout: 10000, rejectUnauthorized: false }, res => {
|
||||
let body = '';
|
||||
res.on('data', d => body += d);
|
||||
res.on('end', () => resolve({ status: res.statusCode, location: res.headers.location, body: body.substring(0, 150) }));
|
||||
});
|
||||
req.on('error', e => resolve({ status: 0, error: e.message }));
|
||||
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
||||
console.log('║ BackOne DPI — Fix PM2 Script & HTTPS Verification ║');
|
||||
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
||||
|
||||
await runSsh(COMMANDS);
|
||||
|
||||
console.log('\n\n▶ External HTTPS checks (from local machine)...\n');
|
||||
const checks = [
|
||||
'https://demoplace.my.id/',
|
||||
'https://demoplace.my.id/login',
|
||||
'https://demoplace.my.id/api/health',
|
||||
];
|
||||
for (const url of checks) {
|
||||
const r = await checkHttps(url);
|
||||
const icon = r.status >= 200 && r.status < 400 ? '✅' : r.status === 0 ? '⚠️' : '❌';
|
||||
console.log(` ${icon} ${url} → HTTP ${r.status} ${r.error || ''}`);
|
||||
if (r.location) console.log(` → Redirects to: ${r.location}`);
|
||||
if (r.status === 200 && r.body) console.log(` Body preview: ${r.body.substring(0, 100)}`);
|
||||
}
|
||||
|
||||
console.log('\n✅ Done!\n');
|
||||
}
|
||||
|
||||
main().catch(err => { console.error('[FATAL]', err); process.exit(1); });
|
||||
@@ -1,94 +0,0 @@
|
||||
const SftpClient = require('ssh2-sftp-client');
|
||||
const { Client } = require('ssh2');
|
||||
|
||||
const remoteAuditScript = `
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const root = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
|
||||
console.log('====================================================');
|
||||
console.log(' FULL COMPONENT & PAGE AUDIT OF DEMOPLACE.MY.ID ');
|
||||
console.log('====================================================');
|
||||
|
||||
// 1. Audit Client/Server Chunks for Page Headers & HelpTriggers
|
||||
const chunksDir = path.join(root, '.next/standalone/.next/server/chunks');
|
||||
if (fs.existsSync(chunksDir)) {
|
||||
const files = fs.readdirSync(chunksDir);
|
||||
files.forEach(f => {
|
||||
if (!f.endsWith('.js')) return;
|
||||
const content = fs.readFileSync(path.join(chunksDir, f), 'utf8');
|
||||
|
||||
// Look for page headers or title definitions
|
||||
const headerMatch = content.match(/["']([A-Z][A-Za-z0-9\\s]{3,35})["'],\\s*description:/);
|
||||
if (headerMatch) {
|
||||
console.log(\`[Chunk \${f}] Found Header Definition: "\${headerMatch[1]}"\`);
|
||||
}
|
||||
|
||||
if (content.includes('Learn This Page')) {
|
||||
console.log(\`[Chunk \${f}] Contains "Learn This Page" button\`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 2. Audit Page Source files in src/app/(dashboard)
|
||||
const appSrcDir = path.join(root, 'src/app/(dashboard)');
|
||||
if (fs.existsSync(appSrcDir)) {
|
||||
function scan(dir) {
|
||||
const items = fs.readdirSync(dir, { withFileTypes: true });
|
||||
for (const item of items) {
|
||||
const full = path.join(dir, item.name);
|
||||
if (item.isDirectory()) {
|
||||
scan(full);
|
||||
} else if (item.name === 'page.tsx' || item.name.endsWith('.tsx')) {
|
||||
const content = fs.readFileSync(full, 'utf8');
|
||||
const rel = path.relative(appSrcDir, full);
|
||||
|
||||
// Find H2 or H1
|
||||
const h2 = content.match(/<h[12][^>]*>([\\s\\S]*?)<\\/h[12]>/i);
|
||||
const titleText = h2 ? h2[1].replace(/<[^>]+>/g, '').trim().split('\\n')[0] : 'None';
|
||||
const hasHelp = content.includes('HelpTrigger') || content.includes('Learn This Page');
|
||||
|
||||
console.log(\`Page File: \${rel}\`);
|
||||
console.log(\` Header Title : \${titleText}\`);
|
||||
console.log(\` Has HelpButton: \${hasHelp}\`);
|
||||
console.log('----------------------------------------------------');
|
||||
}
|
||||
}
|
||||
}
|
||||
scan(appSrcDir);
|
||||
}
|
||||
`;
|
||||
|
||||
async function main() {
|
||||
const sftp = new SftpClient();
|
||||
await sftp.connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
|
||||
const remoteScriptPath = '/home/adminbackend/audit_remote.js';
|
||||
await sftp.put(Buffer.from(remoteAuditScript), remoteScriptPath);
|
||||
await sftp.end();
|
||||
|
||||
const conn = new Client();
|
||||
conn.on('ready', () => {
|
||||
conn.exec(`node ${remoteScriptPath}`, (err, stream) => {
|
||||
let out = '';
|
||||
stream.on('data', d => out += d);
|
||||
stream.on('close', () => {
|
||||
console.log(out);
|
||||
conn.end();
|
||||
});
|
||||
});
|
||||
}).connect({
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH'
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,87 +0,0 @@
|
||||
// scripts/upload-profile-pictures.js
|
||||
// Upload semua foto profil dari lokal ke server production
|
||||
'use strict';
|
||||
const SftpClient = require('ssh2-sftp-client');
|
||||
const { Client: SshClient } = require('ssh2');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const CONFIG = {
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH',
|
||||
readyTimeout: 30000,
|
||||
retries: 3,
|
||||
retry_factor: 2,
|
||||
retry_minTimeout: 2000,
|
||||
};
|
||||
const LOCAL_DIR = path.join(__dirname, '..', 'backend', 'public', 'api', 'uploads');
|
||||
const REMOTE_DIR = '/home/adminbackend/web/demoplace.my.id/public_html/api/uploads';
|
||||
|
||||
function sshExec(cmd) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const conn = new SshClient();
|
||||
conn.on('ready', () => {
|
||||
conn.exec(cmd, (err, stream) => {
|
||||
if (err) { conn.end(); return reject(err); }
|
||||
let out = '';
|
||||
stream
|
||||
.on('data', d => { out += d; })
|
||||
.stderr.on('data', d => { out += d; });
|
||||
stream.on('close', () => { conn.end(); resolve(out); });
|
||||
});
|
||||
}).on('error', reject)
|
||||
.connect({ host: CONFIG.host, port: CONFIG.port, username: CONFIG.username, password: CONFIG.password, readyTimeout: CONFIG.readyTimeout });
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
if (!fs.existsSync(LOCAL_DIR)) {
|
||||
console.log('Folder uploads lokal tidak ditemukan:', LOCAL_DIR);
|
||||
return;
|
||||
}
|
||||
|
||||
const files = fs.readdirSync(LOCAL_DIR).filter(f => /\.(png|jpg|jpeg|webp)$/i.test(f));
|
||||
if (files.length === 0) {
|
||||
console.log('Tidak ada file gambar di folder uploads lokal.');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Ditemukan ${files.length} file foto profil untuk diupload:\n ${files.join('\n ')}\n`);
|
||||
|
||||
// Buat direktori di server jika belum ada
|
||||
await sshExec(`mkdir -p ${REMOTE_DIR} && chmod 755 ${REMOTE_DIR}`);
|
||||
console.log(`[Server] Direktori ${REMOTE_DIR} siap\n`);
|
||||
|
||||
// Upload semua file via SFTP
|
||||
const sftp = new SftpClient();
|
||||
await sftp.connect(CONFIG);
|
||||
console.log('[SFTP] Terhubung ke server\n');
|
||||
|
||||
let uploaded = 0;
|
||||
let failed = 0;
|
||||
|
||||
for (const file of files) {
|
||||
const localPath = path.join(LOCAL_DIR, file);
|
||||
const remotePath = `${REMOTE_DIR}/${file}`;
|
||||
try {
|
||||
await sftp.put(localPath, remotePath);
|
||||
console.log(`✅ Upload: ${file}`);
|
||||
uploaded++;
|
||||
} catch (err) {
|
||||
console.error(`❌ Gagal upload ${file}:`, err.message);
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
|
||||
await sftp.end();
|
||||
|
||||
// Verifikasi
|
||||
const remoteList = await sshExec(`ls -lh ${REMOTE_DIR}`);
|
||||
console.log('\n[Server] Isi folder uploads:\n' + remoteList);
|
||||
|
||||
console.log(`\n✅ Selesai! ${uploaded} berhasil, ${failed} gagal.`);
|
||||
}
|
||||
|
||||
main().catch(e => console.error('[FATAL]', e.message));
|
||||
@@ -1,147 +0,0 @@
|
||||
// scripts/upload-standalone-next.js
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// BackOne DPI — Upload missing .next/standalone/.next/ directory to server
|
||||
// This fixes: "Could not find a production build in the './.next' directory"
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const SftpClient = require('ssh2-sftp-client');
|
||||
const { Client: SshClient } = require('ssh2');
|
||||
|
||||
const LOCAL_ROOT = path.resolve(__dirname, '..');
|
||||
const REMOTE_ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
|
||||
|
||||
const CONFIG = {
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH',
|
||||
};
|
||||
|
||||
// Recursively upload a local directory to remote (skipping node_modules and .git)
|
||||
async function uploadDir(sftp, localPath, remotePath) {
|
||||
const items = fs.readdirSync(localPath, { withFileTypes: true });
|
||||
try { await sftp.mkdir(remotePath, true); } catch {}
|
||||
|
||||
for (const item of items) {
|
||||
if (['node_modules', '.git'].includes(item.name)) continue;
|
||||
if (item.name.endsWith('.log')) continue;
|
||||
|
||||
const lp = path.join(localPath, item.name);
|
||||
const rp = remotePath + '/' + item.name;
|
||||
|
||||
if (item.isDirectory()) {
|
||||
process.stdout.write(` [DIR] ${rp}\n`);
|
||||
await uploadDir(sftp, lp, rp);
|
||||
} else {
|
||||
process.stdout.write(` [UP] ${rp} ...`);
|
||||
await sftp.put(lp, rp);
|
||||
process.stdout.write(' done\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function runSsh(commands) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const ssh = new SshClient();
|
||||
ssh.on('ready', () => {
|
||||
let i = 0;
|
||||
function next() {
|
||||
if (i >= commands.length) { ssh.end(); return; }
|
||||
const cmd = commands[i++];
|
||||
console.log(`\n$ ${cmd.substring(0, 120)}${cmd.length > 120 ? '...' : ''}`);
|
||||
ssh.exec(cmd, (err, stream) => {
|
||||
if (err) { console.error('[ERR]', err.message); next(); return; }
|
||||
stream.on('data', d => process.stdout.write(d.toString()));
|
||||
stream.stderr.on('data', d => { const t = d.toString(); if (!t.includes('npm warn') && !t.includes('notice')) process.stdout.write(t); });
|
||||
stream.on('close', next);
|
||||
});
|
||||
}
|
||||
next();
|
||||
ssh.on('end', resolve);
|
||||
});
|
||||
ssh.on('error', reject);
|
||||
ssh.connect({ ...CONFIG, readyTimeout: 30000 });
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
||||
console.log('║ BackOne DPI — Upload Standalone Build Artifacts ║');
|
||||
console.log('║ Uploading: .next/standalone/.next/ (BUILD_ID + server) ║');
|
||||
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
||||
|
||||
const localStandaloneNext = path.join(LOCAL_ROOT, '.next', 'standalone', '.next');
|
||||
if (!fs.existsSync(localStandaloneNext)) {
|
||||
console.error('✗ ERROR: .next/standalone/.next not found locally!');
|
||||
console.error(' Run: npm run build');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Verify BUILD_ID exists
|
||||
const buildId = fs.existsSync(path.join(localStandaloneNext, 'BUILD_ID'))
|
||||
? fs.readFileSync(path.join(localStandaloneNext, 'BUILD_ID'), 'utf8').trim()
|
||||
: null;
|
||||
console.log(`✓ Build ID: ${buildId || 'NOT FOUND'}`);
|
||||
console.log(`✓ Local path: ${localStandaloneNext}`);
|
||||
|
||||
const sftp = new SftpClient();
|
||||
try {
|
||||
await sftp.connect(CONFIG);
|
||||
console.log('[SFTP] Connected!\n');
|
||||
|
||||
const remotePath = `${REMOTE_ROOT}/.next/standalone/.next`;
|
||||
console.log(`\n[DIR] Uploading .next/standalone/.next/ → ${remotePath}\n`);
|
||||
await uploadDir(sftp, localStandaloneNext, remotePath);
|
||||
|
||||
console.log('\n[SFTP] Upload complete!\n');
|
||||
} finally {
|
||||
await sftp.end();
|
||||
}
|
||||
|
||||
// Post-upload: restart PM2 frontend, verify
|
||||
console.log('\n▶ Restarting PM2 frontend with new build...\n');
|
||||
await runSsh([
|
||||
// Verify BUILD_ID now exists on server
|
||||
`echo "=== VERIFY BUILD_ID ===" && cat ${REMOTE_ROOT}/.next/standalone/.next/BUILD_ID`,
|
||||
|
||||
// Also verify static dir exists
|
||||
`echo "=== VERIFY STATIC ===" && ls ${REMOTE_ROOT}/.next/standalone/.next/static/ 2>/dev/null | wc -l | xargs echo "Static files:"`,
|
||||
|
||||
// Restart frontend PM2 process
|
||||
`echo "=== RESTARTING FRONTEND ===" && ${PM2} restart backone-frontend --update-env && echo "Restarted"`,
|
||||
|
||||
// Wait
|
||||
`sleep 6`,
|
||||
|
||||
// Check PM2 status
|
||||
`echo "=== PM2 STATUS ===" && ${PM2} list`,
|
||||
|
||||
// Test internal endpoints
|
||||
`echo "=== FRONTEND / ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/`,
|
||||
`echo "=== FRONTEND /login ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/login`,
|
||||
`echo "=== BACKEND HEALTH ===" && curl -s http://127.0.0.1:3001/api/health`,
|
||||
|
||||
// Show frontend log
|
||||
`echo "=== FRONTEND LOG ===" && ${PM2} logs backone-frontend --lines 10 --nostream 2>&1 | tail -15`,
|
||||
|
||||
// Test via domain (HTTP which redirects to HTTPS via .htaccess)
|
||||
`echo "=== DOMAIN HTTP TEST ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://demoplace.my.id/`,
|
||||
|
||||
// Check port 3000
|
||||
`echo "=== PORT 3000 ===" && ss -tlnp | grep 3000`,
|
||||
]);
|
||||
|
||||
console.log('\n══════════════════════════════════════════════════════════');
|
||||
console.log(' ✅ Standalone build artifacts uploaded & frontend restarted!');
|
||||
console.log(' 🌐 Dashboard: https://demoplace.my.id');
|
||||
console.log('══════════════════════════════════════════════════════════\n');
|
||||
}
|
||||
|
||||
main().catch(err => {
|
||||
console.error('\n[FATAL]', err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -1,148 +0,0 @@
|
||||
// scripts/verify-deployment.js
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// BackOne DPI — Post-Deployment Verification Script
|
||||
// Tests: frontend, backend, security headers, proxy, MongoDB
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
'use strict';
|
||||
|
||||
const { Client: SshClient } = require('ssh2');
|
||||
const https = require('https');
|
||||
const http = require('http');
|
||||
|
||||
const CONFIG = {
|
||||
host: '103.185.47.52',
|
||||
port: 2222,
|
||||
username: 'adminbackend',
|
||||
password: 'htEo7x6LsBQiEHHH',
|
||||
};
|
||||
|
||||
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
|
||||
const ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
|
||||
|
||||
// HTTP request helper
|
||||
function httpGet(url) {
|
||||
return new Promise((resolve) => {
|
||||
const mod = url.startsWith('https') ? https : http;
|
||||
const req = mod.get(url, { timeout: 10000 }, (res) => {
|
||||
let body = '';
|
||||
res.on('data', (d) => body += d);
|
||||
res.on('end', () => resolve({ status: res.statusCode, headers: res.headers, body: body.substring(0, 300) }));
|
||||
});
|
||||
req.on('error', (e) => resolve({ status: 0, error: e.message }));
|
||||
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
|
||||
});
|
||||
}
|
||||
|
||||
const SSH_COMMANDS = [
|
||||
// Check PM2 process list
|
||||
`echo "=== PM2 STATUS ===" && ${PM2} list`,
|
||||
|
||||
// Check backend health
|
||||
`echo "=== BACKEND HEALTH ===" && curl -s http://127.0.0.1:3001/api/health`,
|
||||
|
||||
// Check frontend pages
|
||||
`echo "=== FRONTEND / ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/`,
|
||||
`echo "=== FRONTEND /login ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/login`,
|
||||
|
||||
// Security audit: ensure backend and proxy ports are NOT publicly accessible
|
||||
`echo "=== SECURITY: Port 3001 external test ===" && ss -tlnp | grep 3001`,
|
||||
`echo "=== SECURITY: Port 4000 external test ===" && ss -tlnp | grep 4000`,
|
||||
|
||||
// Check upload directory permissions
|
||||
`echo "=== UPLOAD DIR PERMS ===" && ls -la ${ROOT}/backend/public/api/uploads/ 2>/dev/null || echo "Upload dir does not exist yet (will be created on first upload)"`,
|
||||
|
||||
// Check proxy MongoDB connection
|
||||
`echo "=== PROXY STATUS ===" && ${PM2} logs backone-proxy --lines 5 --nostream 2>&1 | grep -E "(MongoDB|Connected|Capacity|Scheduler)" | tail -10`,
|
||||
|
||||
// Verify no secrets in Next.js build output (sanity check)
|
||||
`echo "=== SECURITY AUDIT: Check no API key in build ===" && grep -r "sk_db_live" ${ROOT}/.next/standalone/ 2>/dev/null | head -3 || echo "CLEAN: No Netify API key found in build output"`,
|
||||
`echo "=== SECURITY AUDIT: Check no MongoDB URI in build ===" && grep -r "backone_user" ${ROOT}/.next/standalone/ 2>/dev/null | head -3 || echo "CLEAN: No MongoDB credentials in build output"`,
|
||||
|
||||
// Check frontend log for readiness
|
||||
`echo "=== FRONTEND READY LOG ===" && ${PM2} logs backone-frontend --lines 5 --nostream 2>&1 | grep -E "(Ready|Error|Next.js)" | tail -10`,
|
||||
|
||||
// Check disk usage for uploads dir
|
||||
`echo "=== DISK USAGE ===" && df -h /home/adminbackend/web/ 2>/dev/null | tail -2`,
|
||||
|
||||
// Final summary
|
||||
`echo ""`,
|
||||
`echo "╔════════════════════════════════════════════╗"`,
|
||||
`echo "║ BackOne DPI Production — Service Status ║"`,
|
||||
`echo "╠════════════════════════════════════════════╣"`,
|
||||
`${PM2} list 2>/dev/null | grep -E "(online|error|stopped)" | awk '{printf "║ %-12s %-10s %-8s ║\\n", $2, $10, $8}'`,
|
||||
`echo "╚════════════════════════════════════════════╝"`,
|
||||
];
|
||||
|
||||
function runSshChecks(commands) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const ssh = new SshClient();
|
||||
|
||||
ssh.on('ready', () => {
|
||||
console.log('[SSH] Connected for verification!\n');
|
||||
let index = 0;
|
||||
|
||||
function runNext() {
|
||||
if (index >= commands.length) {
|
||||
ssh.end();
|
||||
return;
|
||||
}
|
||||
const cmd = commands[index++];
|
||||
console.log(`\n$ ${cmd.substring(0, 120)}${cmd.length > 120 ? '...' : ''}`);
|
||||
|
||||
ssh.exec(cmd, (err, stream) => {
|
||||
if (err) { console.error(`[ERROR] ${err.message}`); runNext(); return; }
|
||||
stream.on('data', (d) => process.stdout.write(d.toString()));
|
||||
stream.stderr.on('data', (d) => {
|
||||
const t = d.toString();
|
||||
if (!t.includes('npm warn') && !t.includes('npm notice')) process.stdout.write(t);
|
||||
});
|
||||
stream.on('close', runNext);
|
||||
});
|
||||
}
|
||||
|
||||
runNext();
|
||||
ssh.on('end', resolve);
|
||||
});
|
||||
ssh.on('error', reject);
|
||||
ssh.connect({ ...CONFIG, readyTimeout: 30000 });
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
||||
console.log('║ BackOne DPI — Post-Deployment Verification ║');
|
||||
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
||||
|
||||
// ── SSH internal checks ───────────────────────────────────────────────────
|
||||
console.log('▶ Running internal server checks via SSH...');
|
||||
await runSshChecks(SSH_COMMANDS);
|
||||
|
||||
// ── External HTTP checks (from this machine) ──────────────────────────────
|
||||
console.log('\n\n▶ Running external HTTP checks from local machine...\n');
|
||||
|
||||
const checks = [
|
||||
{ url: 'http://demoplace.my.id/', label: 'Domain root (redirect expected)' },
|
||||
{ url: 'http://demoplace.my.id/login', label: 'Login page' },
|
||||
{ url: 'http://demoplace.my.id/api/health', label: 'Backend health via domain' },
|
||||
];
|
||||
|
||||
for (const { url, label } of checks) {
|
||||
const result = await httpGet(url);
|
||||
const status = result.status;
|
||||
const icon = (status >= 200 && status < 400) ? '✅' : (status === 0 ? '⚠️' : '❌');
|
||||
console.log(` ${icon} ${label}: HTTP ${status} ${result.error || ''}`);
|
||||
if (result.body && status >= 200 && status < 300) {
|
||||
console.log(` Body preview: ${result.body.substring(0, 100)}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n══════════════════════════════════════════════════════════');
|
||||
console.log(' Production deployment verification complete!');
|
||||
console.log(' URL: https://demoplace.my.id');
|
||||
console.log('══════════════════════════════════════════════════════════\n');
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('[FATAL]', err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in new issue
Block a user