UNPKG

apache-node-proxy

Version:

CLI tool to automatically configure Apache virtual hosts for Node.js applications

242 lines • 10.7 kB
#!/usr/bin/env node "use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const commander_1 = require("commander"); const chalk_1 = __importDefault(require("chalk")); const inquirer_1 = __importDefault(require("inquirer")); const fs_extra_1 = __importDefault(require("fs-extra")); const path_1 = __importDefault(require("path")); const child_process_1 = require("child_process"); const program = new commander_1.Command(); class ApachePortForwarder { constructor() { this.BITNAMI_BASE = '/opt/bitnami'; this.APACHE_CONF_DIR = '/opt/bitnami/apache/conf'; this.VHOSTS_DIR = '/opt/bitnami/apache/conf/vhosts'; } async run() { console.log(chalk_1.default.blue.bold('šŸš€ Apache Node.js Proxy')); console.log(chalk_1.default.gray('Automatically configure Apache virtual hosts for your Node.js application\n')); try { const options = await this.getConfiguration(); await this.validateConfiguration(options); await this.configureVirtualHosts(options); await this.restartApache(); console.log(chalk_1.default.green.bold('\nāœ… Configuration completed successfully!')); this.printSummary(options); } catch (error) { console.error(chalk_1.default.red.bold('\nāŒ Error:'), error instanceof Error ? error.message : error); process.exit(1); } } async getConfiguration() { const answers = await inquirer_1.default.prompt([ { type: 'input', name: 'projectPath', message: 'Enter your Node.js project path:', default: process.cwd(), validate: (input) => { if (!fs_extra_1.default.existsSync(input)) { return 'Project path does not exist'; } return true; } }, { type: 'number', name: 'port', message: 'Enter the port your Node.js application runs on:', default: 3000, validate: (input) => { if (input < 1 || input > 65535) { return 'Port must be between 1 and 65535'; } return true; } }, { type: 'input', name: 'appName', message: 'Enter a name for your application (used for config files):', default: 'myapp', validate: (input) => { if (!/^[a-zA-Z0-9-_]+$/.test(input)) { return 'App name can only contain letters, numbers, hyphens, and underscores'; } return true; } }, { type: 'confirm', name: 'usePredefined', message: 'Do you want to use predefined virtual hosts (if available)?', default: true }, { type: 'confirm', name: 'useHttps', message: 'Do you want to configure HTTPS virtual host?', default: true } ]); return { projectPath: path_1.default.resolve(answers.projectPath), port: answers.port, appName: answers.appName, useHttps: answers.useHttps, usePredefined: answers.usePredefined }; } async validateConfiguration(options) { console.log(chalk_1.default.yellow('\nšŸ” Validating configuration...')); // Check if running as root if (process.getuid && process.getuid() !== 0) { throw new Error('This tool requires root privileges. Please run with sudo.'); } // Check if Bitnami Apache is installed if (!fs_extra_1.default.existsSync(this.BITNAMI_BASE)) { throw new Error('Bitnami installation not found. This tool is designed for Bitnami Apache installations.'); } // Check if Apache configuration directory exists if (!fs_extra_1.default.existsSync(this.APACHE_CONF_DIR)) { throw new Error('Apache configuration directory not found.'); } // Check if project directory exists if (!fs_extra_1.default.existsSync(options.projectPath)) { throw new Error(`Project directory does not exist: ${options.projectPath}`); } console.log(chalk_1.default.green('āœ… Configuration validation passed')); } async configureVirtualHosts(options) { console.log(chalk_1.default.yellow('\nāš™ļø Configuring virtual hosts...')); if (options.usePredefined) { await this.configurePredefinedVirtualHosts(); } else { await this.configureCustomVirtualHosts(options); } } async configurePredefinedVirtualHosts() { const predefinedFiles = [ { source: 'sample-vhost.conf.disabled', target: 'sample-vhost.conf' }, { source: 'sample-https-vhost.conf.disabled', target: 'sample-https-vhost.conf' } ]; for (const file of predefinedFiles) { const sourcePath = path_1.default.join(this.VHOSTS_DIR, file.source); const targetPath = path_1.default.join(this.VHOSTS_DIR, file.target); if (fs_extra_1.default.existsSync(sourcePath)) { try { fs_extra_1.default.copyFileSync(sourcePath, targetPath); console.log(chalk_1.default.green(`āœ… Enabled ${file.target}`)); } catch (error) { console.log(chalk_1.default.yellow(`āš ļø Could not enable ${file.target}: ${error}`)); } } else { console.log(chalk_1.default.yellow(`āš ļø Predefined file not found: ${file.source}`)); } } } async configureCustomVirtualHosts(options) { // Create HTTP virtual host const httpConfig = this.generateHttpVirtualHost(options); const httpConfigPath = path_1.default.join(this.VHOSTS_DIR, `${options.appName}-http-vhost.conf`); fs_extra_1.default.writeFileSync(httpConfigPath, httpConfig); console.log(chalk_1.default.green(`āœ… Created HTTP virtual host: ${httpConfigPath}`)); // Create HTTPS virtual host if requested if (options.useHttps) { const httpsConfig = this.generateHttpsVirtualHost(options); const httpsConfigPath = path_1.default.join(this.VHOSTS_DIR, `${options.appName}-https-vhost.conf`); fs_extra_1.default.writeFileSync(httpsConfigPath, httpsConfig); console.log(chalk_1.default.green(`āœ… Created HTTPS virtual host: ${httpsConfigPath}`)); } } generateHttpVirtualHost(options) { return `<VirtualHost _default_:80> ServerAlias * DocumentRoot "${options.projectPath}" <Directory "${options.projectPath}"> Require all granted </Directory> ProxyPass / http://localhost:${options.port}/ ProxyPassReverse / http://localhost:${options.port}/ </VirtualHost>`; } generateHttpsVirtualHost(options) { return `<VirtualHost _default_:443> ServerAlias * SSLEngine on SSLCertificateFile "${this.APACHE_CONF_DIR}/bitnami/certs/server.crt" SSLCertificateKeyFile "${this.APACHE_CONF_DIR}/bitnami/certs/server.key" DocumentRoot "${options.projectPath}" <Directory "${options.projectPath}"> Require all granted </Directory> ProxyPass / http://localhost:${options.port}/ ProxyPassReverse / http://localhost:${options.port}/ </VirtualHost>`; } async restartApache() { console.log(chalk_1.default.yellow('\nšŸ”„ Restarting Apache...')); try { (0, child_process_1.execSync)('/opt/bitnami/ctlscript.sh restart apache', { stdio: 'inherit' }); console.log(chalk_1.default.green('āœ… Apache restarted successfully')); } catch (error) { throw new Error('Failed to restart Apache. Please restart manually using: sudo /opt/bitnami/ctlscript.sh restart apache'); } } printSummary(options) { console.log(chalk_1.default.blue.bold('\nšŸ“‹ Configuration Summary:')); console.log(chalk_1.default.white(` Project Path: ${options.projectPath}`)); console.log(chalk_1.default.white(` Application Port: ${options.port}`)); console.log(chalk_1.default.white(` Application Name: ${options.appName}`)); console.log(chalk_1.default.white(` HTTPS Enabled: ${options.useHttps ? 'Yes' : 'No'}`)); console.log(chalk_1.default.white(` Configuration Type: ${options.usePredefined ? 'Predefined' : 'Custom'}`)); console.log(chalk_1.default.blue.bold('\n🌐 Your application should now be accessible at:')); console.log(chalk_1.default.white(` HTTP: http://your-domain.com`)); if (options.useHttps) { console.log(chalk_1.default.white(` HTTPS: https://your-domain.com`)); } console.log(chalk_1.default.yellow('\nšŸ’” Next steps:')); console.log(chalk_1.default.white(' 1. Make sure your Node.js application is running on port ' + options.port)); console.log(chalk_1.default.white(' 2. Ensure your domain points to this server')); console.log(chalk_1.default.white(' 3. If using HTTPS, verify SSL certificates are properly configured')); } } // CLI setup program .name('apache-node-proxy') .description('Configure Apache virtual hosts for Node.js applications') .version('1.0.1') .action(async () => { const forwarder = new ApachePortForwarder(); await forwarder.run(); }); // Add additional commands for specific use cases program .command('quick') .description('Quick setup with default values') .option('-p, --path <path>', 'Project path', process.cwd()) .option('-P, --port <port>', 'Application port', '3000') .option('-n, --name <name>', 'Application name', 'myapp') .option('--no-https', 'Disable HTTPS configuration') .action(async (options) => { const forwarder = new ApachePortForwarder(); // Implementation for quick setup console.log(chalk_1.default.blue('Quick setup mode - coming soon!')); }); program.parse(); //# sourceMappingURL=index.js.map