fix(docs, tests, acme): fix: update changelog, documentation, examples and tests for v19.4.0 release. Adjust global ACME configuration to use ssl@bleu.de and add non-privileged port examples.

This commit is contained in:
Philipp Kunz 2025-05-19 17:39:35 +00:00
parent 5c6437c5b3
commit 4b381915e1
9 changed files with 436 additions and 79 deletions

View File

@ -1,5 +1,27 @@
# Changelog # Changelog
## 2025-05-19 - 19.3.4 - fix(docs, tests, acme)
fix: update changelog, documentation, examples and tests for v19.4.0 release. Adjust global ACME configuration to use ssl@bleu.de and add non-privileged port examples.
- Updated changelog with new v19.4.0 entry detailing fixes in tests and docs
- Revised README and certificate-management.md to demonstrate global ACME settings (using ssl@bleu.de, non-privileged port support, auto-renewal configuration, and renewCheckIntervalHours)
- Added new examples (certificate-management-v19.ts and complete-example-v19.ts) and updated existing examples (dynamic port management, NFTables integration) to reflect v19.4.0 features
- Fixed test exports and port mapping issues in several test files (acme-state-manager, port80-management, race-conditions, etc.)
- Updated readme.plan.md to reflect completed refactoring and breaking changes from v19.3.3
## 2025-05-19 - 19.4.0 - fix(tests) & docs
Fix failing tests and update documentation for v19+ features
- Fix ForwardingHandlerFactory.applyDefaults to set port and socket properties correctly
- Fix route finding logic in forwarding tests to properly identify redirect routes
- Fix test exports in acme-state-manager.node.ts, port80-management.node.ts, and race-conditions.node.ts
- Update ACME email configuration to use ssl@bleu.de instead of test domains
- Update README with v19.4.0 features including global ACME configuration
- Update certificate-management.md documentation to reflect v19+ changes
- Add new examples: certificate-management-v19.ts and complete-example-v19.ts
- Update existing examples to demonstrate global ACME configuration
- Update readme.plan.md to reflect completed refactoring
## 2025-05-19 - 19.3.3 - fix(core) ## 2025-05-19 - 19.3.3 - fix(core)
No changes detected project structure and documentation remain unchanged. No changes detected project structure and documentation remain unchanged.

View File

@ -208,11 +208,18 @@ const smartproxy = new SmartProxy({
// Certificate provisioning was automatic or via certProvisionFunction // Certificate provisioning was automatic or via certProvisionFunction
``` ```
### After (v18+) ### After (v19+)
```typescript ```typescript
// New approach with route-based configuration // New approach with global ACME configuration
const smartproxy = new SmartProxy({ const smartproxy = new SmartProxy({
// Global ACME defaults (v19+)
acme: {
email: 'ssl@bleu.de',
useProduction: true,
port: 80 // Or 8080 for non-privileged
},
routes: [{ routes: [{
match: { ports: 443, domains: 'example.com' }, match: { ports: 443, domains: 'example.com' },
action: { action: {
@ -220,11 +227,7 @@ const smartproxy = new SmartProxy({
target: { host: 'localhost', port: 8080 }, target: { host: 'localhost', port: 8080 },
tls: { tls: {
mode: 'terminate', mode: 'terminate',
certificate: 'auto', certificate: 'auto' // Uses global ACME settings
acme: {
email: 'admin@example.com',
useProduction: true
}
} }
} }
}] }]
@ -235,9 +238,38 @@ const smartproxy = new SmartProxy({
### Common Issues ### Common Issues
1. **Certificate not provisioning**: Ensure port 80 is accessible for ACME challenges 1. **Certificate not provisioning**: Ensure the ACME challenge port (80 or configured port) is accessible
2. **ACME rate limits**: Use staging environment for testing 2. **ACME rate limits**: Use staging environment for testing (`useProduction: false`)
3. **Permission errors**: Ensure the certificate directory is writable 3. **Permission errors**: Ensure the certificate directory is writable
4. **Invalid email domain**: ACME servers may reject certain email domains (e.g., example.com). Use a real email domain
5. **Port binding errors**: Use higher ports (e.g., 8080) if running without root privileges
### Using Non-Privileged Ports
For development or non-root environments:
```typescript
const proxy = new SmartProxy({
acme: {
email: 'ssl@bleu.de',
port: 8080, // Use 8080 instead of 80
useProduction: false
},
routes: [
{
match: { ports: 8443, domains: 'example.com' },
action: {
type: 'forward',
target: { host: 'localhost', port: 3000 },
tls: {
mode: 'terminate',
certificate: 'auto'
}
}
}
]
});
```
### Debug Mode ### Debug Mode

View File

@ -0,0 +1,119 @@
/**
* Certificate Management Example (v19+)
*
* This example demonstrates the new global ACME configuration introduced in v19+
* along with route-level overrides for specific domains.
*/
import {
SmartProxy,
createHttpRoute,
createHttpsTerminateRoute,
createCompleteHttpsServer
} from '../dist_ts/index.js';
async function main() {
// Create a SmartProxy instance with global ACME configuration
const proxy = new SmartProxy({
// Global ACME configuration (v19+)
// These settings apply to all routes with certificate: 'auto'
acme: {
email: 'ssl@bleu.de', // Global contact email
useProduction: false, // Use staging by default
port: 8080, // Use non-privileged port
renewThresholdDays: 30, // Renew 30 days before expiry
autoRenew: true, // Enable automatic renewal
renewCheckIntervalHours: 12 // Check twice daily
},
routes: [
// Route that uses global ACME settings
createHttpsTerminateRoute('app.example.com',
{ host: 'localhost', port: 3000 },
{ certificate: 'auto' } // Uses global ACME configuration
),
// Route with route-level ACME override
{
name: 'production-api',
match: { ports: 443, domains: 'api.example.com' },
action: {
type: 'forward',
target: { host: 'localhost', port: 3001 },
tls: {
mode: 'terminate',
certificate: 'auto',
acme: {
email: 'api-certs@example.com', // Override email
useProduction: true, // Use production for API
renewThresholdDays: 60 // Earlier renewal for critical API
}
}
}
},
// Complete HTTPS server with automatic redirects
...createCompleteHttpsServer('website.example.com',
{ host: 'localhost', port: 8080 },
{ certificate: 'auto' }
),
// Static certificate (not using ACME)
{
name: 'internal-service',
match: { ports: 8443, domains: 'internal.local' },
action: {
type: 'forward',
target: { host: 'localhost', port: 3002 },
tls: {
mode: 'terminate',
certificate: {
cert: '-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----',
key: '-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----'
}
}
}
}
]
});
// Monitor certificate events
proxy.on('certificate:issued', (event) => {
console.log(`Certificate issued for ${event.domain}`);
console.log(`Expires: ${event.expiryDate}`);
});
proxy.on('certificate:renewed', (event) => {
console.log(`Certificate renewed for ${event.domain}`);
});
proxy.on('certificate:error', (event) => {
console.error(`Certificate error for ${event.domain}: ${event.error}`);
});
// Start the proxy
await proxy.start();
console.log('SmartProxy started with global ACME configuration');
// Check certificate status programmatically
setTimeout(async () => {
// Get status for a specific route
const status = proxy.getCertificateStatus('app-route');
console.log('Certificate status:', status);
// Manually trigger renewal if needed
if (status && status.status === 'expiring') {
await proxy.renewCertificate('app-route');
}
}, 10000);
// Handle shutdown gracefully
process.on('SIGINT', async () => {
console.log('Shutting down proxy...');
await proxy.stop();
process.exit(0);
});
}
// Run the example
main().catch(console.error);

View File

@ -0,0 +1,188 @@
/**
* Complete SmartProxy Example (v19+)
*
* This comprehensive example demonstrates all major features of SmartProxy v19+:
* - Global ACME configuration
* - Route-based configuration
* - Helper functions for common patterns
* - Dynamic route management
* - Certificate status monitoring
* - Error handling and recovery
*/
import {
SmartProxy,
createHttpRoute,
createHttpsTerminateRoute,
createHttpsPassthroughRoute,
createHttpToHttpsRedirect,
createCompleteHttpsServer,
createLoadBalancerRoute,
createApiRoute,
createWebSocketRoute,
createStaticFileRoute,
createNfTablesRoute
} from '../dist_ts/index.js';
async function main() {
// Create SmartProxy with comprehensive configuration
const proxy = new SmartProxy({
// Global ACME configuration (v19+)
acme: {
email: 'ssl@bleu.de',
useProduction: false, // Use staging for this example
port: 8080, // Non-privileged port for development
autoRenew: true,
renewCheckIntervalHours: 12
},
// Initial routes
routes: [
// Basic HTTP service
createHttpRoute('api.example.com', { host: 'localhost', port: 3000 }),
// HTTPS with automatic certificates
createHttpsTerminateRoute('secure.example.com',
{ host: 'localhost', port: 3001 },
{ certificate: 'auto' }
),
// Complete HTTPS server with HTTP->HTTPS redirect
...createCompleteHttpsServer('www.example.com',
{ host: 'localhost', port: 8080 },
{ certificate: 'auto' }
),
// Load balancer with multiple backends
createLoadBalancerRoute(
'app.example.com',
['10.0.0.1', '10.0.0.2', '10.0.0.3'],
8080,
{
tls: {
mode: 'terminate',
certificate: 'auto'
}
}
),
// API route with CORS
createApiRoute('api.example.com', '/v1',
{ host: 'api-backend', port: 8081 },
{
useTls: true,
certificate: 'auto',
addCorsHeaders: true
}
),
// WebSocket support
createWebSocketRoute('ws.example.com', '/socket',
{ host: 'websocket-server', port: 8082 },
{
useTls: true,
certificate: 'auto'
}
),
// Static file server
createStaticFileRoute(['cdn.example.com', 'static.example.com'],
'/var/www/static',
{
serveOnHttps: true,
certificate: 'auto'
}
),
// HTTPS passthrough for services that handle their own TLS
createHttpsPassthroughRoute('legacy.example.com',
{ host: '192.168.1.100', port: 443 }
),
// HTTP to HTTPS redirects
createHttpToHttpsRedirect(['*.example.com', 'example.com'])
],
// Enable detailed logging for debugging
enableDetailedLogging: true
});
// Event handlers
proxy.on('connection', (event) => {
console.log(`New connection: ${event.source} -> ${event.destination}`);
});
proxy.on('certificate:issued', (event) => {
console.log(`Certificate issued for ${event.domain}`);
});
proxy.on('certificate:renewed', (event) => {
console.log(`Certificate renewed for ${event.domain}`);
});
proxy.on('error', (error) => {
console.error('Proxy error:', error);
});
// Start the proxy
await proxy.start();
console.log('SmartProxy started successfully');
console.log('Listening on ports:', proxy.getListeningPorts());
// Demonstrate dynamic route management
setTimeout(async () => {
console.log('Adding new route dynamically...');
// Get current routes and add a new one
const currentRoutes = proxy.settings.routes;
const newRoutes = [
...currentRoutes,
createHttpsTerminateRoute('new-service.example.com',
{ host: 'localhost', port: 3003 },
{ certificate: 'auto' }
)
];
// Update routes
await proxy.updateRoutes(newRoutes);
console.log('New route added successfully');
}, 5000);
// Check certificate status periodically
setInterval(async () => {
const routes = proxy.settings.routes;
for (const route of routes) {
if (route.action.tls?.certificate === 'auto') {
const status = proxy.getCertificateStatus(route.name);
if (status) {
console.log(`Certificate status for ${route.name}:`, status);
// Renew if expiring soon
if (status.status === 'expiring') {
console.log(`Renewing certificate for ${route.name}...`);
await proxy.renewCertificate(route.name);
}
}
}
}
}, 3600000); // Check every hour
// Graceful shutdown
process.on('SIGINT', async () => {
console.log('Shutting down gracefully...');
await proxy.stop();
process.exit(0);
});
process.on('SIGTERM', async () => {
console.log('Received SIGTERM, shutting down...');
await proxy.stop();
process.exit(0);
});
}
// Run the example
main().catch((error) => {
console.error('Failed to start proxy:', error);
process.exit(1);
});

View File

@ -3,27 +3,25 @@
* *
* This example demonstrates how to dynamically add and remove ports * This example demonstrates how to dynamically add and remove ports
* while SmartProxy is running, without requiring a restart. * while SmartProxy is running, without requiring a restart.
* Also shows the new v19+ global ACME configuration.
*/ */
import { SmartProxy } from '../dist_ts/index.js'; import { SmartProxy, createHttpRoute, createHttpsTerminateRoute } from '../dist_ts/index.js';
import type { IRouteConfig } from '../dist_ts/index.js'; import type { IRouteConfig } from '../dist_ts/index.js';
async function main() { async function main() {
// Create a SmartProxy instance with initial routes // Create a SmartProxy instance with initial routes and global ACME config
const proxy = new SmartProxy({ const proxy = new SmartProxy({
// Global ACME configuration (v19+)
acme: {
email: 'ssl@bleu.de',
useProduction: false,
port: 8080 // Using non-privileged port for ACME challenges
},
routes: [ routes: [
// Initial route on port 8080 // Initial route on port 8080
{ createHttpRoute(['example.com', '*.example.com'], { host: 'localhost', port: 3000 })
match: {
ports: 8080,
domains: ['example.com', '*.example.com']
},
action: {
type: 'forward',
target: { host: 'localhost', port: 3000 }
},
name: 'Initial HTTP Route'
}
] ]
}); });

View File

@ -5,6 +5,7 @@
* for high-performance network routing that operates at the kernel level. * for high-performance network routing that operates at the kernel level.
* *
* NOTE: This requires elevated privileges to run (sudo) as it interacts with nftables. * NOTE: This requires elevated privileges to run (sudo) as it interacts with nftables.
* Also shows the new v19+ global ACME configuration.
*/ */
import { SmartProxy } from '../ts/proxies/smart-proxy/index.js'; import { SmartProxy } from '../ts/proxies/smart-proxy/index.js';
@ -50,15 +51,22 @@ async function simpleForwardingExample() {
async function httpsTerminationExample() { async function httpsTerminationExample() {
console.log('Starting HTTPS termination with NFTables example...'); console.log('Starting HTTPS termination with NFTables example...');
// Create a SmartProxy instance with an HTTPS termination route using NFTables // Create a SmartProxy instance with global ACME and NFTables HTTPS termination
const proxy = new SmartProxy({ const proxy = new SmartProxy({
// Global ACME configuration (v19+)
acme: {
email: 'ssl@bleu.de',
useProduction: false,
port: 80 // NFTables needs root, so we can use port 80
},
routes: [ routes: [
createNfTablesTerminateRoute('secure.example.com', { createNfTablesTerminateRoute('secure.example.com', {
host: 'localhost', host: 'localhost',
port: 8443 port: 8443
}, { }, {
ports: 443, ports: 443,
certificate: 'auto', // Automatic certificate provisioning certificate: 'auto', // Uses global ACME configuration
tableName: 'smartproxy_https' tableName: 'smartproxy_https'
}) })
], ],

View File

@ -113,7 +113,7 @@ npm install @push.rocks/smartproxy
## Quick Start with SmartProxy ## Quick Start with SmartProxy
SmartProxy v18.0.0 continues the evolution of the unified route-based configuration system making your proxy setup more flexible and intuitive with improved helper functions and NFTables integration for high-performance kernel-level routing. SmartProxy v19.4.0 provides a unified route-based configuration system with enhanced certificate management, NFTables integration for high-performance kernel-level routing, and improved helper functions for common proxy setups.
```typescript ```typescript
import { import {
@ -136,10 +136,12 @@ import {
const proxy = new SmartProxy({ const proxy = new SmartProxy({
// Global ACME settings for all routes with certificate: 'auto' // Global ACME settings for all routes with certificate: 'auto'
acme: { acme: {
email: 'ssl@example.com', // Required for Let's Encrypt email: 'ssl@bleu.de', // Required for Let's Encrypt
useProduction: false, // Use staging by default useProduction: false, // Use staging by default
renewThresholdDays: 30, // Renew 30 days before expiry renewThresholdDays: 30, // Renew 30 days before expiry
port: 80 // Port for HTTP-01 challenges port: 80, // Port for HTTP-01 challenges (use 8080 for non-privileged)
autoRenew: true, // Enable automatic renewal
renewCheckIntervalHours: 24 // Check for renewals daily
}, },
// Define all your routing rules in a single array // Define all your routing rules in a single array
@ -216,26 +218,7 @@ const proxy = new SmartProxy({
certificate: 'auto', certificate: 'auto',
maxRate: '100mbps' maxRate: '100mbps'
}) })
], ]
// Global settings that apply to all routes
defaults: {
security: {
maxConnections: 500
}
},
// Automatic Let's Encrypt integration
acme: {
enabled: true,
contactEmail: 'admin@example.com',
useProduction: true
}
});
// Listen for certificate events
proxy.on('certificate', evt => {
console.log(`Certificate for ${evt.domain} ready, expires: ${evt.expiryDate}`);
}); });
// Start the proxy // Start the proxy

View File

@ -1,22 +1,15 @@
# SmartProxy Architecture Refactoring Plan # SmartProxy v19.4.0 - Completed Refactoring
## Overview ## Overview
Refactor the proxy architecture to provide clearer separation of concerns between HTTP/HTTPS traffic handling and low-level connection routing. SmartProxy has been successfully refactored with clearer separation of concerns between HTTP/HTTPS traffic handling and low-level connection routing. Version 19.4.0 introduces global ACME configuration and enhanced route management.
## Current Architecture Problems ## Current Architecture (v19.4.0)
1. NetworkProxy name doesn't clearly indicate it handles HTTP/HTTPS ### HttpProxy (formerly NetworkProxy)
2. HTTP parsing logic is duplicated in RouteConnectionHandler
3. Redirect and static route handling is embedded in SmartProxy
4. Unclear separation between TCP routing and HTTP processing
## Proposed Architecture
### HttpProxy (renamed from NetworkProxy)
**Purpose**: Handle all HTTP/HTTPS traffic with TLS termination **Purpose**: Handle all HTTP/HTTPS traffic with TLS termination
**Responsibilities**: **Current Responsibilities**:
- TLS termination for HTTPS - TLS termination for HTTPS
- HTTP/1.1 and HTTP/2 protocol handling - HTTP/1.1 and HTTP/2 protocol handling
- HTTP request/response parsing - HTTP request/response parsing
@ -25,29 +18,33 @@ Refactor the proxy architecture to provide clearer separation of concerns betwee
- Static route handlers - Static route handlers
- WebSocket protocol upgrades - WebSocket protocol upgrades
- Connection pooling for backend servers - Connection pooling for backend servers
- Certificate management (ACME and static) - Certificate management integration
### SmartProxy ### SmartProxy
**Purpose**: Low-level connection router and port manager **Purpose**: Central API for all proxy needs with route-based configuration
**Responsibilities**: **Current Responsibilities**:
- Port management (listen on multiple ports) - Port management (listen on multiple ports)
- Route-based connection routing - Route-based connection routing
- TLS passthrough (SNI-based routing) - TLS passthrough (SNI-based routing)
- NFTables integration - NFTables integration
- Delegate HTTP/HTTPS connections to HttpProxy - Certificate management via SmartCertManager
- Raw TCP proxying - Raw TCP proxying
- Connection lifecycle management - Connection lifecycle management
- Global ACME configuration (v19+)
## Implementation Plan ## Completed Implementation
### Phase 1: Rename and Reorganize NetworkProxy ✅ ### Phase 1: Rename and Reorganize ✅
- NetworkProxy renamed to HttpProxy
- Directory structure reorganized
- All imports and references updated
1. **Rename NetworkProxy to HttpProxy** ### Phase 2: Certificate Management ✅
- Renamed directory from `network-proxy` to `http-proxy` - Unified certificate management in SmartCertManager
- Updated all imports and references - Global ACME configuration support (v19+)
- Route-level certificate overrides
2. **Update class and file names** - Automatic renewal system
- Renamed `network-proxy.ts` to `http-proxy.ts` - Renamed `network-proxy.ts` to `http-proxy.ts`
- Updated `NetworkProxy` class to `HttpProxy` class - Updated `NetworkProxy` class to `HttpProxy` class
- Updated all type definitions and interfaces - Updated all type definitions and interfaces
@ -157,16 +154,26 @@ After this refactoring, we can more easily add:
4. Protocol-specific optimizations 4. Protocol-specific optimizations
5. Better HTTP/2 multiplexing 5. Better HTTP/2 multiplexing
## Breaking Changes ## Breaking Changes from v18 to v19
1. `NetworkProxy` class renamed to `HttpProxy` 1. `NetworkProxy` class renamed to `HttpProxy`
2. Import paths change from `network-proxy` to `http-proxy` 2. Import paths change from `network-proxy` to `http-proxy`
3. Some type names may change for consistency 3. Global ACME configuration now available at the top level
4. Certificate management unified under SmartCertManager
## Rollback Plan ## Future Enhancements
If issues arise: 1. HTTP/3 (QUIC) support in HttpProxy
1. Git revert to previous commit 2. Advanced HTTP features (compression, caching)
2. Re-deploy previous version 3. HTTP middleware system
3. Document lessons learned 4. Protocol-specific optimizations
4. Plan incremental changes 5. Better HTTP/2 multiplexing
6. Enhanced monitoring and metrics
## Key Features in v19.4.0
1. **Global ACME Configuration**: Default settings for all routes with `certificate: 'auto'`
2. **Enhanced Route Management**: Better separation between routing and certificate management
3. **Improved Test Coverage**: Fixed test exports and port bindings
4. **Better Error Messages**: Clear guidance for ACME configuration issues
5. **Non-Privileged Port Support**: Examples for development environments

View File

@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@push.rocks/smartproxy', name: '@push.rocks/smartproxy',
version: '19.3.3', version: '19.3.4',
description: 'A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.' description: 'A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.'
} }