Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
- ADD_CHAIN138_TO_LEDGER_LIVE: Ledger form done; public code review repo bis-innovations/LedgerLive; init/push commands - CONTRACT_DEPLOYMENT_RUNBOOK: Chain 138 gas price 1 gwei, 36-addr check, TransactionMirror workaround - CONTRACT_*: AddressMapper, MirrorManager deployed 2026-02-12; 36-address on-chain check - NEXT_STEPS_FOR_YOU: Ledger done; steps completable now (no LAN); run-completable-tasks-from-anywhere - MASTER_INDEX, OPERATOR_OPTIONAL, SMART_CONTRACTS_INVENTORY_SIMPLE: updates - LEDGER_BLOCKCHAIN_INTEGRATION_COMPLETE: bis-innovations/LedgerLive reference Co-authored-by: Cursor <cursoragent@cursor.com>
312 lines
11 KiB
JavaScript
Executable File
312 lines
11 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
/**
|
|
* Configure SSL certificates for all domains in Nginx Proxy Manager via API
|
|
* This script uses the NPM API directly instead of browser automation
|
|
*/
|
|
|
|
import { readFileSync } from 'fs';
|
|
import { fileURLToPath } from 'url';
|
|
import { dirname, join } from 'path';
|
|
import { config } from 'dotenv';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = dirname(__filename);
|
|
const PROJECT_ROOT = join(__dirname, '../..');
|
|
|
|
// Load environment variables
|
|
config({ path: join(PROJECT_ROOT, '.env') });
|
|
|
|
// Configuration
|
|
const NPM_URL = process.env.NPM_URL || 'http://192.168.11.26:81';
|
|
const NPM_EMAIL = process.env.NPM_EMAIL || process.env.NGINX_EMAIL || 'nsatoshi2007@hotmail.com';
|
|
const NPM_PASSWORD = process.env.NPM_PASSWORD || process.env.NGINX_PASSWORD || 'L@ker$2010';
|
|
|
|
// All domains to configure
|
|
const DOMAINS = [
|
|
// sankofa.nexus zone
|
|
{ domain: 'sankofa.nexus', target: 'http://192.168.11.140:80', websocket: false },
|
|
{ domain: 'www.sankofa.nexus', target: 'http://192.168.11.140:80', websocket: false },
|
|
{ domain: 'phoenix.sankofa.nexus', target: 'http://192.168.11.140:80', websocket: false },
|
|
{ domain: 'www.phoenix.sankofa.nexus', target: 'http://192.168.11.140:80', websocket: false },
|
|
{ domain: 'the-order.sankofa.nexus', target: 'http://192.168.11.140:80', websocket: false },
|
|
|
|
// d-bis.org zone
|
|
{ domain: 'explorer.d-bis.org', target: 'http://192.168.11.140:4000', websocket: false },
|
|
{ domain: 'rpc-http-pub.d-bis.org', target: 'https://192.168.11.252:443', websocket: true },
|
|
{ domain: 'rpc-ws-pub.d-bis.org', target: 'https://192.168.11.252:443', websocket: true },
|
|
{ domain: 'rpc-http-prv.d-bis.org', target: 'https://192.168.11.251:443', websocket: true },
|
|
{ domain: 'rpc-ws-prv.d-bis.org', target: 'https://192.168.11.251:443', websocket: true },
|
|
{ domain: 'dbis-admin.d-bis.org', target: 'http://192.168.11.130:80', websocket: false },
|
|
{ domain: 'dbis-api.d-bis.org', target: 'http://192.168.11.155:3000', websocket: false },
|
|
{ domain: 'dbis-api-2.d-bis.org', target: 'http://192.168.11.156:3000', websocket: false },
|
|
{ domain: 'secure.d-bis.org', target: 'http://192.168.11.130:80', websocket: false },
|
|
|
|
// mim4u.org zone
|
|
// MIM4U - VMID 7810 (mim-web-1) @ 192.168.11.37 - Web Frontend serves main site and proxies /api/* to 7811
|
|
{ domain: 'mim4u.org', target: 'http://192.168.11.37:80', websocket: false },
|
|
{ domain: 'www.mim4u.org', target: 'http://192.168.11.37:80', websocket: false },
|
|
{ domain: 'secure.mim4u.org', target: 'http://192.168.11.37:80', websocket: false },
|
|
{ domain: 'training.mim4u.org', target: 'http://192.168.11.37:80', websocket: false },
|
|
|
|
// defi-oracle.io zone
|
|
{ domain: 'rpc.public-0138.defi-oracle.io', target: 'https://192.168.11.252:443', websocket: true },
|
|
];
|
|
|
|
// Helper functions
|
|
function log(message, type = 'info') {
|
|
const prefix = type === 'error' ? '[✗]' : type === 'success' ? '[✓]' : '[INFO]';
|
|
console.log(`${prefix} ${message}`);
|
|
}
|
|
|
|
async function getAuthToken() {
|
|
try {
|
|
const response = await fetch(`${NPM_URL}/api/tokens`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
identity: NPM_EMAIL,
|
|
secret: NPM_PASSWORD
|
|
})
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.token) {
|
|
log('Authentication successful', 'success');
|
|
return data.token;
|
|
} else {
|
|
log(`Authentication failed: ${data.error?.message || 'Unknown error'}`, 'error');
|
|
return null;
|
|
}
|
|
} catch (error) {
|
|
log(`Authentication error: ${error.message}`, 'error');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
async function checkExistingProxyHost(token, domain) {
|
|
try {
|
|
const response = await fetch(`${NPM_URL}/api/nginx/proxy-hosts`, {
|
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.result) {
|
|
const existing = data.result.find(host =>
|
|
host.domain_names && host.domain_names.includes(domain)
|
|
);
|
|
return existing;
|
|
}
|
|
|
|
return null;
|
|
} catch (error) {
|
|
log(`Error checking existing host for ${domain}: ${error.message}`, 'error');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
async function createProxyHost(token, domainConfig) {
|
|
const { domain, target, websocket } = domainConfig;
|
|
const url = new URL(target);
|
|
const scheme = url.protocol.replace(':', '');
|
|
const hostname = url.hostname;
|
|
const port = url.port || (scheme === 'https' ? '443' : '80');
|
|
|
|
const payload = {
|
|
domain_names: [domain],
|
|
forward_scheme: scheme,
|
|
forward_hostname: hostname,
|
|
forward_port: parseInt(port),
|
|
allow_websocket_upgrade: websocket,
|
|
block_exploits: true,
|
|
cache_enabled: false,
|
|
ssl_forced: true,
|
|
http2_support: true,
|
|
hsts_enabled: true,
|
|
hsts_subdomains: true,
|
|
access_list_id: 0,
|
|
certificate_id: 0,
|
|
meta: {
|
|
letsencrypt_agree: true,
|
|
letsencrypt_email: NPM_EMAIL
|
|
}
|
|
};
|
|
|
|
try {
|
|
const response = await fetch(`${NPM_URL}/api/nginx/proxy-hosts`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`,
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(payload)
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.id) {
|
|
log(`Created proxy host for ${domain} (ID: ${data.id})`, 'success');
|
|
return data;
|
|
} else {
|
|
log(`Failed to create proxy host for ${domain}: ${data.error?.message || 'Unknown error'}`, 'error');
|
|
return null;
|
|
}
|
|
} catch (error) {
|
|
log(`Error creating proxy host for ${domain}: ${error.message}`, 'error');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
async function requestSSLCertificate(token, proxyHostId, domain) {
|
|
try {
|
|
// First, get the certificate ID by requesting it
|
|
const response = await fetch(`${NPM_URL}/api/nginx/certificates`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`,
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
domain_names: [domain],
|
|
provider: 'letsencrypt',
|
|
letsencrypt_email: NPM_EMAIL,
|
|
letsencrypt_agree: true
|
|
})
|
|
});
|
|
|
|
const certData = await response.json();
|
|
|
|
if (certData.id) {
|
|
log(`Requested SSL certificate for ${domain} (Cert ID: ${certData.id})`, 'success');
|
|
|
|
// Update proxy host to use this certificate
|
|
const updateResponse = await fetch(`${NPM_URL}/api/nginx/proxy-hosts/${proxyHostId}`, {
|
|
method: 'PUT',
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`,
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
certificate_id: certData.id,
|
|
ssl_forced: true
|
|
})
|
|
});
|
|
|
|
const updateData = await updateResponse.json();
|
|
|
|
if (updateData.id) {
|
|
log(`Updated proxy host ${proxyHostId} with SSL certificate`, 'success');
|
|
return true;
|
|
}
|
|
} else {
|
|
log(`Failed to request SSL certificate for ${domain}: ${certData.error?.message || 'Unknown error'}`, 'error');
|
|
}
|
|
|
|
return false;
|
|
} catch (error) {
|
|
log(`Error requesting SSL certificate for ${domain}: ${error.message}`, 'error');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async function main() {
|
|
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
console.log('🔒 Nginx Proxy Manager SSL Configuration (API)');
|
|
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
console.log('');
|
|
log(`NPM URL: ${NPM_URL}`);
|
|
log(`Email: ${NPM_EMAIL}`);
|
|
log(`Domains to configure: ${DOMAINS.length}`);
|
|
console.log('');
|
|
|
|
// Get authentication token
|
|
const token = await getAuthToken();
|
|
if (!token) {
|
|
log('Cannot proceed without authentication token', 'error');
|
|
process.exit(1);
|
|
}
|
|
|
|
let successCount = 0;
|
|
let failCount = 0;
|
|
let skipCount = 0;
|
|
|
|
// Configure each domain
|
|
for (const domainConfig of DOMAINS) {
|
|
const { domain } = domainConfig;
|
|
|
|
log(`Processing ${domain}...`);
|
|
|
|
// Check if already exists
|
|
const existing = await checkExistingProxyHost(token, domain);
|
|
|
|
if (existing) {
|
|
log(`Proxy host for ${domain} already exists (ID: ${existing.id}), skipping creation`, 'info');
|
|
|
|
// Check if it has SSL certificate
|
|
if (!existing.certificate_id || existing.certificate_id === 0) {
|
|
log(`Requesting SSL certificate for existing proxy host ${domain}...`);
|
|
const sslSuccess = await requestSSLCertificate(token, existing.id, domain);
|
|
if (sslSuccess) {
|
|
successCount++;
|
|
} else {
|
|
failCount++;
|
|
}
|
|
} else {
|
|
log(`SSL certificate already configured for ${domain}`, 'success');
|
|
successCount++;
|
|
}
|
|
|
|
skipCount++;
|
|
continue;
|
|
}
|
|
|
|
// Create proxy host
|
|
const proxyHost = await createProxyHost(token, domainConfig);
|
|
|
|
if (proxyHost) {
|
|
// Request SSL certificate
|
|
log(`Requesting SSL certificate for ${domain}...`);
|
|
const sslSuccess = await requestSSLCertificate(token, proxyHost.id, domain);
|
|
|
|
if (sslSuccess) {
|
|
successCount++;
|
|
log(`✓ Successfully configured ${domain}`, 'success');
|
|
} else {
|
|
failCount++;
|
|
log(`✗ Failed to configure SSL for ${domain}`, 'error');
|
|
}
|
|
} else {
|
|
failCount++;
|
|
log(`✗ Failed to create proxy host for ${domain}`, 'error');
|
|
}
|
|
|
|
// Small delay between requests
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
}
|
|
|
|
console.log('');
|
|
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
console.log('📊 Configuration Summary');
|
|
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
console.log(`✅ Successful: ${successCount}`);
|
|
console.log(`⚠️ Skipped: ${skipCount}`);
|
|
console.log(`✗ Failed: ${failCount}`);
|
|
console.log(`📋 Total: ${DOMAINS.length}`);
|
|
console.log('');
|
|
|
|
if (failCount === 0) {
|
|
log('All domains configured successfully!', 'success');
|
|
console.log('');
|
|
log('Note: SSL certificates may take 1-2 minutes to be issued by Let\'s Encrypt');
|
|
log('Run verification: bash scripts/nginx-proxy-manager/verify-ssl-config.sh');
|
|
} else {
|
|
log('Some domains failed to configure. Check errors above.', 'error');
|
|
}
|
|
}
|
|
|
|
main().catch(error => {
|
|
log(`Fatal error: ${error.message}`, 'error');
|
|
process.exit(1);
|
|
});
|