Files
proxmox/scripts/nginx-proxy-manager/configure-ssl-api.js
defiQUG fbda1b4beb
Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
docs: Ledger Live integration, contract deploy learnings, NEXT_STEPS updates
- 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>
2026-02-12 15:46:57 -08:00

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);
});