apache-node-proxy
Version:
CLI tool to automatically configure Apache virtual hosts for Node.js applications
242 lines ⢠10.7 kB
JavaScript
;
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