feat(smartproxy): Update documentation and route helper functions; add createPortRange, createSecurityConfig, createStaticFileRoute, and createTestRoute helpers to the readme and tests. Refactor test examples to use the new helper API and remove legacy connection handling files (including the old connection handler and PortRangeManager) to fully embrace the unified route‐based configuration.

This commit is contained in:
Philipp Kunz 2025-05-10 07:34:35 +00:00
parent 36bea96ac7
commit b4a0e4be6b
14 changed files with 458 additions and 193 deletions

View File

@ -1,5 +1,12 @@
# Changelog # Changelog
## 2025-05-10 - 15.1.0 - feat(smartproxy)
Update documentation and route helper functions; add createPortRange, createSecurityConfig, createStaticFileRoute, and createTestRoute helpers to the readme and tests. Refactor test examples to use the new helper API and remove legacy connection handling files (including the old connection handler and PortRangeManager) to fully embrace the unified routebased configuration.
- Added new helper functions (createPortRange, createSecurityConfig, createStaticFileRoute, createTestRoute) in readme and route helpers.
- Refactored tests (test.forwarding.examples.ts, test.forwarding.unit.ts, etc.) to update references to the new API.
- Removed legacy connection handler and PortRangeManager files to simplify code and align with routebased configuration.
## 2025-05-10 - 15.0.0 - BREAKING CHANGE(documentation) ## 2025-05-10 - 15.0.0 - BREAKING CHANGE(documentation)
Update readme documentation to comprehensively describe the new unified route-based configuration system in v14.0.0 Update readme documentation to comprehensively describe the new unified route-based configuration system in v14.0.0

View File

@ -463,6 +463,10 @@ Available helper functions:
- `createBlockRoute()` - Create a route to block specific traffic - `createBlockRoute()` - Create a route to block specific traffic
- `createLoadBalancerRoute()` - Create a route for load balancing - `createLoadBalancerRoute()` - Create a route for load balancing
- `createHttpsServer()` - Create a complete HTTPS server setup with HTTP redirect - `createHttpsServer()` - Create a complete HTTPS server setup with HTTP redirect
- `createPortRange()` - Helper to create port range configurations from various formats
- `createSecurityConfig()` - Helper to create security configuration objects
- `createStaticFileRoute()` - Create a route for serving static files
- `createTestRoute()` - Create a test route for debugging and testing purposes
## What You Can Do with SmartProxy ## What You Can Do with SmartProxy

View File

@ -1,112 +1,197 @@
import * as plugins from '../ts/plugins.js'; import * as path from 'path';
import { tap, expect } from '@push.rocks/tapbundle'; import { tap, expect } from '@push.rocks/tapbundle';
import { SmartProxy } from '../ts/proxies/smart-proxy/index.js'; import { SmartProxy } from '../ts/proxies/smart-proxy/index.js';
import type { TForwardingType } from '../ts/forwarding/config/forwarding-types.js';
import type { IDomainConfig } from '../ts/forwarding/config/domain-config.js';
import { import {
httpOnly, createHttpRoute,
httpsPassthrough, createHttpsRoute,
tlsTerminateToHttp, createPassthroughRoute,
tlsTerminateToHttps createRedirectRoute,
} from '../ts/forwarding/config/forwarding-types.js'; createHttpToHttpsRedirect,
createBlockRoute,
createLoadBalancerRoute,
createHttpsServer,
createPortRange,
createSecurityConfig,
createStaticFileRoute,
createTestRoute
} from '../ts/proxies/smart-proxy/route-helpers/index.js';
import type { IRouteConfig } from '../ts/proxies/smart-proxy/models/route-types.js';
// Test to demonstrate various forwarding configurations // Test to demonstrate various route configurations using the new helpers
tap.test('Forwarding configuration examples', async (tools) => { tap.test('Route-based configuration examples', async (tools) => {
// Example 1: HTTP-only configuration // Example 1: HTTP-only configuration
const httpOnlyConfig: IDomainConfig = { const httpOnlyRoute = createHttpRoute({
domains: ['http.example.com'], domains: 'http.example.com',
forwarding: httpOnly({
target: { target: {
host: 'localhost', host: 'localhost',
port: 3000 port: 3000
}, },
security: { security: {
allowedIps: ['*'] // Allow all allowedIps: ['*'] // Allow all
} },
}) name: 'Basic HTTP Route'
}; });
console.log(httpOnlyConfig.forwarding, 'HTTP-only configuration created successfully');
expect(httpOnlyConfig.forwarding.type).toEqual('http-only');
// Example 2: HTTPS Passthrough (SNI) console.log('HTTP-only route created successfully:', httpOnlyRoute.name);
const httpsPassthroughConfig: IDomainConfig = { expect(httpOnlyRoute.action.type).toEqual('forward');
domains: ['pass.example.com'], expect(httpOnlyRoute.match.domains).toEqual('http.example.com');
forwarding: httpsPassthrough({
// Example 2: HTTPS Passthrough (SNI) configuration
const httpsPassthroughRoute = createPassthroughRoute({
domains: 'pass.example.com',
target: { target: {
host: ['10.0.0.1', '10.0.0.2'], // Round-robin target IPs host: ['10.0.0.1', '10.0.0.2'], // Round-robin target IPs
port: 443 port: 443
}, },
security: { security: {
allowedIps: ['*'] // Allow all allowedIps: ['*'] // Allow all
} },
}) name: 'HTTPS Passthrough Route'
}; });
expect(httpsPassthroughConfig.forwarding).toBeTruthy();
expect(httpsPassthroughConfig.forwarding.type).toEqual('https-passthrough'); expect(httpsPassthroughRoute).toBeTruthy();
expect(Array.isArray(httpsPassthroughConfig.forwarding.target.host)).toBeTrue(); expect(httpsPassthroughRoute.action.tls?.mode).toEqual('passthrough');
expect(Array.isArray(httpsPassthroughRoute.action.target?.host)).toBeTrue();
// Example 3: HTTPS Termination to HTTP Backend // Example 3: HTTPS Termination to HTTP Backend
const terminateToHttpConfig: IDomainConfig = { const terminateToHttpRoute = createHttpsRoute({
domains: ['secure.example.com'], domains: 'secure.example.com',
forwarding: tlsTerminateToHttp({
target: { target: {
host: 'localhost', host: 'localhost',
port: 8080 port: 8080
}, },
http: { tlsMode: 'terminate',
redirectToHttps: true, // Redirect HTTP requests to HTTPS certificate: 'auto',
headers: { headers: {
'X-Forwarded-Proto': 'https' 'X-Forwarded-Proto': 'https'
}
},
acme: {
enabled: true,
maintenance: true,
production: false // Use staging ACME server for testing
}, },
security: { security: {
allowedIps: ['*'] // Allow all allowedIps: ['*'] // Allow all
}
})
};
expect(terminateToHttpConfig.forwarding).toBeTruthy();
expect(terminateToHttpConfig.forwarding.type).toEqual('https-terminate-to-http');
expect(terminateToHttpConfig.forwarding.http?.redirectToHttps).toBeTrue();
// Example 4: HTTPS Termination to HTTPS Backend
const terminateToHttpsConfig: IDomainConfig = {
domains: ['proxy.example.com'],
forwarding: tlsTerminateToHttps({
target: {
host: 'internal-api.local',
port: 8443
}, },
https: { name: 'HTTPS Termination to HTTP Backend'
forwardSni: true // Forward original SNI info });
// Create the HTTP to HTTPS redirect for this domain
const httpToHttpsRedirect = createHttpToHttpsRedirect({
domains: 'secure.example.com',
name: 'HTTP to HTTPS Redirect for secure.example.com'
});
expect(terminateToHttpRoute).toBeTruthy();
expect(terminateToHttpRoute.action.tls?.mode).toEqual('terminate');
expect(terminateToHttpRoute.action.advanced?.headers?.['X-Forwarded-Proto']).toEqual('https');
expect(httpToHttpsRedirect.action.type).toEqual('redirect');
// Example 4: Load Balancer with HTTPS
const loadBalancerRoute = createLoadBalancerRoute({
domains: 'proxy.example.com',
targets: ['internal-api-1.local', 'internal-api-2.local'],
targetPort: 8443,
tlsMode: 'terminate-and-reencrypt',
certificate: 'auto',
headers: {
'X-Original-Host': '{domain}'
}, },
security: { security: {
allowedIps: ['10.0.0.0/24', '192.168.1.0/24'], allowedIps: ['10.0.0.0/24', '192.168.1.0/24'],
maxConnections: 1000 maxConnections: 1000
}, },
advanced: { name: 'Load Balanced HTTPS Route'
timeout: 3600000, // 1 hour in ms });
expect(loadBalancerRoute).toBeTruthy();
expect(loadBalancerRoute.action.tls?.mode).toEqual('terminate-and-reencrypt');
expect(Array.isArray(loadBalancerRoute.action.target?.host)).toBeTrue();
expect(loadBalancerRoute.action.security?.allowedIps?.length).toEqual(2);
// Example 5: Block specific IPs
const blockRoute = createBlockRoute({
ports: [80, 443],
clientIp: ['192.168.5.0/24'],
name: 'Block Suspicious IPs',
priority: 1000 // High priority to ensure it's evaluated first
});
expect(blockRoute.action.type).toEqual('block');
expect(blockRoute.match.clientIp?.length).toEqual(1);
expect(blockRoute.priority).toEqual(1000);
// Example 6: Complete HTTPS Server with HTTP Redirect
const httpsServerRoutes = createHttpsServer({
domains: 'complete.example.com',
target: {
host: 'localhost',
port: 8080
},
certificate: 'auto',
name: 'Complete HTTPS Server'
});
expect(Array.isArray(httpsServerRoutes)).toBeTrue();
expect(httpsServerRoutes.length).toEqual(2); // HTTPS route and HTTP redirect
expect(httpsServerRoutes[0].action.tls?.mode).toEqual('terminate');
expect(httpsServerRoutes[1].action.type).toEqual('redirect');
// Example 7: Static File Server
const staticFileRoute = createStaticFileRoute({
domains: 'static.example.com',
targetDirectory: '/var/www/static',
tlsMode: 'terminate',
certificate: 'auto',
headers: { headers: {
'X-Original-Host': '{sni}' 'Cache-Control': 'public, max-age=86400'
} },
} name: 'Static File Server'
}) });
};
expect(terminateToHttpsConfig.forwarding).toBeTruthy();
expect(terminateToHttpsConfig.forwarding.type).toEqual('https-terminate-to-https');
expect(terminateToHttpsConfig.forwarding.https?.forwardSni).toBeTrue();
expect(terminateToHttpsConfig.forwarding.security?.allowedIps?.length).toEqual(2);
// Skip the SmartProxy integration test for now and just verify our configuration objects work expect(staticFileRoute.action.advanced?.staticFiles?.directory).toEqual('/var/www/static');
console.log('All forwarding configurations were created successfully'); expect(staticFileRoute.action.advanced?.headers?.['Cache-Control']).toEqual('public, max-age=86400');
// This is just to verify that our test passes // Example 8: Test Route for Debugging
expect(true).toBeTrue(); const testRoute = createTestRoute({
ports: 8000,
domains: 'test.example.com',
response: {
status: 200,
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ status: 'ok', message: 'API is working!' })
}
});
expect(testRoute.match.ports).toEqual(8000);
expect(testRoute.action.advanced?.testResponse?.status).toEqual(200);
// Create a SmartProxy instance with all routes
const allRoutes: IRouteConfig[] = [
httpOnlyRoute,
httpsPassthroughRoute,
terminateToHttpRoute,
httpToHttpsRedirect,
loadBalancerRoute,
blockRoute,
...httpsServerRoutes,
staticFileRoute,
testRoute
];
// We're not actually starting the SmartProxy in this test,
// just verifying that the configuration is valid
const smartProxy = new SmartProxy({
routes: allRoutes,
acme: {
email: 'admin@example.com',
termsOfServiceAgreed: true,
directoryUrl: 'https://acme-staging-v02.api.letsencrypt.org/directory'
}
});
console.log(`Smart Proxy configured with ${allRoutes.length} routes`);
// Verify our example proxy was created correctly
expect(smartProxy).toBeTruthy();
}); });
export default tap.start(); export default tap.start();

View File

@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@push.rocks/smartproxy', name: '@push.rocks/smartproxy',
version: '15.0.0', version: '15.1.0',
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.'
} }

View File

@ -61,6 +61,25 @@ export interface IRouteRedirect {
status: 301 | 302 | 307 | 308; status: 301 | 302 | 307 | 308;
} }
/**
* Authentication options
*/
export interface IRouteAuthentication {
type: 'basic' | 'digest' | 'oauth' | 'jwt';
credentials?: {
username: string;
password: string;
}[];
realm?: string;
jwtSecret?: string;
jwtIssuer?: string;
oauthProvider?: string;
oauthClientId?: string;
oauthClientSecret?: string;
oauthRedirectUri?: string;
[key: string]: any; // Allow additional auth-specific options
}
/** /**
* Security options for route actions * Security options for route actions
*/ */
@ -68,10 +87,28 @@ export interface IRouteSecurity {
allowedIps?: string[]; allowedIps?: string[];
blockedIps?: string[]; blockedIps?: string[];
maxConnections?: number; maxConnections?: number;
authentication?: { authentication?: IRouteAuthentication;
type: 'basic' | 'digest' | 'oauth'; }
// Auth-specific options would go here
}; /**
* Static file server configuration
*/
export interface IRouteStaticFiles {
directory: string;
indexFiles?: string[];
cacheControl?: string;
expires?: number;
followSymlinks?: boolean;
disableDirectoryListing?: boolean;
}
/**
* Test route response configuration
*/
export interface IRouteTestResponse {
status: number;
headers: Record<string, string>;
body: string;
} }
/** /**
@ -81,6 +118,8 @@ export interface IRouteAdvanced {
timeout?: number; timeout?: number;
headers?: Record<string, string>; headers?: Record<string, string>;
keepAlive?: boolean; keepAlive?: boolean;
staticFiles?: IRouteStaticFiles;
testResponse?: IRouteTestResponse;
// Additional advanced options would go here // Additional advanced options would go here
} }

View File

@ -377,16 +377,10 @@ export class NetworkProxyBridge {
publicKey: certCert, publicKey: certCert,
destinationIps: targetHosts, destinationIps: targetHosts,
destinationPorts: [targetPort], destinationPorts: [targetPort],
proxyConfig: { // Use backendProtocol for TLS re-encryption:
targetIsTls: route.action.tls.mode === 'terminate-and-reencrypt', backendProtocol: route.action.tls.mode === 'terminate-and-reencrypt' ? 'http2' : 'http1',
allowHTTP1: true, // Add rewriteHostHeader for host header handling:
// Apply any other NetworkProxy-specific settings rewriteHostHeader: route.action.advanced?.headers ? true : false
...(route.action.advanced ? {
preserveHost: true,
timeout: route.action.advanced.timeout,
headers: route.action.advanced.headers
} : {})
}
}; };
configs.push(config); configs.push(config);

View File

@ -741,20 +741,7 @@ export class RouteConnectionHandler {
this.connectionManager.incrementTerminationStat('outgoing', 'connection_failed'); this.connectionManager.incrementTerminationStat('outgoing', 'connection_failed');
} }
// If we have a forwarding handler for this domain, let it handle the error // Route-based configuration doesn't use domain handlers
if (domainConfig) {
try {
const forwardingHandler = this.domainConfigManager.getForwardingHandler(domainConfig);
forwardingHandler.emit('connection_error', {
socket,
error: err,
connectionId
});
} catch (handlerErr) {
// If getting the handler fails, just log and continue with normal cleanup
console.log(`Error getting forwarding handler for error handling: ${handlerErr}`);
}
}
// Clean up the connection // Clean up the connection
this.connectionManager.initiateCleanupOnce(record, `connection_failed_${code}`); this.connectionManager.initiateCleanupOnce(record, `connection_failed_${code}`);
@ -887,8 +874,8 @@ export class RouteConnectionHandler {
`${ `${
serverName serverName
? ` (SNI: ${serverName})` ? ` (SNI: ${serverName})`
: domainConfig : record.lockedDomain
? ` (Port-based for domain: ${domainConfig.domains.join(', ')})` ? ` (Domain: ${record.lockedDomain})`
: '' : ''
}` + }` +
` TLS: ${record.isTLS ? 'Yes' : 'No'}, Keep-Alive: ${ ` TLS: ${record.isTLS ? 'Yes' : 'No'}, Keep-Alive: ${
@ -901,8 +888,8 @@ export class RouteConnectionHandler {
`${ `${
serverName serverName
? ` (SNI: ${serverName})` ? ` (SNI: ${serverName})`
: domainConfig : record.lockedDomain
? ` (Port-based for domain: ${domainConfig.domains.join(', ')})` ? ` (Domain: ${record.lockedDomain})`
: '' : ''
}` }`
); );

View File

@ -6,7 +6,8 @@ import type {
IRouteTls, IRouteTls,
IRouteRedirect, IRouteRedirect,
IRouteSecurity, IRouteSecurity,
IRouteAdvanced IRouteAdvanced,
TPortRange
} from './models/route-types.js'; } from './models/route-types.js';
/** /**
@ -342,3 +343,155 @@ export function createHttpsServer(
return routes; return routes;
} }
/**
* Create a port range configuration from various input formats
*/
export function createPortRange(
ports: number | number[] | string | Array<{ from: number; to: number }>
): TPortRange {
// If it's a string like "80,443" or "8000-9000", parse it
if (typeof ports === 'string') {
if (ports.includes('-')) {
// Handle range like "8000-9000"
const [start, end] = ports.split('-').map(p => parseInt(p.trim(), 10));
return [{ from: start, to: end }];
} else if (ports.includes(',')) {
// Handle comma-separated list like "80,443,8080"
return ports.split(',').map(p => parseInt(p.trim(), 10));
} else {
// Handle single port as string
return parseInt(ports.trim(), 10);
}
}
// Otherwise return as is
return ports;
}
/**
* Create a security configuration object
*/
export function createSecurityConfig(
options: {
allowedIps?: string[];
blockedIps?: string[];
maxConnections?: number;
authentication?: {
type: 'basic' | 'digest' | 'oauth';
// Auth-specific options
[key: string]: any;
};
}
): IRouteSecurity {
return {
...(options.allowedIps ? { allowedIps: options.allowedIps } : {}),
...(options.blockedIps ? { blockedIps: options.blockedIps } : {}),
...(options.maxConnections ? { maxConnections: options.maxConnections } : {}),
...(options.authentication ? { authentication: options.authentication } : {})
};
}
/**
* Create a static file server route
*/
export function createStaticFileRoute(
options: {
ports?: number | number[]; // Default: 80
domains: string | string[];
path?: string;
targetDirectory: string;
tlsMode?: 'terminate' | 'terminate-and-reencrypt';
certificate?: 'auto' | { key: string; cert: string };
headers?: Record<string, string>;
security?: IRouteSecurity;
name?: string;
description?: string;
priority?: number;
tags?: string[];
}
): IRouteConfig {
const useTls = options.tlsMode !== undefined;
const defaultPort = useTls ? 443 : 80;
return createRoute(
{
ports: options.ports || defaultPort,
domains: options.domains,
...(options.path ? { path: options.path } : {})
},
{
type: 'forward',
target: {
host: 'localhost', // Static file serving is typically handled locally
port: 0, // Special value indicating a static file server
preservePort: false
},
...(useTls ? {
tls: {
mode: options.tlsMode!,
certificate: options.certificate || 'auto'
}
} : {}),
advanced: {
...(options.headers ? { headers: options.headers } : {}),
staticFiles: {
directory: options.targetDirectory,
indexFiles: ['index.html', 'index.htm']
}
},
...(options.security ? { security: options.security } : {})
},
{
name: options.name || 'Static File Server',
description: options.description || `Serving static files from ${options.targetDirectory}`,
priority: options.priority,
tags: options.tags
}
);
}
/**
* Create a test route for debugging purposes
*/
export function createTestRoute(
options: {
ports?: number | number[]; // Default: 8000
domains?: string | string[];
path?: string;
response?: {
status?: number;
headers?: Record<string, string>;
body?: string;
};
name?: string;
}
): IRouteConfig {
return createRoute(
{
ports: options.ports || 8000,
...(options.domains ? { domains: options.domains } : {}),
...(options.path ? { path: options.path } : {})
},
{
type: 'forward',
target: {
host: 'test', // Special value indicating a test route
port: 0
},
advanced: {
testResponse: {
status: options.response?.status || 200,
headers: options.response?.headers || { 'Content-Type': 'text/plain' },
body: options.response?.body || 'Test route is working!'
}
}
},
{
name: options.name || 'Test Route',
description: 'Route for testing and debugging',
priority: 500,
tags: ['test', 'debug']
}
);
}

View File

@ -0,0 +1,9 @@
/**
* Route helpers for SmartProxy
*
* This module provides helper functions for creating various types of route configurations
* to be used with the SmartProxy system.
*/
// Re-export all functions from the route-helpers.ts file
export * from '../route-helpers.js';

View File

@ -7,8 +7,7 @@ import type {
} from './models/route-types.js'; } from './models/route-types.js';
import type { import type {
ISmartProxyOptions, ISmartProxyOptions,
IRoutedSmartProxyOptions, IRoutedSmartProxyOptions
IDomainConfig
} from './models/interfaces.js'; } from './models/interfaces.js';
import { import {
isRoutedOptions, isRoutedOptions,

View File

@ -6,7 +6,7 @@ import { SecurityManager } from './security-manager.js';
import { TlsManager } from './tls-manager.js'; import { TlsManager } from './tls-manager.js';
import { NetworkProxyBridge } from './network-proxy-bridge.js'; import { NetworkProxyBridge } from './network-proxy-bridge.js';
import { TimeoutManager } from './timeout-manager.js'; import { TimeoutManager } from './timeout-manager.js';
import { PortRangeManager } from './port-range-manager.js'; // import { PortRangeManager } from './port-range-manager.js';
import { RouteManager } from './route-manager.js'; import { RouteManager } from './route-manager.js';
import { RouteConnectionHandler } from './route-connection-handler.js'; import { RouteConnectionHandler } from './route-connection-handler.js';
@ -22,7 +22,7 @@ import type {
ISmartProxyOptions, ISmartProxyOptions,
IRoutedSmartProxyOptions IRoutedSmartProxyOptions
} from './models/interfaces.js'; } from './models/interfaces.js';
import { isRoutedOptions } from './models/interfaces.js'; import { isRoutedOptions, isLegacyOptions } from './models/interfaces.js';
import type { IRouteConfig } from './models/route-types.js'; import type { IRouteConfig } from './models/route-types.js';
/** /**
@ -49,7 +49,7 @@ export class SmartProxy extends plugins.EventEmitter {
private tlsManager: TlsManager; private tlsManager: TlsManager;
private networkProxyBridge: NetworkProxyBridge; private networkProxyBridge: NetworkProxyBridge;
private timeoutManager: TimeoutManager; private timeoutManager: TimeoutManager;
private portRangeManager: PortRangeManager; // private portRangeManager: PortRangeManager;
private routeManager: RouteManager; private routeManager: RouteManager;
private routeConnectionHandler: RouteConnectionHandler; private routeConnectionHandler: RouteConnectionHandler;
@ -133,7 +133,7 @@ export class SmartProxy extends plugins.EventEmitter {
autoRenew: true, autoRenew: true,
certificateStore: './certs', certificateStore: './certs',
skipConfiguredCerts: false, skipConfiguredCerts: false,
httpsRedirectPort: this.settings.fromPort || 443, httpsRedirectPort: 443,
renewCheckIntervalHours: 24, renewCheckIntervalHours: 24,
domainForwards: [] domainForwards: []
}; };
@ -152,7 +152,7 @@ export class SmartProxy extends plugins.EventEmitter {
this.routeManager = new RouteManager(this.settings); this.routeManager = new RouteManager(this.settings);
// Create port range manager // Create port range manager
this.portRangeManager = new PortRangeManager(this.settings); // this.portRangeManager = new PortRangeManager(this.settings);
// Create other required components // Create other required components
this.tlsManager = new TlsManager(this.settings); this.tlsManager = new TlsManager(this.settings);
@ -220,22 +220,22 @@ export class SmartProxy extends plugins.EventEmitter {
if (this.port80Handler) { if (this.port80Handler) {
const acme = this.settings.acme!; const acme = this.settings.acme!;
// Setup domain forwards based on configuration type // Setup domain forwards
const domainForwards = acme.domainForwards?.map(f => { const domainForwards = acme.domainForwards?.map(f => {
if (isLegacyOptions(this.settings)) { // Check if a matching route exists
// If using legacy mode, check if domain config exists const matchingRoute = this.settings.routes.find(
const domainConfig = this.settings.domainConfigs.find( route => Array.isArray(route.match.domains)
dc => dc.domains.some(d => d === f.domain) ? route.match.domains.some(d => d === f.domain)
: route.match.domains === f.domain
); );
if (domainConfig?.forwarding) { if (matchingRoute) {
return { return {
domain: f.domain, domain: f.domain,
forwardConfig: f.forwardConfig, forwardConfig: f.forwardConfig,
acmeForwardConfig: f.acmeForwardConfig, acmeForwardConfig: f.acmeForwardConfig,
sslRedirect: f.sslRedirect || domainConfig.forwarding.http?.redirectToHttps || false sslRedirect: f.sslRedirect || false
}; };
}
} else { } else {
// In route mode, look for matching route // In route mode, look for matching route
const route = this.routeManager.findMatchingRoute({ const route = this.routeManager.findMatchingRoute({
@ -332,10 +332,8 @@ export class SmartProxy extends plugins.EventEmitter {
const isNetworkProxyPort = this.settings.useNetworkProxy?.includes(port); const isNetworkProxyPort = this.settings.useNetworkProxy?.includes(port);
console.log( console.log(
`SmartProxy -> OK: Now listening on port ${port}${ `SmartProxy -> OK: Now listening on port ${port}${
isLegacyOptions(this.settings) && this.settings.sniEnabled && !isNetworkProxyPort ? isNetworkProxyPort ? ' (NetworkProxy forwarding enabled)' : ''
' (SNI passthrough enabled)' : }`
''
}${isNetworkProxyPort ? ' (NetworkProxy forwarding enabled)' : ''}`
); );
}); });
@ -723,17 +721,7 @@ export class SmartProxy extends plugins.EventEmitter {
domains.push(...eligibleDomains); domains.push(...eligibleDomains);
} }
// For legacy mode, also get domains from domain configs // Legacy mode is no longer supported
if (isLegacyOptions(this.settings)) {
for (const config of this.settings.domainConfigs) {
// Skip domains that can't be used with ACME
const eligibleDomains = config.domains.filter(domain =>
!domain.includes('*') && this.isValidDomain(domain)
);
domains.push(...eligibleDomains);
}
}
return domains; return domains;
} }