#!/usr/bin/env bun /** * Management CLI for NGINX Proxy Manager * Usage: bun manage.ts [options] */ import { program } from 'commander'; import { database } from './src/database/index.js'; import { UserModel } from './src/models/User.js'; import { ProxyModel } from './src/models/Proxy.js'; import { CertificateModel } from './src/models/Certificate.js'; import { SSLService } from './src/services/SSLService.js'; import { NginxService } from './src/services/NginxService.js'; import bcrypt from 'bcryptjs'; import logger from './src/utils/logger.js'; program .name('nginx-proxy-manager') .description('NGINX Proxy Manager CLI') .version('1.0.0'); // User management commands const userCmd = program.command('user').description('User management commands'); userCmd .command('create') .description('Create a new admin user') .requiredOption('-u, --username ', 'Username') .requiredOption('-p, --password ', 'Password') .action(async (options) => { try { const hashedPassword = await bcrypt.hash(options.password, 10); const user = await UserModel.create({ username: options.username, password: hashedPassword }); console.log(`✅ User created: ${user.username} (ID: ${user.id})`); } catch (error: any) { console.error(`❌ Failed to create user: ${error.message}`); } finally { await database.close(); process.exit(); } }); userCmd .command('change-password') .description('Change user password') .requiredOption('-u, --username ', 'Username') .requiredOption('-p, --password ', 'New password') .action(async (options) => { try { const user = await UserModel.findByUsername(options.username); if (!user) { console.error(`❌ User not found: ${options.username}`); return; } const hashedPassword = await bcrypt.hash(options.password, 10); await UserModel.updatePassword(user.id!, hashedPassword); console.log(`✅ Password updated for user: ${options.username}`); } catch (error: any) { console.error(`❌ Failed to update password: ${error.message}`); } finally { await database.close(); process.exit(); } }); // Proxy management commands const proxyCmd = program.command('proxy').description('Proxy management commands'); proxyCmd .command('list') .description('List all proxies') .action(async () => { try { const proxies = await ProxyModel.findAll(); console.log(`\n📋 Found ${proxies.length} proxy(ies):\n`); proxies.forEach(proxy => { console.log(`🔗 ${proxy.domain} → ${proxy.target}`); console.log(` SSL: ${proxy.ssl_type}`); console.log(` ID: ${proxy.id}`); console.log(` Created: ${proxy.created_at}\n`); }); } catch (error: any) { console.error(`❌ Failed to list proxies: ${error.message}`); } finally { await database.close(); process.exit(); } }); proxyCmd .command('delete') .description('Delete a proxy by ID') .requiredOption('-i, --id ', 'Proxy ID') .action(async (options) => { try { const id = parseInt(options.id); const proxy = await ProxyModel.findById(id); if (!proxy) { console.error(`❌ Proxy not found with ID: ${id}`); return; } // Remove NGINX config await NginxService.removeConfig(proxy.domain); // Delete from database await ProxyModel.delete(id); // Reload NGINX const result = await NginxService.reload(); if (result.success) { console.log(`✅ Proxy deleted: ${proxy.domain}`); } else { console.log(`⚠️ Proxy deleted but NGINX reload failed: ${result.output}`); } } catch (error: any) { console.error(`❌ Failed to delete proxy: ${error.message}`); } finally { await database.close(); process.exit(); } }); // Certificate management commands const certCmd = program.command('cert').description('Certificate management commands'); certCmd .command('list') .description('List all certificates') .action(async () => { try { const certificates = await CertificateModel.findAll(); console.log(`\n🔐 Found ${certificates.length} certificate(s):\n`); certificates.forEach(cert => { console.log(`📜 ${cert.domain}`); console.log(` Type: ${cert.type}`); console.log(` Status: ${cert.status}`); console.log(` Expiry: ${cert.expiry || 'N/A'}`); console.log(` ID: ${cert.id}\n`); }); } catch (error: any) { console.error(`❌ Failed to list certificates: ${error.message}`); } finally { await database.close(); process.exit(); } }); certCmd .command('renew') .description('Renew certificates expiring soon') .option('-d, --days ', 'Days before expiry to renew', '30') .action(async (options) => { try { const days = parseInt(options.days); console.log(`🔍 Checking for certificates expiring within ${days} days...`); await SSLService.autoRenewCertificates(); console.log('✅ Certificate renewal process completed'); } catch (error: any) { console.error(`❌ Certificate renewal failed: ${error.message}`); } finally { await database.close(); process.exit(); } }); // NGINX management commands const nginxCmd = program.command('nginx').description('NGINX management commands'); nginxCmd .command('test') .description('Test NGINX configuration') .action(async () => { try { const result = await NginxService.testConfig(); if (result.success) { console.log('✅ NGINX configuration is valid'); } else { console.log('❌ NGINX configuration test failed:'); console.log(result.output); } } catch (error: any) { console.error(`❌ Failed to test NGINX: ${error.message}`); } finally { process.exit(); } }); nginxCmd .command('reload') .description('Reload NGINX configuration') .action(async () => { try { const result = await NginxService.reload(); if (result.success) { console.log('✅ NGINX reloaded successfully'); } else { console.log('❌ NGINX reload failed:'); console.log(result.output); } } catch (error: any) { console.error(`❌ Failed to reload NGINX: ${error.message}`); } finally { process.exit(); } }); nginxCmd .command('status') .description('Get NGINX status') .action(async () => { try { const result = await NginxService.getStatus(); if (result.success) { console.log('✅ NGINX Status:'); console.log(result.output); } else { console.log('❌ Failed to get NGINX status:'); console.log(result.output); } } catch (error: any) { console.error(`❌ Failed to get NGINX status: ${error.message}`); } finally { process.exit(); } }); // Database management commands const dbCmd = program.command('db').description('Database management commands'); dbCmd .command('init') .description('Initialize database') .action(async () => { try { console.log('🗄️ Initializing database...'); // Database initialization happens automatically when imported console.log('✅ Database initialized successfully'); } catch (error: any) { console.error(`❌ Database initialization failed: ${error.message}`); } finally { await database.close(); process.exit(); } }); dbCmd .command('backup') .description('Create database backup') .option('-o, --output ', 'Output file path', `./backups/backup-${new Date().toISOString().split('T')[0]}.db`) .action(async (options) => { try { const fs = await import('fs'); const path = await import('path'); // Ensure backup directory exists const backupDir = path.dirname(options.output); if (!fs.existsSync(backupDir)) { fs.mkdirSync(backupDir, { recursive: true }); } // Copy database file fs.copyFileSync('./data/proxy_manager.db', options.output); console.log(`✅ Database backed up to: ${options.output}`); } catch (error: any) { console.error(`❌ Backup failed: ${error.message}`); } finally { await database.close(); process.exit(); } }); // Status command program .command('status') .description('Show application status') .action(async () => { try { console.log('📊 NGINX Proxy Manager Status\n'); // Check database console.log('🗄️ Database:'); const proxies = await ProxyModel.findAll(); const certificates = await CertificateModel.findAll(); console.log(` Proxies: ${proxies.length}`); console.log(` Certificates: ${certificates.length}`); // Check NGINX console.log('\n🔧 NGINX:'); const nginxStatus = await NginxService.getStatus(); if (nginxStatus.success) { console.log(' Status: ✅ Running'); console.log(` Version: ${nginxStatus.output.trim()}`); } else { console.log(' Status: ❌ Not running or error'); } // Check config const configTest = await NginxService.testConfig(); console.log(` Config: ${configTest.success ? '✅ Valid' : '❌ Invalid'}`); // Check expiring certificates console.log('\n🔐 Certificates:'); const expiring = await SSLService.checkExpiringCertificates(30); console.log(` Expiring soon (30 days): ${expiring.length}`); } catch (error: any) { console.error(`❌ Failed to get status: ${error.message}`); } finally { await database.close(); process.exit(); } }); // Parse arguments program.parse(); // If no command provided, show help if (!process.argv.slice(2).length) { program.outputHelp(); process.exit(); }