6.5 KiB
SmartProxy Project Hints
Project Overview
- Package:
@push.rocks/smartproxy– high-performance proxy supporting HTTP(S), TCP, WebSocket, and ACME integration. - Written in TypeScript, compiled output in
dist_ts/, uses ESM with NodeNext resolution.
Important: ACME Configuration in v19.0.0
- Breaking Change: ACME configuration must be placed within individual route TLS settings, not at the top level
- Route-level ACME config is the ONLY way to enable SmartAcme initialization
- SmartCertManager requires email in route config for certificate acquisition
- Top-level ACME configuration is ignored in v19.0.0
Repository Structure
ts/– TypeScript source files:index.tsexports main modules.plugins.tscentralizes native and third-party imports.- Subdirectories:
networkproxy/,nftablesproxy/,port80handler/,redirect/,smartproxy/. - Key classes:
ProxyRouter(classes.router.ts),SmartProxy(classes.smartproxy.ts), plus handlers/managers.
dist_ts/– transpiled.jsand.d.tsfiles mirroringts/structure.test/– test suites in TypeScript:test.router.ts– routing logic (hostname matching, wildcards, path parameters, config management).test.smartproxy.ts– proxy behavior tests (TCP forwarding, SNI handling, concurrency, chaining, timeouts).test/helpers/– utilities (e.g., certificates).
assets/certs/– placeholder certificates for ACME and TLS.
Development Setup
- Requires
pnpm(v10+). - Install dependencies:
pnpm install. - Build:
pnpm build(runstsbuild --web --allowimplicitany). - Test:
pnpm test(runststest test/). - Format:
pnpm format(runsgitzone format).
Testing Framework
- Uses
@push.rocks/tapbundle(tap,expect,expactAsync). - Test files: must start with
test.and use.tsextension. - Run specific tests via
tsx, e.g.,tsx test/test.router.ts.
Coding Conventions
- Import modules via
plugins.ts:import * as plugins from './plugins.ts'; const server = new plugins.http.Server(); - Reference plugins with full path:
plugins.acme,plugins.smartdelay,plugins.minimatch, etc. - Path patterns support globs (
*) and parameters (:param) inProxyRouter. - Wildcard hostname matching leverages
minimatchpatterns.
Key Components
- ProxyRouter
- Methods:
routeReq,routeReqWithDetails. - Hostname matching: case-insensitive, strips port, supports exact, wildcard, TLD, complex patterns.
- Path routing: exact, wildcard, parameter extraction (
pathParams), returnspathMatchandpathRemainder. - Config API:
setNewProxyConfigs,addProxyConfig,removeProxyConfig,getHostnames,getProxyConfigs.
- Methods:
- SmartProxy
- Manages one or more
net.Serverinstances to forward TCP streams. - Options:
preserveSourceIP,defaultAllowedIPs,globalPortRanges,sniEnabled. - DomainConfigManager: round-robin selection for multiple target IPs.
- Graceful shutdown in
stop(), ensures no lingering servers or sockets.
- Manages one or more
Notable Points
- TSConfig:
module: NodeNext,verbatimModuleSyntax, allows.jsextension imports in TS. - Mermaid diagrams and architecture flows in
readme.mdillustrate component interactions and protocol flows. - CLI entrypoint (
cli.js) supports command-line usage (ACME, proxy controls). - ACME and certificate handling via
Port80Handlerandhelpers.certificates.ts.
ACME/Certificate Configuration Example (v19.0.0)
const proxy = new SmartProxy({
routes: [{
name: 'example.com',
match: { domains: 'example.com', ports: 443 },
action: {
type: 'forward',
target: { host: 'localhost', port: 8080 },
tls: {
mode: 'terminate',
certificate: 'auto',
acme: { // ACME config MUST be here, not at top level
email: 'ssl@example.com',
useProduction: false,
challengePort: 80
}
}
}
}]
});
TODOs / Considerations
- Ensure import extensions in source match build outputs (
.tsvs.js). - Update
plugins.tswhen adding new dependencies. - Maintain test coverage for new routing or proxy features.
- Keep
ts/anddist_ts/in sync after refactors. - Consider implementing top-level ACME config support for backward compatibility
HTTP-01 ACME Challenge Fix (v19.3.8)
Issue
Non-TLS connections on ports configured in useHttpProxy were not being forwarded to HttpProxy. This caused ACME HTTP-01 challenges to fail when the ACME port (usually 80) was included in useHttpProxy.
Root Cause
In the RouteConnectionHandler.handleForwardAction method, only connections with TLS settings (mode: 'terminate' or 'terminate-and-reencrypt') were being forwarded to HttpProxy. Non-TLS connections were always handled as direct connections, even when the port was configured for HttpProxy.
Solution
Added a check for non-TLS connections on ports listed in useHttpProxy:
// No TLS settings - check if this port should use HttpProxy
const isHttpProxyPort = this.settings.useHttpProxy?.includes(record.localPort);
if (isHttpProxyPort && this.httpProxyBridge.getHttpProxy()) {
// Forward non-TLS connections to HttpProxy if configured
this.httpProxyBridge.forwardToHttpProxy(/*...*/);
return;
}
Test Coverage
test/test.http-fix-unit.ts- Unit tests verifying the fix- Tests confirm that non-TLS connections on HttpProxy ports are properly forwarded
- Tests verify that non-HttpProxy ports still use direct connections
Configuration Example
const proxy = new SmartProxy({
useHttpProxy: [80], // Enable HttpProxy for port 80
httpProxyPort: 8443,
acme: {
email: 'ssl@example.com',
port: 80
},
routes: [
// Your routes here
]
});
ACME Certificate Provisioning Timing Fix (v19.3.9)
Issue
Certificate provisioning would start before ports were listening, causing ACME HTTP-01 challenges to fail with connection refused errors.
Root Cause
SmartProxy initialization sequence:
- Certificate manager initialized → immediately starts provisioning
- Ports start listening (too late for ACME challenges)
Solution
Deferred certificate provisioning until after ports are ready:
// SmartCertManager.initialize() now skips automatic provisioning
// SmartProxy.start() calls provisionAllCertificates() directly after ports are listening
Test Coverage
test/test.acme-timing-simple.ts- Verifies proper timing sequence
Migration
Update to v19.3.9+, no configuration changes needed.