@push.rocks/smartproxy 22.4.2 → 23.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.md +36 -0
- package/dist_rust/rustproxy +0 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/index.d.ts +1 -6
- package/dist_ts/index.js +3 -11
- package/dist_ts/protocols/common/fragment-handler.js +5 -1
- package/dist_ts/proxies/index.d.ts +1 -6
- package/dist_ts/proxies/index.js +2 -8
- package/dist_ts/proxies/smart-proxy/index.d.ts +5 -10
- package/dist_ts/proxies/smart-proxy/index.js +7 -13
- package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +5 -2
- package/dist_ts/proxies/smart-proxy/models/route-types.js +1 -1
- package/dist_ts/proxies/smart-proxy/route-preprocessor.d.ts +37 -0
- package/dist_ts/proxies/smart-proxy/route-preprocessor.js +103 -0
- package/dist_ts/proxies/smart-proxy/rust-binary-locator.d.ts +23 -0
- package/dist_ts/proxies/smart-proxy/rust-binary-locator.js +104 -0
- package/dist_ts/proxies/smart-proxy/rust-metrics-adapter.d.ts +74 -0
- package/dist_ts/proxies/smart-proxy/rust-metrics-adapter.js +146 -0
- package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.d.ts +49 -0
- package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.js +259 -0
- package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +39 -157
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +224 -621
- package/dist_ts/proxies/smart-proxy/socket-handler-server.d.ts +45 -0
- package/dist_ts/proxies/smart-proxy/socket-handler-server.js +253 -0
- package/dist_ts/routing/index.d.ts +1 -1
- package/dist_ts/routing/index.js +3 -3
- package/dist_ts/routing/models/http-types.d.ts +119 -4
- package/dist_ts/routing/models/http-types.js +93 -5
- package/package.json +1 -1
- package/readme.md +444 -219
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/index.ts +4 -15
- package/ts/protocols/common/fragment-handler.ts +4 -0
- package/ts/proxies/index.ts +1 -12
- package/ts/proxies/smart-proxy/index.ts +6 -13
- package/ts/proxies/smart-proxy/models/interfaces.ts +6 -4
- package/ts/proxies/smart-proxy/models/route-types.ts +0 -2
- package/ts/proxies/smart-proxy/route-preprocessor.ts +122 -0
- package/ts/proxies/smart-proxy/rust-binary-locator.ts +112 -0
- package/ts/proxies/smart-proxy/rust-metrics-adapter.ts +161 -0
- package/ts/proxies/smart-proxy/rust-proxy-bridge.ts +310 -0
- package/ts/proxies/smart-proxy/smart-proxy.ts +282 -798
- package/ts/proxies/smart-proxy/socket-handler-server.ts +279 -0
- package/ts/routing/index.ts +2 -2
- package/ts/routing/models/http-types.ts +147 -4
- package/dist_ts/proxies/nftables-proxy/index.d.ts +0 -6
- package/dist_ts/proxies/nftables-proxy/index.js +0 -7
- package/dist_ts/proxies/nftables-proxy/models/errors.d.ts +0 -15
- package/dist_ts/proxies/nftables-proxy/models/errors.js +0 -28
- package/dist_ts/proxies/nftables-proxy/models/index.d.ts +0 -5
- package/dist_ts/proxies/nftables-proxy/models/index.js +0 -6
- package/dist_ts/proxies/nftables-proxy/models/interfaces.d.ts +0 -75
- package/dist_ts/proxies/nftables-proxy/models/interfaces.js +0 -5
- package/dist_ts/proxies/nftables-proxy/nftables-proxy.d.ts +0 -124
- package/dist_ts/proxies/nftables-proxy/nftables-proxy.js +0 -1374
- package/dist_ts/proxies/nftables-proxy/utils/index.d.ts +0 -9
- package/dist_ts/proxies/nftables-proxy/utils/index.js +0 -12
- package/dist_ts/proxies/nftables-proxy/utils/nft-command-executor.d.ts +0 -66
- package/dist_ts/proxies/nftables-proxy/utils/nft-command-executor.js +0 -131
- package/dist_ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.d.ts +0 -39
- package/dist_ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.js +0 -112
- package/dist_ts/proxies/nftables-proxy/utils/nft-rule-validator.d.ts +0 -59
- package/dist_ts/proxies/nftables-proxy/utils/nft-rule-validator.js +0 -130
- package/ts/proxies/http-proxy/connection-pool.ts +0 -228
- package/ts/proxies/http-proxy/context-creator.ts +0 -145
- package/ts/proxies/http-proxy/default-certificates.ts +0 -150
- package/ts/proxies/http-proxy/function-cache.ts +0 -279
- package/ts/proxies/http-proxy/handlers/index.ts +0 -5
- package/ts/proxies/http-proxy/http-proxy.ts +0 -669
- package/ts/proxies/http-proxy/http-request-handler.ts +0 -331
- package/ts/proxies/http-proxy/http2-request-handler.ts +0 -255
- package/ts/proxies/http-proxy/index.ts +0 -18
- package/ts/proxies/http-proxy/models/http-types.ts +0 -148
- package/ts/proxies/http-proxy/models/index.ts +0 -5
- package/ts/proxies/http-proxy/models/types.ts +0 -125
- package/ts/proxies/http-proxy/request-handler.ts +0 -878
- package/ts/proxies/http-proxy/security-manager.ts +0 -413
- package/ts/proxies/http-proxy/websocket-handler.ts +0 -581
- package/ts/proxies/nftables-proxy/index.ts +0 -6
- package/ts/proxies/nftables-proxy/models/errors.ts +0 -30
- package/ts/proxies/nftables-proxy/models/index.ts +0 -5
- package/ts/proxies/nftables-proxy/models/interfaces.ts +0 -94
- package/ts/proxies/nftables-proxy/nftables-proxy.ts +0 -1754
- package/ts/proxies/nftables-proxy/utils/index.ts +0 -38
- package/ts/proxies/nftables-proxy/utils/nft-command-executor.ts +0 -162
- package/ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.ts +0 -125
- package/ts/proxies/nftables-proxy/utils/nft-rule-validator.ts +0 -156
- package/ts/proxies/smart-proxy/acme-state-manager.ts +0 -112
- package/ts/proxies/smart-proxy/cert-store.ts +0 -92
- package/ts/proxies/smart-proxy/certificate-manager.ts +0 -895
- package/ts/proxies/smart-proxy/connection-manager.ts +0 -809
- package/ts/proxies/smart-proxy/http-proxy-bridge.ts +0 -213
- package/ts/proxies/smart-proxy/metrics-collector.ts +0 -453
- package/ts/proxies/smart-proxy/nftables-manager.ts +0 -271
- package/ts/proxies/smart-proxy/port-manager.ts +0 -358
- package/ts/proxies/smart-proxy/route-connection-handler.ts +0 -1712
- package/ts/proxies/smart-proxy/route-orchestrator.ts +0 -297
- package/ts/proxies/smart-proxy/security-manager.ts +0 -269
- package/ts/proxies/smart-proxy/throughput-tracker.ts +0 -138
- package/ts/proxies/smart-proxy/timeout-manager.ts +0 -196
- package/ts/proxies/smart-proxy/tls-manager.ts +0 -171
package/readme.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @push.rocks/smartproxy 🚀
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**A high-performance, Rust-powered proxy toolkit for Node.js** — unified route-based configuration for SSL/TLS termination, HTTP/HTTPS reverse proxying, WebSocket support, load balancing, custom protocol handlers, and kernel-level NFTables forwarding.
|
|
4
4
|
|
|
5
5
|
## 📦 Installation
|
|
6
6
|
|
|
@@ -16,22 +16,26 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
|
|
|
16
16
|
|
|
17
17
|
## 🎯 What is SmartProxy?
|
|
18
18
|
|
|
19
|
-
SmartProxy is a
|
|
19
|
+
SmartProxy is a production-ready proxy solution that takes the complexity out of traffic management. Under the hood, all networking — TCP, TLS, HTTP reverse proxy, connection tracking, security enforcement, and NFTables — is handled by a **Rust engine** for maximum performance, while you configure everything through a clean TypeScript API with full type safety.
|
|
20
|
+
|
|
21
|
+
Whether you're building microservices, deploying edge infrastructure, or need a battle-tested reverse proxy with automatic Let's Encrypt certificates, SmartProxy has you covered.
|
|
20
22
|
|
|
21
23
|
### ⚡ Key Features
|
|
22
24
|
|
|
23
25
|
| Feature | Description |
|
|
24
26
|
|---------|-------------|
|
|
27
|
+
| 🦀 **Rust-Powered Engine** | All networking handled by a high-performance Rust binary via IPC |
|
|
25
28
|
| 🔀 **Unified Route-Based Config** | Clean match/action patterns for intuitive traffic routing |
|
|
26
29
|
| 🔒 **Automatic SSL/TLS** | Zero-config HTTPS with Let's Encrypt ACME integration |
|
|
27
|
-
| 🎯 **Flexible Matching** | Route by port, domain, path, client IP, TLS version, or custom logic |
|
|
30
|
+
| 🎯 **Flexible Matching** | Route by port, domain, path, client IP, TLS version, headers, or custom logic |
|
|
28
31
|
| 🚄 **High-Performance** | Choose between user-space or kernel-level (NFTables) forwarding |
|
|
29
|
-
| ⚖️ **Load Balancing** |
|
|
30
|
-
| 🛡️ **Enterprise Security** | IP filtering, rate limiting,
|
|
32
|
+
| ⚖️ **Load Balancing** | Round-robin, least-connections, IP-hash with health checks |
|
|
33
|
+
| 🛡️ **Enterprise Security** | IP filtering, rate limiting, basic auth, JWT auth, connection limits |
|
|
31
34
|
| 🔌 **WebSocket Support** | First-class WebSocket proxying with ping/pong keep-alive |
|
|
32
|
-
| 🎮 **Custom Protocols** | Socket handlers for implementing any protocol |
|
|
35
|
+
| 🎮 **Custom Protocols** | Socket handlers for implementing any protocol in TypeScript |
|
|
33
36
|
| 📊 **Live Metrics** | Real-time throughput, connection counts, and performance data |
|
|
34
37
|
| 🔧 **Dynamic Management** | Add/remove ports and routes at runtime without restarts |
|
|
38
|
+
| 🔄 **PROXY Protocol** | Full PROXY protocol v1/v2 support for preserving client information |
|
|
35
39
|
|
|
36
40
|
## 🚀 Quick Start
|
|
37
41
|
|
|
@@ -43,16 +47,16 @@ import { SmartProxy, createCompleteHttpsServer } from '@push.rocks/smartproxy';
|
|
|
43
47
|
// Create a proxy with automatic HTTPS
|
|
44
48
|
const proxy = new SmartProxy({
|
|
45
49
|
acme: {
|
|
46
|
-
email: 'ssl@yourdomain.com',
|
|
47
|
-
useProduction: true
|
|
50
|
+
email: 'ssl@yourdomain.com',
|
|
51
|
+
useProduction: true
|
|
48
52
|
},
|
|
49
53
|
routes: [
|
|
50
|
-
// Complete HTTPS setup in one
|
|
54
|
+
// Complete HTTPS setup in one call! ✨
|
|
51
55
|
...createCompleteHttpsServer('app.example.com', {
|
|
52
56
|
host: 'localhost',
|
|
53
57
|
port: 3000
|
|
54
58
|
}, {
|
|
55
|
-
certificate: 'auto' //
|
|
59
|
+
certificate: 'auto' // Automatic Let's Encrypt cert 🎩
|
|
56
60
|
})
|
|
57
61
|
]
|
|
58
62
|
});
|
|
@@ -84,10 +88,11 @@ SmartProxy uses a powerful **match/action** pattern that makes routing predictab
|
|
|
84
88
|
```
|
|
85
89
|
|
|
86
90
|
Every route consists of:
|
|
87
|
-
- **Match**
|
|
88
|
-
- **Action**
|
|
89
|
-
- **Security** (optional)
|
|
90
|
-
- **
|
|
91
|
+
- **Match** — What traffic to capture (ports, domains, paths, IPs, headers)
|
|
92
|
+
- **Action** — What to do with it (`forward` or `socket-handler`)
|
|
93
|
+
- **Security** (optional) — IP allow/block lists, rate limits, authentication
|
|
94
|
+
- **Headers** (optional) — Request/response header manipulation with template variables
|
|
95
|
+
- **Name/Priority** (optional) — For identification and ordering
|
|
91
96
|
|
|
92
97
|
### 🔄 TLS Modes
|
|
93
98
|
|
|
@@ -95,8 +100,8 @@ SmartProxy supports three TLS handling modes:
|
|
|
95
100
|
|
|
96
101
|
| Mode | Description | Use Case |
|
|
97
102
|
|------|-------------|----------|
|
|
98
|
-
| `passthrough` | Forward encrypted traffic as-is | Backend handles TLS |
|
|
99
|
-
| `terminate` | Decrypt at proxy, forward plain | Standard reverse proxy |
|
|
103
|
+
| `passthrough` | Forward encrypted traffic as-is (SNI-based routing) | Backend handles TLS |
|
|
104
|
+
| `terminate` | Decrypt at proxy, forward plain HTTP to backend | Standard reverse proxy |
|
|
100
105
|
| `terminate-and-reencrypt` | Decrypt, then re-encrypt to backend | Zero-trust environments |
|
|
101
106
|
|
|
102
107
|
## 💡 Common Use Cases
|
|
@@ -116,53 +121,61 @@ const proxy = new SmartProxy({
|
|
|
116
121
|
### ⚖️ Load Balancer with Health Checks
|
|
117
122
|
|
|
118
123
|
```typescript
|
|
119
|
-
import { createLoadBalancerRoute } from '@push.rocks/smartproxy';
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
124
|
+
import { SmartProxy, createLoadBalancerRoute } from '@push.rocks/smartproxy';
|
|
125
|
+
|
|
126
|
+
const proxy = new SmartProxy({
|
|
127
|
+
routes: [
|
|
128
|
+
createLoadBalancerRoute(
|
|
129
|
+
'app.example.com',
|
|
130
|
+
[
|
|
131
|
+
{ host: 'server1.internal', port: 8080 },
|
|
132
|
+
{ host: 'server2.internal', port: 8080 },
|
|
133
|
+
{ host: 'server3.internal', port: 8080 }
|
|
134
|
+
],
|
|
135
|
+
{
|
|
136
|
+
tls: { mode: 'terminate', certificate: 'auto' },
|
|
137
|
+
loadBalancing: {
|
|
138
|
+
algorithm: 'round-robin',
|
|
139
|
+
healthCheck: {
|
|
140
|
+
path: '/health',
|
|
141
|
+
interval: 30000,
|
|
142
|
+
timeout: 5000
|
|
143
|
+
}
|
|
144
|
+
}
|
|
136
145
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
);
|
|
146
|
+
)
|
|
147
|
+
]
|
|
148
|
+
});
|
|
140
149
|
```
|
|
141
150
|
|
|
142
151
|
### 🔌 WebSocket Proxy
|
|
143
152
|
|
|
144
153
|
```typescript
|
|
145
|
-
import { createWebSocketRoute } from '@push.rocks/smartproxy';
|
|
154
|
+
import { SmartProxy, createWebSocketRoute } from '@push.rocks/smartproxy';
|
|
146
155
|
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
156
|
+
const proxy = new SmartProxy({
|
|
157
|
+
routes: [
|
|
158
|
+
createWebSocketRoute(
|
|
159
|
+
'ws.example.com',
|
|
160
|
+
{ host: 'websocket-server', port: 8080 },
|
|
161
|
+
{
|
|
162
|
+
path: '/socket',
|
|
163
|
+
useTls: true,
|
|
164
|
+
certificate: 'auto',
|
|
165
|
+
pingInterval: 30000,
|
|
166
|
+
pingTimeout: 10000
|
|
167
|
+
}
|
|
168
|
+
)
|
|
169
|
+
]
|
|
170
|
+
});
|
|
158
171
|
```
|
|
159
172
|
|
|
160
173
|
### 🚦 API Gateway with Rate Limiting
|
|
161
174
|
|
|
162
175
|
```typescript
|
|
163
|
-
import { createApiGatewayRoute, addRateLimiting } from '@push.rocks/smartproxy';
|
|
176
|
+
import { SmartProxy, createApiGatewayRoute, addRateLimiting } from '@push.rocks/smartproxy';
|
|
164
177
|
|
|
165
|
-
let
|
|
178
|
+
let apiRoute = createApiGatewayRoute(
|
|
166
179
|
'api.example.com',
|
|
167
180
|
'/api',
|
|
168
181
|
{ host: 'api-backend', port: 8080 },
|
|
@@ -173,20 +186,22 @@ let route = createApiGatewayRoute(
|
|
|
173
186
|
}
|
|
174
187
|
);
|
|
175
188
|
|
|
176
|
-
// Add rate limiting
|
|
177
|
-
|
|
189
|
+
// Add rate limiting — 100 requests per minute per IP
|
|
190
|
+
apiRoute = addRateLimiting(apiRoute, {
|
|
178
191
|
maxRequests: 100,
|
|
179
192
|
window: 60,
|
|
180
193
|
keyBy: 'ip'
|
|
181
194
|
});
|
|
195
|
+
|
|
196
|
+
const proxy = new SmartProxy({ routes: [apiRoute] });
|
|
182
197
|
```
|
|
183
198
|
|
|
184
199
|
### 🎮 Custom Protocol Handler
|
|
185
200
|
|
|
186
|
-
SmartProxy lets you implement any protocol with full socket control:
|
|
201
|
+
SmartProxy lets you implement any protocol with full socket control. Routes with JavaScript socket handlers are automatically relayed from the Rust engine back to your TypeScript code:
|
|
187
202
|
|
|
188
203
|
```typescript
|
|
189
|
-
import { createSocketHandlerRoute, SocketHandlers } from '@push.rocks/smartproxy';
|
|
204
|
+
import { SmartProxy, createSocketHandlerRoute, SocketHandlers } from '@push.rocks/smartproxy';
|
|
190
205
|
|
|
191
206
|
// Use pre-built handlers
|
|
192
207
|
const echoRoute = createSocketHandlerRoute(
|
|
@@ -199,8 +214,8 @@ const echoRoute = createSocketHandlerRoute(
|
|
|
199
214
|
const customRoute = createSocketHandlerRoute(
|
|
200
215
|
'custom.example.com',
|
|
201
216
|
9999,
|
|
202
|
-
async (socket
|
|
203
|
-
console.log(`
|
|
217
|
+
async (socket) => {
|
|
218
|
+
console.log(`New connection on custom protocol`);
|
|
204
219
|
socket.write('Welcome to my custom protocol!\n');
|
|
205
220
|
|
|
206
221
|
socket.on('data', (data) => {
|
|
@@ -214,18 +229,21 @@ const customRoute = createSocketHandlerRoute(
|
|
|
214
229
|
});
|
|
215
230
|
}
|
|
216
231
|
);
|
|
232
|
+
|
|
233
|
+
const proxy = new SmartProxy({ routes: [echoRoute, customRoute] });
|
|
217
234
|
```
|
|
218
235
|
|
|
219
236
|
**Pre-built Socket Handlers:**
|
|
220
237
|
|
|
221
238
|
| Handler | Description |
|
|
222
239
|
|---------|-------------|
|
|
223
|
-
| `SocketHandlers.echo` | Echo server
|
|
240
|
+
| `SocketHandlers.echo` | Echo server — returns everything sent |
|
|
224
241
|
| `SocketHandlers.proxy(host, port)` | TCP proxy to another server |
|
|
225
242
|
| `SocketHandlers.lineProtocol(handler)` | Line-based text protocol |
|
|
226
243
|
| `SocketHandlers.httpResponse(code, body)` | Simple HTTP response |
|
|
227
|
-
| `SocketHandlers.httpRedirect(url, code)` | HTTP redirect with
|
|
244
|
+
| `SocketHandlers.httpRedirect(url, code)` | HTTP redirect with template variables (`{domain}`, `{path}`, `{port}`, `{clientIp}`) |
|
|
228
245
|
| `SocketHandlers.httpServer(handler)` | Full HTTP request/response handling |
|
|
246
|
+
| `SocketHandlers.httpBlock(status, message)` | HTTP block response |
|
|
229
247
|
| `SocketHandlers.block(message)` | Block with optional message |
|
|
230
248
|
|
|
231
249
|
### ⚡ High-Performance NFTables Forwarding
|
|
@@ -233,48 +251,72 @@ const customRoute = createSocketHandlerRoute(
|
|
|
233
251
|
For ultra-low latency on Linux, use kernel-level forwarding (requires root):
|
|
234
252
|
|
|
235
253
|
```typescript
|
|
236
|
-
import { createNfTablesTerminateRoute } from '@push.rocks/smartproxy';
|
|
254
|
+
import { SmartProxy, createNfTablesTerminateRoute } from '@push.rocks/smartproxy';
|
|
237
255
|
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
256
|
+
const proxy = new SmartProxy({
|
|
257
|
+
routes: [
|
|
258
|
+
createNfTablesTerminateRoute(
|
|
259
|
+
'fast.example.com',
|
|
260
|
+
{ host: 'backend', port: 8080 },
|
|
261
|
+
{
|
|
262
|
+
ports: 443,
|
|
263
|
+
certificate: 'auto',
|
|
264
|
+
preserveSourceIP: true // Backend sees real client IP
|
|
265
|
+
}
|
|
266
|
+
)
|
|
267
|
+
]
|
|
268
|
+
});
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### 🔒 SNI Passthrough (TLS Passthrough)
|
|
272
|
+
|
|
273
|
+
Forward encrypted traffic to backends without terminating TLS — the proxy routes based on the SNI hostname alone:
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
import { SmartProxy, createHttpsPassthroughRoute } from '@push.rocks/smartproxy';
|
|
277
|
+
|
|
278
|
+
const proxy = new SmartProxy({
|
|
279
|
+
routes: [
|
|
280
|
+
createHttpsPassthroughRoute('secure.example.com', {
|
|
281
|
+
host: 'backend-that-handles-tls',
|
|
282
|
+
port: 8443
|
|
283
|
+
})
|
|
284
|
+
]
|
|
285
|
+
});
|
|
248
286
|
```
|
|
249
287
|
|
|
250
288
|
## 🔧 Advanced Features
|
|
251
289
|
|
|
252
290
|
### 🎯 Dynamic Routing
|
|
253
291
|
|
|
254
|
-
Route traffic based on runtime conditions:
|
|
292
|
+
Route traffic based on runtime conditions using function-based host/port resolution:
|
|
255
293
|
|
|
256
294
|
```typescript
|
|
257
|
-
{
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
}
|
|
295
|
+
const proxy = new SmartProxy({
|
|
296
|
+
routes: [{
|
|
297
|
+
name: 'dynamic-backend',
|
|
298
|
+
match: {
|
|
299
|
+
ports: 443,
|
|
300
|
+
domains: 'app.example.com'
|
|
301
|
+
},
|
|
302
|
+
action: {
|
|
303
|
+
type: 'forward',
|
|
304
|
+
targets: [{
|
|
305
|
+
host: (context) => {
|
|
306
|
+
return context.path?.startsWith('/premium')
|
|
307
|
+
? 'premium-backend'
|
|
308
|
+
: 'standard-backend';
|
|
309
|
+
},
|
|
310
|
+
port: 8080
|
|
311
|
+
}],
|
|
312
|
+
tls: { mode: 'terminate', certificate: 'auto' }
|
|
313
|
+
}
|
|
314
|
+
}]
|
|
315
|
+
});
|
|
276
316
|
```
|
|
277
317
|
|
|
318
|
+
> **Note:** Routes with dynamic functions (host/port callbacks) are automatically relayed through the TypeScript socket handler server, since JavaScript functions can't be serialized to Rust.
|
|
319
|
+
|
|
278
320
|
### 🔒 Security Controls
|
|
279
321
|
|
|
280
322
|
Comprehensive per-route security options:
|
|
@@ -285,7 +327,8 @@ Comprehensive per-route security options:
|
|
|
285
327
|
match: { ports: 443, domains: 'api.example.com' },
|
|
286
328
|
action: {
|
|
287
329
|
type: 'forward',
|
|
288
|
-
targets: [{ host: 'api-backend', port: 8080 }]
|
|
330
|
+
targets: [{ host: 'api-backend', port: 8080 }],
|
|
331
|
+
tls: { mode: 'terminate', certificate: 'auto' }
|
|
289
332
|
},
|
|
290
333
|
security: {
|
|
291
334
|
// IP-based access control
|
|
@@ -294,17 +337,31 @@ Comprehensive per-route security options:
|
|
|
294
337
|
|
|
295
338
|
// Connection limits
|
|
296
339
|
maxConnections: 1000,
|
|
297
|
-
maxConnectionsPerIp: 10,
|
|
298
340
|
|
|
299
341
|
// Rate limiting
|
|
300
342
|
rateLimit: {
|
|
343
|
+
enabled: true,
|
|
301
344
|
maxRequests: 100,
|
|
302
|
-
|
|
303
|
-
}
|
|
345
|
+
window: 60
|
|
346
|
+
},
|
|
347
|
+
|
|
348
|
+
// Authentication
|
|
349
|
+
basicAuth: { users: [{ username: 'admin', password: 'secret' }] },
|
|
350
|
+
jwtAuth: { secret: 'your-jwt-secret', algorithm: 'HS256' }
|
|
304
351
|
}
|
|
305
352
|
}
|
|
306
353
|
```
|
|
307
354
|
|
|
355
|
+
**Security modifier helpers** let you add security to any existing route:
|
|
356
|
+
|
|
357
|
+
```typescript
|
|
358
|
+
import { addRateLimiting, addBasicAuth, addJwtAuth } from '@push.rocks/smartproxy';
|
|
359
|
+
|
|
360
|
+
let route = createHttpsTerminateRoute('api.example.com', { host: 'backend', port: 8080 });
|
|
361
|
+
route = addRateLimiting(route, { maxRequests: 100, window: 60, keyBy: 'ip' });
|
|
362
|
+
route = addBasicAuth(route, { users: [{ username: 'admin', password: 'secret' }] });
|
|
363
|
+
```
|
|
364
|
+
|
|
308
365
|
### 📊 Runtime Management
|
|
309
366
|
|
|
310
367
|
Control your proxy without restarts:
|
|
@@ -313,21 +370,26 @@ Control your proxy without restarts:
|
|
|
313
370
|
// Dynamic port management
|
|
314
371
|
await proxy.addListeningPort(8443);
|
|
315
372
|
await proxy.removeListeningPort(8080);
|
|
373
|
+
const ports = await proxy.getListeningPorts();
|
|
316
374
|
|
|
317
|
-
// Update routes on the fly
|
|
375
|
+
// Update routes on the fly (atomic, mutex-locked)
|
|
318
376
|
await proxy.updateRoutes([...newRoutes]);
|
|
319
377
|
|
|
320
|
-
//
|
|
321
|
-
const status = proxy.getStatus();
|
|
322
|
-
console.log(`Active connections: ${status.activeConnections}`);
|
|
323
|
-
|
|
324
|
-
// Get detailed metrics
|
|
378
|
+
// Get real-time metrics
|
|
325
379
|
const metrics = proxy.getMetrics();
|
|
326
|
-
console.log(`
|
|
380
|
+
console.log(`Active connections: ${metrics.connections.active()}`);
|
|
381
|
+
console.log(`Requests/sec: ${metrics.throughput.requestsPerSecond()}`);
|
|
382
|
+
|
|
383
|
+
// Get detailed statistics from the Rust engine
|
|
384
|
+
const stats = await proxy.getStatistics();
|
|
327
385
|
|
|
328
386
|
// Certificate management
|
|
329
|
-
|
|
330
|
-
|
|
387
|
+
await proxy.provisionCertificate('my-route-name');
|
|
388
|
+
await proxy.renewCertificate('my-route-name');
|
|
389
|
+
const certStatus = await proxy.getCertificateStatus('my-route-name');
|
|
390
|
+
|
|
391
|
+
// NFTables status
|
|
392
|
+
const nftStatus = await proxy.getNfTablesStatus();
|
|
331
393
|
```
|
|
332
394
|
|
|
333
395
|
### 🔄 Header Manipulation
|
|
@@ -338,51 +400,107 @@ Transform requests and responses with template variables:
|
|
|
338
400
|
{
|
|
339
401
|
action: {
|
|
340
402
|
type: 'forward',
|
|
341
|
-
targets: [{ host: 'backend', port: 8080 }]
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
}
|
|
403
|
+
targets: [{ host: 'backend', port: 8080 }]
|
|
404
|
+
},
|
|
405
|
+
headers: {
|
|
406
|
+
request: {
|
|
407
|
+
'X-Real-IP': '{clientIp}',
|
|
408
|
+
'X-Request-ID': '{uuid}',
|
|
409
|
+
'X-Forwarded-Proto': 'https'
|
|
410
|
+
},
|
|
411
|
+
response: {
|
|
412
|
+
'Strict-Transport-Security': 'max-age=31536000',
|
|
413
|
+
'X-Frame-Options': 'DENY'
|
|
353
414
|
}
|
|
354
415
|
}
|
|
355
416
|
}
|
|
356
417
|
```
|
|
357
418
|
|
|
419
|
+
### 🔀 PROXY Protocol Support
|
|
420
|
+
|
|
421
|
+
Preserve original client information through proxy chains:
|
|
422
|
+
|
|
423
|
+
```typescript
|
|
424
|
+
const proxy = new SmartProxy({
|
|
425
|
+
// Accept PROXY protocol from trusted load balancers
|
|
426
|
+
acceptProxyProtocol: true,
|
|
427
|
+
proxyIPs: ['10.0.0.1', '10.0.0.2'],
|
|
428
|
+
|
|
429
|
+
// Forward PROXY protocol to backends
|
|
430
|
+
sendProxyProtocol: true,
|
|
431
|
+
|
|
432
|
+
routes: [...]
|
|
433
|
+
});
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### 🏗️ Custom Certificate Provisioning
|
|
437
|
+
|
|
438
|
+
Supply your own certificates or integrate with external certificate providers:
|
|
439
|
+
|
|
440
|
+
```typescript
|
|
441
|
+
const proxy = new SmartProxy({
|
|
442
|
+
certProvisionFunction: async (domain: string) => {
|
|
443
|
+
// Return 'http01' to let the built-in ACME handle it
|
|
444
|
+
if (domain.endsWith('.example.com')) return 'http01';
|
|
445
|
+
|
|
446
|
+
// Or return a static certificate object
|
|
447
|
+
return {
|
|
448
|
+
publicKey: myPemCert,
|
|
449
|
+
privateKey: myPemKey,
|
|
450
|
+
};
|
|
451
|
+
},
|
|
452
|
+
certProvisionFallbackToAcme: true, // Fall back to ACME if callback fails
|
|
453
|
+
routes: [...]
|
|
454
|
+
});
|
|
455
|
+
```
|
|
456
|
+
|
|
358
457
|
## 🏛️ Architecture
|
|
359
458
|
|
|
360
|
-
SmartProxy
|
|
459
|
+
SmartProxy uses a hybrid **Rust + TypeScript** architecture:
|
|
361
460
|
|
|
362
461
|
```
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
462
|
+
┌─────────────────────────────────────────────────────┐
|
|
463
|
+
│ Your Application │
|
|
464
|
+
│ (TypeScript — routes, config, socket handlers) │
|
|
465
|
+
└──────────────────┬──────────────────────────────────┘
|
|
466
|
+
│ IPC (JSON over stdin/stdout)
|
|
467
|
+
┌──────────────────▼──────────────────────────────────┐
|
|
468
|
+
│ Rust Proxy Engine │
|
|
469
|
+
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌──────────┐ │
|
|
470
|
+
│ │ TCP/TLS │ │ HTTP │ │ Route │ │ ACME │ │
|
|
471
|
+
│ │ Listener│ │ Reverse │ │ Matcher │ │ Cert Mgr │ │
|
|
472
|
+
│ │ │ │ Proxy │ │ │ │ │ │
|
|
473
|
+
│ └─────────┘ └─────────┘ └─────────┘ └──────────┘ │
|
|
474
|
+
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌──────────┐ │
|
|
475
|
+
│ │ Security│ │ Metrics │ │ Connec- │ │ NFTables │ │
|
|
476
|
+
│ │ Enforce │ │ Collect │ │ tion │ │ Mgr │ │
|
|
477
|
+
│ │ │ │ │ │ Tracker │ │ │ │
|
|
478
|
+
│ └─────────┘ └─────────┘ └─────────┘ └──────────┘ │
|
|
479
|
+
└──────────────────┬──────────────────────────────────┘
|
|
480
|
+
│ Unix Socket Relay
|
|
481
|
+
┌──────────────────▼──────────────────────────────────┐
|
|
482
|
+
│ TypeScript Socket Handler Server │
|
|
483
|
+
│ (for JS-defined socket handlers & dynamic routes) │
|
|
484
|
+
└─────────────────────────────────────────────────────┘
|
|
373
485
|
```
|
|
374
486
|
|
|
487
|
+
- **Rust Engine** handles all networking, TLS, HTTP proxying, connection management, security, and metrics
|
|
488
|
+
- **TypeScript** provides the npm API, configuration types, route helpers, validation, and socket handler callbacks
|
|
489
|
+
- **IPC** — JSON commands/events over stdin/stdout for seamless cross-language communication
|
|
490
|
+
- **Socket Relay** — a Unix domain socket server for routes requiring TypeScript-side handling (socket handlers, dynamic host/port functions)
|
|
491
|
+
|
|
375
492
|
## 🎯 Route Configuration Reference
|
|
376
493
|
|
|
377
494
|
### Match Criteria
|
|
378
495
|
|
|
379
496
|
```typescript
|
|
380
497
|
interface IRouteMatch {
|
|
381
|
-
ports: number | number[] |
|
|
382
|
-
domains?: string | string[];
|
|
383
|
-
path?: string;
|
|
384
|
-
clientIp?: string
|
|
385
|
-
tlsVersion?: string
|
|
498
|
+
ports: number | number[] | Array<{ from: number; to: number }>; // Port(s) to listen on
|
|
499
|
+
domains?: string | string[]; // 'example.com', '*.example.com'
|
|
500
|
+
path?: string; // '/api/*', '/users/:id'
|
|
501
|
+
clientIp?: string[]; // ['10.0.0.0/8', '192.168.*']
|
|
502
|
+
tlsVersion?: string[]; // ['TLSv1.2', 'TLSv1.3']
|
|
503
|
+
headers?: Record<string, string | RegExp>; // Match by HTTP headers
|
|
386
504
|
}
|
|
387
505
|
```
|
|
388
506
|
|
|
@@ -390,134 +508,160 @@ interface IRouteMatch {
|
|
|
390
508
|
|
|
391
509
|
| Type | Description |
|
|
392
510
|
|------|-------------|
|
|
393
|
-
| `forward` | Proxy to one or more backend targets |
|
|
394
|
-
| `
|
|
395
|
-
|
|
396
|
-
|
|
511
|
+
| `forward` | Proxy to one or more backend targets (with optional TLS, WebSocket, load balancing) |
|
|
512
|
+
| `socket-handler` | Custom socket handling function in TypeScript |
|
|
513
|
+
|
|
514
|
+
### Target Options
|
|
515
|
+
|
|
516
|
+
```typescript
|
|
517
|
+
interface IRouteTarget {
|
|
518
|
+
host: string | string[] | ((context: IRouteContext) => string);
|
|
519
|
+
port: number | 'preserve' | ((context: IRouteContext) => number);
|
|
520
|
+
tls?: { ... }; // Per-target TLS override
|
|
521
|
+
priority?: number; // Target priority
|
|
522
|
+
match?: ITargetMatch; // Sub-match within a route (by port, path, headers, method)
|
|
523
|
+
}
|
|
524
|
+
```
|
|
397
525
|
|
|
398
526
|
### TLS Options
|
|
399
527
|
|
|
400
528
|
```typescript
|
|
401
529
|
interface IRouteTls {
|
|
402
530
|
mode: 'passthrough' | 'terminate' | 'terminate-and-reencrypt';
|
|
403
|
-
certificate
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
531
|
+
certificate?: 'auto' | {
|
|
532
|
+
key: string;
|
|
533
|
+
cert: string;
|
|
534
|
+
ca?: string;
|
|
535
|
+
keyFile?: string;
|
|
536
|
+
certFile?: string;
|
|
537
|
+
};
|
|
538
|
+
acme?: {
|
|
539
|
+
email: string;
|
|
540
|
+
useProduction?: boolean;
|
|
541
|
+
challengePort?: number;
|
|
542
|
+
renewBeforeDays?: number;
|
|
543
|
+
};
|
|
544
|
+
versions?: string[];
|
|
545
|
+
ciphers?: string;
|
|
546
|
+
honorCipherOrder?: boolean;
|
|
547
|
+
sessionTimeout?: number;
|
|
548
|
+
}
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
### WebSocket Options
|
|
552
|
+
|
|
553
|
+
```typescript
|
|
554
|
+
interface IRouteWebSocket {
|
|
555
|
+
enabled: boolean;
|
|
556
|
+
pingInterval?: number; // ms between pings
|
|
557
|
+
pingTimeout?: number; // ms to wait for pong
|
|
558
|
+
maxPayloadSize?: number; // Maximum frame payload
|
|
559
|
+
subprotocols?: string[]; // Allowed subprotocols
|
|
560
|
+
allowedOrigins?: string[]; // CORS origins
|
|
561
|
+
}
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
### Load Balancing Options
|
|
565
|
+
|
|
566
|
+
```typescript
|
|
567
|
+
interface IRouteLoadBalancing {
|
|
568
|
+
algorithm: 'round-robin' | 'least-connections' | 'ip-hash';
|
|
569
|
+
healthCheck?: {
|
|
570
|
+
path: string;
|
|
571
|
+
interval: number; // ms
|
|
572
|
+
timeout: number; // ms
|
|
573
|
+
unhealthyThreshold: number;
|
|
574
|
+
healthyThreshold: number;
|
|
409
575
|
};
|
|
410
576
|
}
|
|
411
577
|
```
|
|
412
578
|
|
|
413
579
|
## 🛠️ Helper Functions Reference
|
|
414
580
|
|
|
415
|
-
All helpers are fully typed and
|
|
581
|
+
All helpers are fully typed and return `IRouteConfig` or `IRouteConfig[]`:
|
|
416
582
|
|
|
417
583
|
```typescript
|
|
418
584
|
import {
|
|
419
585
|
// HTTP/HTTPS
|
|
420
|
-
createHttpRoute,
|
|
421
|
-
createHttpsTerminateRoute,
|
|
422
|
-
createHttpsPassthroughRoute,
|
|
423
|
-
createHttpToHttpsRedirect,
|
|
424
|
-
createCompleteHttpsServer,
|
|
586
|
+
createHttpRoute, // Plain HTTP route
|
|
587
|
+
createHttpsTerminateRoute, // HTTPS with TLS termination
|
|
588
|
+
createHttpsPassthroughRoute, // SNI passthrough (no termination)
|
|
589
|
+
createHttpToHttpsRedirect, // HTTP → HTTPS redirect
|
|
590
|
+
createCompleteHttpsServer, // HTTPS + redirect combo (returns IRouteConfig[])
|
|
425
591
|
|
|
426
592
|
// Load Balancing
|
|
427
|
-
createLoadBalancerRoute,
|
|
428
|
-
createSmartLoadBalancer,
|
|
593
|
+
createLoadBalancerRoute, // Multi-backend with health checks
|
|
594
|
+
createSmartLoadBalancer, // Dynamic domain-based backend selection
|
|
429
595
|
|
|
430
596
|
// API & WebSocket
|
|
431
|
-
createApiRoute,
|
|
432
|
-
createApiGatewayRoute,
|
|
433
|
-
createWebSocketRoute,
|
|
597
|
+
createApiRoute, // API route with path matching
|
|
598
|
+
createApiGatewayRoute, // API gateway with CORS
|
|
599
|
+
createWebSocketRoute, // WebSocket-enabled route
|
|
434
600
|
|
|
435
601
|
// Custom Protocols
|
|
436
|
-
createSocketHandlerRoute,
|
|
437
|
-
SocketHandlers,
|
|
602
|
+
createSocketHandlerRoute, // Custom socket handler
|
|
603
|
+
SocketHandlers, // Pre-built handlers (echo, proxy, block, etc.)
|
|
438
604
|
|
|
439
|
-
// NFTables (Linux)
|
|
440
|
-
createNfTablesRoute,
|
|
441
|
-
createNfTablesTerminateRoute,
|
|
442
|
-
createCompleteNfTablesHttpsServer,
|
|
605
|
+
// NFTables (Linux, requires root)
|
|
606
|
+
createNfTablesRoute, // Kernel-level packet forwarding
|
|
607
|
+
createNfTablesTerminateRoute, // NFTables + TLS termination
|
|
608
|
+
createCompleteNfTablesHttpsServer, // NFTables HTTPS + redirect combo
|
|
443
609
|
|
|
444
610
|
// Dynamic Routing
|
|
445
|
-
createPortMappingRoute,
|
|
446
|
-
createOffsetPortMappingRoute,
|
|
447
|
-
createDynamicRoute,
|
|
611
|
+
createPortMappingRoute, // Port mapping with context
|
|
612
|
+
createOffsetPortMappingRoute, // Simple port offset
|
|
613
|
+
createDynamicRoute, // Dynamic host/port via functions
|
|
448
614
|
|
|
449
615
|
// Security Modifiers
|
|
450
|
-
addRateLimiting,
|
|
451
|
-
addBasicAuth,
|
|
452
|
-
addJwtAuth
|
|
616
|
+
addRateLimiting, // Add rate limiting to any route
|
|
617
|
+
addBasicAuth, // Add basic auth to any route
|
|
618
|
+
addJwtAuth, // Add JWT auth to any route
|
|
619
|
+
|
|
620
|
+
// Route Utilities
|
|
621
|
+
mergeRouteConfigs, // Deep-merge two route configs
|
|
622
|
+
findMatchingRoutes, // Find routes matching criteria
|
|
623
|
+
findBestMatchingRoute, // Find best matching route
|
|
624
|
+
cloneRoute, // Deep-clone a route
|
|
625
|
+
generateRouteId, // Generate deterministic route ID
|
|
626
|
+
RouteValidator, // Validate route configurations
|
|
453
627
|
} from '@push.rocks/smartproxy';
|
|
454
628
|
```
|
|
455
629
|
|
|
456
|
-
## 🐛 Troubleshooting
|
|
457
|
-
|
|
458
|
-
### Certificate Issues
|
|
459
|
-
- ✅ Ensure domain DNS points to your server
|
|
460
|
-
- ✅ Port 80 must be accessible for ACME HTTP-01 challenges
|
|
461
|
-
- ✅ Check DNS propagation with `dig` or `nslookup`
|
|
462
|
-
- ✅ Verify the email in ACME configuration is valid
|
|
463
|
-
|
|
464
|
-
### Connection Problems
|
|
465
|
-
- ✅ Check route priorities (higher number = matched first)
|
|
466
|
-
- ✅ Verify security rules aren't blocking legitimate traffic
|
|
467
|
-
- ✅ Test with `curl -v` for detailed connection output
|
|
468
|
-
- ✅ Enable debug logging for verbose output
|
|
469
|
-
|
|
470
|
-
### Performance Tuning
|
|
471
|
-
- ✅ Use NFTables forwarding for high-traffic routes (Linux only)
|
|
472
|
-
- ✅ Enable connection keep-alive where appropriate
|
|
473
|
-
- ✅ Monitor metrics to identify bottlenecks
|
|
474
|
-
- ✅ Adjust `maxConnections` based on your server resources
|
|
475
|
-
|
|
476
|
-
### Debug Mode
|
|
477
|
-
|
|
478
|
-
```typescript
|
|
479
|
-
const proxy = new SmartProxy({
|
|
480
|
-
enableDetailedLogging: true, // Verbose connection logging
|
|
481
|
-
routes: [...]
|
|
482
|
-
});
|
|
483
|
-
```
|
|
484
|
-
|
|
485
|
-
## 🏆 Best Practices
|
|
486
|
-
|
|
487
|
-
1. **📝 Use Helper Functions** - They provide sensible defaults and prevent common mistakes
|
|
488
|
-
2. **🎯 Set Route Priorities** - More specific routes should have higher priority values
|
|
489
|
-
3. **🔒 Enable Security** - Always use IP filtering and rate limiting for public services
|
|
490
|
-
4. **📊 Monitor Metrics** - Use the built-in metrics to identify issues early
|
|
491
|
-
5. **🔄 Certificate Monitoring** - Set up alerts for certificate expiration
|
|
492
|
-
6. **🛑 Graceful Shutdown** - Always call `proxy.stop()` for clean connection termination
|
|
493
|
-
7. **🔧 Test Routes** - Validate your route configurations before deploying to production
|
|
494
|
-
|
|
495
630
|
## 📖 API Documentation
|
|
496
631
|
|
|
497
632
|
### SmartProxy Class
|
|
498
633
|
|
|
499
634
|
```typescript
|
|
500
|
-
class SmartProxy {
|
|
635
|
+
class SmartProxy extends EventEmitter {
|
|
501
636
|
constructor(options: ISmartProxyOptions);
|
|
502
637
|
|
|
503
638
|
// Lifecycle
|
|
504
639
|
start(): Promise<void>;
|
|
505
640
|
stop(): Promise<void>;
|
|
506
641
|
|
|
507
|
-
// Route Management
|
|
642
|
+
// Route Management (atomic, mutex-locked)
|
|
508
643
|
updateRoutes(routes: IRouteConfig[]): Promise<void>;
|
|
509
644
|
|
|
510
645
|
// Port Management
|
|
511
646
|
addListeningPort(port: number): Promise<void>;
|
|
512
647
|
removeListeningPort(port: number): Promise<void>;
|
|
513
|
-
getListeningPorts(): number[]
|
|
648
|
+
getListeningPorts(): Promise<number[]>;
|
|
514
649
|
|
|
515
|
-
// Monitoring
|
|
516
|
-
|
|
517
|
-
|
|
650
|
+
// Monitoring & Metrics
|
|
651
|
+
getMetrics(): IMetrics; // Sync — returns cached metrics adapter
|
|
652
|
+
getStatistics(): Promise<any>; // Async — queries Rust engine
|
|
518
653
|
|
|
519
654
|
// Certificate Management
|
|
520
|
-
|
|
655
|
+
provisionCertificate(routeName: string): Promise<void>;
|
|
656
|
+
renewCertificate(routeName: string): Promise<void>;
|
|
657
|
+
getCertificateStatus(routeName: string): Promise<any>;
|
|
658
|
+
getEligibleDomainsForCertificates(): string[];
|
|
659
|
+
|
|
660
|
+
// NFTables
|
|
661
|
+
getNfTablesStatus(): Promise<Record<string, any>>;
|
|
662
|
+
|
|
663
|
+
// Events
|
|
664
|
+
on(event: 'error', handler: (err: Error) => void): this;
|
|
521
665
|
}
|
|
522
666
|
```
|
|
523
667
|
|
|
@@ -525,29 +669,110 @@ class SmartProxy {
|
|
|
525
669
|
|
|
526
670
|
```typescript
|
|
527
671
|
interface ISmartProxyOptions {
|
|
528
|
-
routes: IRouteConfig[];
|
|
672
|
+
routes: IRouteConfig[]; // Required: array of route configs
|
|
529
673
|
|
|
530
674
|
// ACME/Let's Encrypt
|
|
531
675
|
acme?: {
|
|
532
|
-
email: string;
|
|
533
|
-
useProduction?: boolean;
|
|
534
|
-
port?: number;
|
|
535
|
-
renewThresholdDays?: number;
|
|
676
|
+
email: string; // Contact email for Let's Encrypt
|
|
677
|
+
useProduction?: boolean; // Use production servers (default: false)
|
|
678
|
+
port?: number; // HTTP-01 challenge port (default: 80)
|
|
679
|
+
renewThresholdDays?: number; // Days before expiry to renew (default: 30)
|
|
680
|
+
autoRenew?: boolean; // Enable auto-renewal (default: true)
|
|
681
|
+
certificateStore?: string; // Directory to store certs (default: './certs')
|
|
682
|
+
renewCheckIntervalHours?: number; // Renewal check interval (default: 24)
|
|
536
683
|
};
|
|
537
684
|
|
|
538
|
-
//
|
|
685
|
+
// Custom certificate provisioning
|
|
686
|
+
certProvisionFunction?: (domain: string) => Promise<ICert | 'http01'>;
|
|
687
|
+
certProvisionFallbackToAcme?: boolean; // Fall back to ACME on failure (default: true)
|
|
688
|
+
|
|
689
|
+
// Global defaults
|
|
539
690
|
defaults?: {
|
|
540
691
|
target?: { host: string; port: number };
|
|
541
|
-
security?:
|
|
542
|
-
|
|
692
|
+
security?: { ipAllowList?: string[]; ipBlockList?: string[]; maxConnections?: number };
|
|
693
|
+
};
|
|
694
|
+
|
|
695
|
+
// PROXY protocol
|
|
696
|
+
proxyIPs?: string[]; // Trusted proxy IPs
|
|
697
|
+
acceptProxyProtocol?: boolean; // Accept PROXY protocol headers
|
|
698
|
+
sendProxyProtocol?: boolean; // Send PROXY protocol to targets
|
|
699
|
+
|
|
700
|
+
// Timeouts
|
|
701
|
+
connectionTimeout?: number; // Backend connection timeout (default: 30s)
|
|
702
|
+
initialDataTimeout?: number; // Initial data/SNI timeout (default: 60s)
|
|
703
|
+
socketTimeout?: number; // Socket inactivity timeout (default: 1h)
|
|
704
|
+
maxConnectionLifetime?: number; // Max connection lifetime (default: 24h)
|
|
705
|
+
inactivityTimeout?: number; // Inactivity timeout (default: 4h)
|
|
706
|
+
gracefulShutdownTimeout?: number; // Shutdown grace period (default: 30s)
|
|
707
|
+
|
|
708
|
+
// Connection limits
|
|
709
|
+
maxConnectionsPerIP?: number; // Per-IP connection limit (default: 100)
|
|
710
|
+
connectionRateLimitPerMinute?: number; // Per-IP rate limit (default: 300/min)
|
|
711
|
+
|
|
712
|
+
// Keep-alive
|
|
713
|
+
keepAliveTreatment?: 'standard' | 'extended' | 'immortal';
|
|
714
|
+
keepAliveInactivityMultiplier?: number; // (default: 6)
|
|
715
|
+
extendedKeepAliveLifetime?: number; // (default: 7 days)
|
|
716
|
+
|
|
717
|
+
// Metrics
|
|
718
|
+
metrics?: {
|
|
719
|
+
enabled?: boolean;
|
|
720
|
+
sampleIntervalMs?: number;
|
|
721
|
+
retentionSeconds?: number;
|
|
543
722
|
};
|
|
544
723
|
|
|
545
724
|
// Behavior
|
|
546
|
-
enableDetailedLogging?: boolean;
|
|
547
|
-
|
|
725
|
+
enableDetailedLogging?: boolean; // Verbose connection logging
|
|
726
|
+
enableTlsDebugLogging?: boolean; // TLS handshake debug logging
|
|
727
|
+
|
|
728
|
+
// Rust binary
|
|
729
|
+
rustBinaryPath?: string; // Custom path to the Rust binary
|
|
548
730
|
}
|
|
549
731
|
```
|
|
550
732
|
|
|
733
|
+
## 🐛 Troubleshooting
|
|
734
|
+
|
|
735
|
+
### Certificate Issues
|
|
736
|
+
- ✅ Ensure domain DNS points to your server
|
|
737
|
+
- ✅ Port 80 must be accessible for ACME HTTP-01 challenges
|
|
738
|
+
- ✅ Check DNS propagation with `dig` or `nslookup`
|
|
739
|
+
- ✅ Verify the email in ACME configuration is valid
|
|
740
|
+
- ✅ Use `getCertificateStatus('route-name')` to check cert state
|
|
741
|
+
|
|
742
|
+
### Connection Problems
|
|
743
|
+
- ✅ Check route priorities (higher number = matched first)
|
|
744
|
+
- ✅ Verify security rules aren't blocking legitimate traffic
|
|
745
|
+
- ✅ Test with `curl -v` for detailed connection output
|
|
746
|
+
- ✅ Enable debug logging with `enableDetailedLogging: true`
|
|
747
|
+
|
|
748
|
+
### Rust Binary Not Found
|
|
749
|
+
SmartProxy searches for the Rust binary in this order:
|
|
750
|
+
1. `SMARTPROXY_RUST_BINARY` environment variable
|
|
751
|
+
2. Platform-specific npm package (`@push.rocks/smartproxy-linux-x64`, etc.)
|
|
752
|
+
3. Local dev build (`./rust/target/release/rustproxy`)
|
|
753
|
+
4. System PATH (`rustproxy`)
|
|
754
|
+
|
|
755
|
+
Set `rustBinaryPath` in options to override.
|
|
756
|
+
|
|
757
|
+
### Performance Tuning
|
|
758
|
+
- ✅ Use NFTables forwarding for high-traffic routes (Linux only)
|
|
759
|
+
- ✅ Enable connection keep-alive where appropriate
|
|
760
|
+
- ✅ Use `getMetrics()` and `getStatistics()` to identify bottlenecks
|
|
761
|
+
- ✅ Adjust `maxConnectionsPerIP` and `connectionRateLimitPerMinute` based on your workload
|
|
762
|
+
- ✅ Use `passthrough` TLS mode when backend can handle TLS directly
|
|
763
|
+
|
|
764
|
+
## 🏆 Best Practices
|
|
765
|
+
|
|
766
|
+
1. **📝 Use Helper Functions** — They provide sensible defaults and prevent common mistakes
|
|
767
|
+
2. **🎯 Set Route Priorities** — More specific routes should have higher priority values
|
|
768
|
+
3. **🔒 Enable Security** — Always use IP filtering and rate limiting for public-facing services
|
|
769
|
+
4. **📊 Monitor Metrics** — Use the built-in metrics to catch issues early
|
|
770
|
+
5. **🔄 Certificate Monitoring** — Set up alerts before certificates expire
|
|
771
|
+
6. **🛑 Graceful Shutdown** — Always call `proxy.stop()` for clean connection termination
|
|
772
|
+
7. **✅ Validate Routes** — Use `RouteValidator.validateRoutes()` to catch config errors before deployment
|
|
773
|
+
8. **🔀 Atomic Updates** — Use `updateRoutes()` for hot-reloading routes (mutex-locked, no downtime)
|
|
774
|
+
9. **🎮 Use Socket Handlers** — For protocols beyond HTTP, implement custom socket handlers instead of fighting the proxy model
|
|
775
|
+
|
|
551
776
|
## License and Legal Information
|
|
552
777
|
|
|
553
778
|
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](./LICENSE) file.
|