fix(core): Refactor filesystem usage to smartfs async provider, update dependencies, tests and nginx config paths

This commit is contained in:
2025-11-27 13:14:58 +00:00
parent 5700522b8a
commit 5781204c88
16 changed files with 7766 additions and 4139 deletions

270
readme.md
View File

@@ -1,81 +1,255 @@
# @push.rocks/smartnginx
control nginx from node, TypeScript ready
Control Nginx programmatically from Node.js with full TypeScript support 🚀
## Issue Reporting and Security
For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
## Features
- 🎯 **Dynamic Configuration** - Generate and manage Nginx configs on the fly
- 🔒 **SSL/TLS Ready** - Built-in support for SSL certificates with automatic HTTP→HTTPS redirects
- 🔄 **Hot Reload** - Apply configuration changes without downtime
- 📦 **Zero-Config Defaults** - Self-signed certificates auto-generated for immediate testing
- 🎛️ **Reverse Proxy Made Easy** - Set up proxy hosts with a single method call
- 🧠 **Smart Diffing** - Only reloads Nginx when configurations actually change
- 📝 **TypeScript First** - Full type definitions included
## Install
To install `@push.rocks/smartnginx`, you can use npm (Node Package Manager). Open your terminal and run:
```bash
npm install @push.rocks/smartnginx --save
pnpm add @push.rocks/smartnginx
# or
npm install @push.rocks/smartnginx
```
This will download and install `@push.rocks/smartnginx` and its dependencies into your project's `node_modules` folder and save it as a dependency in your project's `package.json` file.
> **Prerequisites**: Nginx must be installed and available in your system PATH.
## Quick Start
```typescript
import { SmartNginx } from '@push.rocks/smartnginx';
// Create a SmartNginx instance with a default fallback URL
const nginx = new SmartNginx({
defaultProxyUrl: 'https://your-default-site.com'
});
// Add a reverse proxy host
nginx.addHostCandidate({
hostName: 'api.example.com',
destination: 'localhost',
destinationPort: 3000,
privateKey: '<your-ssl-private-key>',
publicKey: '<your-ssl-certificate>'
});
// Deploy and start Nginx
await nginx.deploy();
```
That's it! Your reverse proxy is now running 🎉
## Usage
`@push.rocks/smartnginx` is a powerful library for interacting with Nginx programmatically using Node.js and TypeScript. It simplifies tasks such as configuring hosts, deploying configurations, and managing SSL certificates. Below is a comprehensive guide to using the library effectively in your TypeScript projects.
### Getting Started
First, ensure you have imported the library into your TypeScript file. Use ESM syntax as shown:
```typescript
import { SmartNginx, NginxHost } from '@push.rocks/smartnginx';
```
### Creating the SmartNginx Instance
The `SmartNginx` class is your main interface for managing Nginx:
### Initialize SmartNginx
Before you interact with Nginx, you need to create an instance of `SmartNginx`. This object acts as the main interface to your Nginx server. You can specify a default proxy URL that requests will be redirected to if no matching host is found.
```typescript
const smartNginx = new SmartNginx({
defaultProxyUrl: 'https://your-default-url.com'
import { SmartNginx } from '@push.rocks/smartnginx';
const nginx = new SmartNginx({
defaultProxyUrl: 'https://fallback.example.com', // Where unmatched requests go
logger: myCustomLogger // Optional: pass a @push.rocks/smartlog instance
});
```
### Add Host Candidates
To serve content or applications via Nginx, you will define hosts. Each host corresponds to a domain or subdomain and can be configured with specific rules. Here's how to add host candidates:
### Adding Host Configurations
Each host represents a domain/subdomain with its proxy rules and SSL certificates:
```typescript
const myHost = smartNginx.addHostCandidate({
hostName: 'example.com',
// Add a host using addHostCandidate()
const myHost = nginx.addHostCandidate({
hostName: 'app.example.com', // Domain name
destination: '127.0.0.1', // Backend server address
destinationPort: 8080, // Backend port
privateKey: sslPrivateKeyPem, // SSL private key (PEM format)
publicKey: sslCertificatePem // SSL certificate (PEM format)
});
```
### Multi-Host Setup
Run multiple sites through a single Nginx instance:
```typescript
// Production API
nginx.addHostCandidate({
hostName: 'api.myapp.com',
destination: 'localhost',
destinationPort: 3000,
privateKey: apiPrivateKey,
publicKey: apiCertificate
});
// Admin panel
nginx.addHostCandidate({
hostName: 'admin.myapp.com',
destination: 'localhost',
destinationPort: 4000,
privateKey: adminPrivateKey,
publicKey: adminCertificate
});
// Staging environment
nginx.addHostCandidate({
hostName: 'staging.myapp.com',
destination: '192.168.1.100',
destinationPort: 8080,
privateKey: '<Your SSL Private Key>',
publicKey: '<Your SSL Public Key>'
privateKey: stagingPrivateKey,
publicKey: stagingCertificate
});
// Deploy all at once
await nginx.deploy();
```
Replace `'example.com'`, `'localhost'`, `8080`, `'<Your SSL Private Key>'`, and `'<Your SSL Public Key>'` with your actual host name, destination IP or hostname, port number, and SSL keys respectively.
### Deploying Configuration
After adding all your host candidates, you will need to apply these configurations for Nginx to recognize and use them. Deploy the configuration as follows:
### Deploying Configurations
The `deploy()` method is smart about changes:
```typescript
await smartNginx.deploy();
```
This method checks for any changes in your host configurations compared to what's currently deployed and updates the Nginx configuration accordingly.
// First deploy - writes configs and starts Nginx
await nginx.deploy();
### Managing SSL Certificates
When setting up SSL for your hosts, you will provide the paths to the private key and public certificate. It's essential to ensure these files are securely stored and accessible by the library during deployment.
### Handling Multiple Hosts
You can add multiple host candidates using `addHostCandidate` method for different domains or subdomains, each with unique configurations. Here's an example of adding another host:
```typescript
const anotherHost = smartNginx.addHostCandidate({
hostName: 'sub.example.com',
// Add more hosts dynamically
nginx.addHostCandidate({
hostName: 'newsite.example.com',
destination: 'localhost',
destinationPort: 9090,
privateKey: '<Another SSL Private Key>',
publicKey: '<Another SSL Public Key>'
destinationPort: 5000,
privateKey: newPrivateKey,
publicKey: newCertificate
});
// Second deploy - detects changes, updates configs, hot-reloads Nginx
await nginx.deploy();
// If you call deploy() with no changes, it skips the reload (efficient!)
await nginx.deploy(); // → "hosts have not diverged, skipping nginx reload"
```
### Reloading Configurations
If at any time you make changes to your host configurations and need to apply these changes, simply call the `deploy` method again. `@push.rocks/smartnginx` efficiently detects changes and reloads Nginx with the new configurations.
### Querying Deployed Hosts
### Stopping SmartNginx
To stop the Nginx process managed by `@push.rocks/smartnginx`, use:
```typescript
await smartNginx.stop();
```
Bear in mind that this might affect your web services if they rely on the Nginx instance you are stopping.
// Get all deployed hosts
const hosts = await nginx.listDeployedHosts();
console.log(`Running ${hosts.length} hosts`);
### Conclusion
`@push.rocks/smartnginx` abstracts away much of the complexity involved in managing Nginx configurations, offering a TypeScript-ready solution for Node.js projects. With simple method calls, you can automate and manage your Nginx server programmatically, making it an excellent tool for developers seeking to integrate Nginx management into their applications or deployment workflows.
// Find a specific host by domain
const apiHost = nginx.getDeployedNginxHostByHostName('api.example.com');
if (apiHost) {
console.log(`API proxying to ${apiHost.destination}:${apiHost.destinationPort}`);
}
```
### Removing Hosts
```typescript
const hostToRemove = nginx.getDeployedNginxHostByHostName('staging.myapp.com');
if (hostToRemove) {
await nginx.removeDeployedHost(hostToRemove);
// Nginx automatically reloaded with updated config
}
```
### Stopping Nginx
```typescript
// Gracefully stop the Nginx process
await nginx.stop();
```
## Generated Configuration
SmartNginx generates production-ready Nginx configurations:
**For each host, you get:**
- HTTP (port 80) → HTTPS (port 443) automatic redirect
- Upstream with keepalive connections (100 idle connections)
- WebSocket-friendly proxy settings (HTTP/1.1, no buffering)
- Proper proxy headers (`X-Real-IP`, `X-Forwarded-For`, `X-Forwarded-Proto`)
- Smart failover (`proxy_next_upstream` on errors, timeouts, 404/429/500/502)
**Default server:**
- Self-signed certificate for unmatched domains
- Redirects to your configured `defaultProxyUrl`
## Architecture
```
┌─────────────────────────────────────────────────────────────┐
│ SmartNginx │
├─────────────────────────────────────────────────────────────┤
│ hostCandidates[] → deploy() → deployedHosts[] │
│ ↓ │
│ NginxProcess │
│ (start/reload/stop) │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Generated Files │
├─────────────────────────────────────────────────────────────┤
│ nginxconfig/ │
│ ├── nginx.conf (main config) │
│ └── hosts/ │
│ ├── default.private.pem (self-signed key) │
│ ├── default.public.pem (self-signed cert) │
│ ├── api.example.com.conf │
│ ├── api.example.com.private.pem │
│ └── api.example.com.public.pem │
└─────────────────────────────────────────────────────────────┘
```
## API Reference
### SmartNginx
| Method | Description |
|--------|-------------|
| `addHostCandidate(config)` | Add a new host configuration |
| `deploy()` | Write configs and start/reload Nginx |
| `listDeployedHosts()` | Get all currently deployed hosts |
| `getDeployedNginxHostByHostName(hostname)` | Find a host by domain name |
| `removeDeployedHost(host)` | Remove a host and reload Nginx |
| `stop()` | Gracefully stop Nginx |
### IHostConfig
```typescript
interface IHostConfig {
hostName: string; // Domain name (e.g., 'api.example.com')
destination: string; // Backend server IP/hostname
destinationPort: number; // Backend port
privateKey: string; // SSL private key (PEM)
publicKey: string; // SSL certificate (PEM)
}
```
### NginxHost
Each host instance exposes:
- `hostName` - The configured domain
- `destination` - Backend address
- `destinationPort` - Backend port
- `configString` - The generated Nginx config (after deploy)
- `deploy()` - Write this host's config files
## License and Legal Information
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
@@ -85,7 +259,7 @@ This project is owned and maintained by Task Venture Capital GmbH. The names and
### Company Information
Task Venture Capital GmbH
Task Venture Capital GmbH
Registered at District court Bremen HRB 35230 HB, Germany
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.