@push.rocks/smartproxy 27.21.0 → 28.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/readme.hints.md DELETED
@@ -1,561 +0,0 @@
1
- # SmartProxy Development Hints
2
-
3
- ## Byte Tracking and Metrics
4
-
5
- ### Throughput Drift Issue (Fixed)
6
-
7
- **Problem**: Throughput numbers were gradually increasing over time for long-lived connections.
8
-
9
- **Root Cause**: The `byRoute()` and `byIP()` methods were dividing cumulative total bytes (since connection start) by the window duration, causing rates to appear higher as connections aged:
10
- - Hour 1: 1GB total / 60s = 17 MB/s ✓
11
- - Hour 2: 2GB total / 60s = 34 MB/s ✗ (appears doubled!)
12
- - Hour 3: 3GB total / 60s = 50 MB/s ✗ (keeps rising!)
13
-
14
- **Solution**: Implemented dedicated ThroughputTracker instances for each route and IP address:
15
- - Each route and IP gets its own throughput tracker with per-second sampling
16
- - Samples are taken every second and stored in a circular buffer
17
- - Rate calculations use actual samples within the requested window
18
- - Default window is now 1 second for real-time accuracy
19
-
20
- ### What Gets Counted (Network Interface Throughput)
21
-
22
- The byte tracking is designed to match network interface throughput (what Unifi/network monitoring tools show):
23
-
24
- **Counted bytes include:**
25
- - All application data
26
- - TLS handshakes and protocol overhead
27
- - TLS record headers and encryption padding
28
- - HTTP headers and protocol data
29
- - WebSocket frames and protocol overhead
30
- - TLS alerts sent to clients
31
-
32
- **NOT counted:**
33
- - PROXY protocol headers (sent to backend, not client)
34
- - TCP/IP headers (handled by OS, not visible at application layer)
35
-
36
- **Byte direction:**
37
- - `bytesReceived`: All bytes received FROM the client on the incoming connection
38
- - `bytesSent`: All bytes sent TO the client on the incoming connection
39
- - Backend connections are separate and not mixed with client metrics
40
-
41
- ### Double Counting Issue (Fixed)
42
-
43
- **Problem**: Initial data chunks were being counted twice in the byte tracking:
44
- 1. Once when stored in `pendingData` in `setupDirectConnection()`
45
- 2. Again when the data flowed through bidirectional forwarding
46
-
47
- **Solution**: Removed the byte counting when storing initial chunks. Bytes are now only counted when they actually flow through the `setupBidirectionalForwarding()` callbacks.
48
-
49
- ### HttpProxy Metrics (Fixed)
50
-
51
- **Problem**: HttpProxy forwarding was updating connection record byte counts but not calling `metricsCollector.recordBytes()`, resulting in missing throughput data.
52
-
53
- **Solution**: Added `metricsCollector.recordBytes()` calls to the HttpProxy bidirectional forwarding callbacks.
54
-
55
- ### Metrics Architecture
56
-
57
- The metrics system has multiple layers:
58
- 1. **Connection Records** (`record.bytesReceived/bytesSent`): Track total bytes per connection
59
- 2. **Global ThroughputTracker**: Accumulates bytes between samples for overall rate calculations
60
- 3. **Per-Route ThroughputTrackers**: Dedicated tracker for each route with per-second sampling
61
- 4. **Per-IP ThroughputTrackers**: Dedicated tracker for each IP with per-second sampling
62
- 5. **connectionByteTrackers**: Track cumulative bytes and metadata for active connections
63
-
64
- Key features:
65
- - All throughput trackers sample every second (1Hz)
66
- - Each tracker maintains a circular buffer of samples (default: 1 hour retention)
67
- - Rate calculations are accurate for any requested window (default: 1 second)
68
- - All byte counting happens exactly once at the data flow point
69
- - Unused route/IP trackers are automatically cleaned up when connections close
70
-
71
- ### Understanding "High" Byte Counts
72
-
73
- If byte counts seem high compared to actual application data, remember:
74
- - TLS handshakes can be 1-5KB depending on cipher suites and certificates
75
- - Each TLS record has 5 bytes of header overhead
76
- - TLS encryption adds 16-48 bytes of padding/MAC per record
77
- - HTTP/2 has additional framing overhead
78
- - WebSocket has frame headers (2-14 bytes per message)
79
-
80
- This overhead is real network traffic and should be counted for accurate throughput metrics.
81
-
82
- ### Byte Counting Paths
83
-
84
- There are two mutually exclusive paths for connections:
85
-
86
- 1. **Direct forwarding** (route-connection-handler.ts):
87
- - Used for TCP passthrough, TLS passthrough, and direct connections
88
- - Bytes counted in `setupBidirectionalForwarding` callbacks
89
- - Initial chunk NOT counted separately (flows through bidirectional forwarding)
90
-
91
- 2. **HttpProxy forwarding** (http-proxy-bridge.ts):
92
- - Used for TLS termination (terminate, terminate-and-reencrypt)
93
- - Initial chunk counted when written to proxy
94
- - All subsequent bytes counted in `setupBidirectionalForwarding` callbacks
95
- - This is the ONLY counting point for these connections
96
-
97
- ### Byte Counting Audit (2025-01-06)
98
-
99
- A comprehensive audit was performed to verify byte counting accuracy:
100
-
101
- **Audit Results:**
102
- - ✅ No double counting detected in any connection flow
103
- - ✅ Each byte counted exactly once in each direction
104
- - ✅ Connection records and metrics updated consistently
105
- - ✅ PROXY protocol headers correctly excluded from client metrics
106
- - ✅ NFTables forwarded connections correctly not counted (kernel handles)
107
-
108
- **Key Implementation Points:**
109
- - All byte counting happens in only 2 files: `route-connection-handler.ts` and `http-proxy-bridge.ts`
110
- - Both use the same pattern: increment `record.bytesReceived/Sent` AND call `metricsCollector.recordBytes()`
111
- - Initial chunks handled correctly: stored but not counted until forwarded
112
- - TLS alerts counted as sent bytes (correct - they are sent to client)
113
-
114
- For full audit details, see `readme.byte-counting-audit.md`
115
-
116
- ## Connection Cleanup
117
-
118
- ### Zombie Connection Detection
119
-
120
- The connection manager performs comprehensive zombie detection every 10 seconds:
121
- - **Full zombies**: Both incoming and outgoing sockets destroyed but connection not cleaned up
122
- - **Half zombies**: One socket destroyed, grace period expired (5 minutes for TLS, 30 seconds for non-TLS)
123
- - **Stuck connections**: Data received but none sent back after threshold (5 minutes for TLS, 60 seconds for non-TLS)
124
-
125
- ### Cleanup Queue
126
-
127
- Connections are cleaned up through a batched queue system:
128
- - Batch size: 100 connections
129
- - Processing triggered immediately when batch size reached
130
- - Otherwise processed after 100ms delay
131
- - Prevents overwhelming the system during mass disconnections
132
-
133
- ## Keep-Alive Handling
134
-
135
- Keep-alive connections receive special treatment based on `keepAliveTreatment` setting:
136
- - **standard**: Normal timeout applies
137
- - **extended**: Timeout multiplied by `keepAliveInactivityMultiplier` (default 6x)
138
- - **immortal**: No timeout, connections persist indefinitely
139
-
140
- ## PROXY Protocol
141
-
142
- The system supports both receiving and sending PROXY protocol:
143
- - **Receiving**: Enabled explicitly per listener through `match.inboundProxyProtocol`; the global `trustedProxyIPs` list only supplies trust entries for explicit `optional` or `required` policies
144
- - **Sending**: Enabled per-target, per-route, or globally via `sendProxyProtocol`
145
- - Real client IP is preserved and used for all connection tracking and security checks
146
-
147
- ## Metrics and Throughput Calculation
148
-
149
- The metrics system tracks throughput using per-second sampling:
150
-
151
- 1. **Byte Recording**: Bytes are recorded as data flows through connections
152
- 2. **Sampling**: Every second, accumulated bytes are stored as a sample
153
- 3. **Rate Calculation**: Throughput is calculated by summing bytes over a time window
154
- 4. **Per-Route/IP Tracking**: Separate ThroughputTracker instances for each route and IP
155
-
156
- Key implementation details:
157
- - Bytes are recorded in the bidirectional forwarding callbacks
158
- - The instant() method returns throughput over the last 1 second
159
- - The recent() method returns throughput over the last 10 seconds
160
- - Custom windows can be specified for different averaging periods
161
-
162
- ### Throughput Spikes Issue
163
-
164
- There's a fundamental difference between application-layer and network-layer throughput:
165
-
166
- **Application Layer (what we measure)**:
167
- - Bytes are recorded when delivered to/from the application
168
- - Large chunks can arrive "instantly" due to kernel/Node.js buffering
169
- - Shows spikes when buffers are flushed (e.g., 20MB in 1 second = 160 Mbit/s)
170
-
171
- **Network Layer (what Unifi shows)**:
172
- - Actual packet flow through the network interface
173
- - Limited by physical network speed (e.g., 20 Mbit/s)
174
- - Data transfers over time, not in bursts
175
-
176
- The spikes occur because:
177
- 1. Data flows over network at 20 Mbit/s (takes 8 seconds for 20MB)
178
- 2. Kernel/Node.js buffers this incoming data
179
- 3. When buffer is flushed, application receives large chunk at once
180
- 4. We record entire chunk in current second, creating artificial spike
181
-
182
- **Potential Solutions**:
183
- 1. Use longer window for "instant" measurements (e.g., 5 seconds instead of 1)
184
- 2. Track socket write backpressure to estimate actual network flow
185
- 3. Implement bandwidth estimation based on connection duration
186
- 4. Accept that application-layer != network-layer throughput
187
-
188
- ## Connection Limiting
189
-
190
- ### Per-IP Connection Limits
191
- - SmartProxy tracks connections per IP address in the SecurityManager
192
- - Default limit is 100 connections per IP (configurable via `maxConnectionsPerIP`)
193
- - Connection rate limiting is also enforced (default 300 connections/minute per IP)
194
- - HttpProxy has been enhanced to also enforce per-IP limits when forwarding from SmartProxy
195
-
196
- ### Route-Level Connection Limits
197
- - Routes can define `security.maxConnections` to limit connections per route
198
- - Rust `HttpProxyService` enforces HTTP route limits after the route has matched and before forwarding
199
- - Exceeded route limits return terminal `429` responses; lower-priority fallback routes are not considered
200
- - Route counters are keyed by route id, then route name, and retained while non-zero across route updates
201
- - Streamed HTTP/H3 response bodies and WebSocket tunnels hold the route slot until the body/tunnel closes
202
-
203
- ### HttpProxy Integration
204
- - When SmartProxy forwards to HttpProxy for TLS termination, it sends a `CLIENT_IP:<ip>\r\n` header
205
- - HttpProxy parses this header to track the real client IP, not the localhost IP
206
- - This ensures per-IP limits are enforced even for forwarded connections
207
- - The header is parsed in the connection handler before any data processing
208
-
209
- ### Memory Optimization
210
- - Periodic cleanup runs every 60 seconds to remove:
211
- - IPs with no active connections
212
- - Expired rate limit timestamps (older than 1 minute)
213
- - Prevents memory accumulation from many unique IPs over time
214
- - Cleanup is automatic and runs in background with `unref()` to not keep process alive
215
-
216
- ### Connection Cleanup Queue
217
- - Cleanup queue processes connections in batches to prevent overwhelming the system
218
- - Race condition prevention using `isProcessingCleanup` flag
219
- - Try-finally block ensures flag is always reset even if errors occur
220
- - New connections added during processing are queued for next batch
221
-
222
- ### Important Implementation Notes
223
- - Always use `NodeJS.Timeout` type instead of `NodeJS.Timer` for interval/timeout references
224
- - IPv4/IPv6 normalization is handled (e.g., `::ffff:127.0.0.1` and `127.0.0.1` are treated as the same IP)
225
- - Connection limits are checked before route matching to prevent DoS attacks
226
- - SharedSecurityManager supports checking route-level limits via optional parameter
227
-
228
- ## Log Deduplication
229
-
230
- To reduce log spam during high-traffic scenarios or attacks, SmartProxy implements log deduplication for repetitive events:
231
-
232
- ### How It Works
233
- - Similar log events are batched and aggregated over a 5-second window
234
- - Instead of logging each event individually, a summary is emitted
235
- - Events are grouped by type and deduplicated by key (e.g., IP address, reason)
236
-
237
- ### Deduplicated Event Types
238
- 1. **Connection Rejections** (`connection-rejected`):
239
- - Groups by rejection reason (global-limit, route-limit, etc.)
240
- - Example: "Rejected 150 connections (reasons: global-limit: 100, route-limit: 50)"
241
-
242
- 2. **IP Rejections** (`ip-rejected`):
243
- - Groups by IP address
244
- - Shows top offenders with rejection counts and reasons
245
- - Example: "Rejected 500 connections from 10 IPs (top offenders: 192.168.1.100 (200x, rate-limit), ...)"
246
-
247
- 3. **Connection Cleanups** (`connection-cleanup`):
248
- - Groups by cleanup reason (normal, timeout, error, zombie, etc.)
249
- - Example: "Cleaned up 250 connections (reasons: normal: 200, timeout: 30, error: 20)"
250
-
251
- 4. **IP Tracking Cleanup** (`ip-cleanup`):
252
- - Summarizes periodic IP cleanup operations
253
- - Example: "IP tracking cleanup: removed 50 entries across 5 cleanup cycles"
254
-
255
- ### Configuration
256
- - Default flush interval: 5 seconds
257
- - Maximum batch size: 100 events (triggers immediate flush)
258
- - Global periodic flush: Every 10 seconds (ensures logs are emitted regularly)
259
- - Process exit handling: Logs are flushed on SIGINT/SIGTERM
260
-
261
- ### Benefits
262
- - Reduces log volume during attacks or high traffic
263
- - Provides better overview of patterns (e.g., which IPs are attacking)
264
- - Improves log readability and analysis
265
- - Prevents log storage overflow
266
- - Maintains detailed information in aggregated form
267
-
268
- ### Log Output Examples
269
-
270
- Instead of hundreds of individual logs:
271
- ```
272
- Connection rejected
273
- Connection rejected
274
- Connection rejected
275
- ... (repeated 500 times)
276
- ```
277
-
278
- You'll see:
279
- ```
280
- [SUMMARY] Rejected 500 connections from 10 IPs in 5s (rate-limit: 350, per-ip-limit: 150) (top offenders: 192.168.1.100 (200x, rate-limit), 10.0.0.1 (150x, per-ip-limit))
281
- ```
282
-
283
- Instead of:
284
- ```
285
- Connection terminated: ::ffff:127.0.0.1 (client_closed). Active: 266
286
- Connection terminated: ::ffff:127.0.0.1 (client_closed). Active: 265
287
- ... (repeated 266 times)
288
- ```
289
-
290
- You'll see:
291
- ```
292
- [SUMMARY] 266 HttpProxy connections terminated in 5s (reasons: client_closed: 266, activeConnections: 0)
293
- ```
294
-
295
- ### Rapid Event Handling
296
- - During attacks or high-volume scenarios, logs are flushed more frequently
297
- - If 50+ events occur within 1 second, immediate flush is triggered
298
- - Prevents memory buildup during flooding attacks
299
- - Maintains real-time visibility during incidents
300
-
301
- ## Custom Certificate Provision Function
302
-
303
- The `certProvisionFunction` feature has been implemented to allow users to provide their own certificate generation logic.
304
-
305
- ### Implementation Details
306
-
307
- 1. **Type Definition**: The function must return `Promise<TSmartProxyCertProvisionObject>` where:
308
- - `TSmartProxyCertProvisionObject = plugins.tsclass.network.ICert | 'http01'`
309
- - Return `'http01'` to fallback to Let's Encrypt
310
- - Return a certificate object for custom certificates
311
-
312
- 2. **Certificate Manager Changes**:
313
- - Added `certProvisionFunction` property to CertificateManager
314
- - Modified `provisionAcmeCertificate()` to check custom function first
315
- - Custom certificates are stored with source type 'custom'
316
- - Expiry date extraction currently defaults to 90 days
317
-
318
- 3. **Configuration Options**:
319
- - `certProvisionFunction`: The custom provision function
320
- - `certProvisionFallbackToAcme`: Whether to fallback to ACME on error (default: true)
321
-
322
- 4. **Usage Example**:
323
- ```typescript
324
- new SmartProxy({
325
- certProvisionFunction: async (domain: string) => {
326
- if (domain === 'internal.example.com') {
327
- return {
328
- cert: customCert,
329
- key: customKey,
330
- ca: customCA
331
- } as unknown as TSmartProxyCertProvisionObject;
332
- }
333
- return 'http01'; // Use Let's Encrypt
334
- },
335
- certProvisionFallbackToAcme: true
336
- })
337
- ```
338
-
339
- 5. **Testing Notes**:
340
- - Type assertions through `unknown` are needed in tests due to strict interface typing
341
- - Mock certificate objects work for testing but need proper type casting
342
- - The actual certificate parsing for expiry dates would need a proper X.509 parser
343
-
344
- ### Future Improvements
345
-
346
- 1. Implement proper certificate expiry date extraction using X.509 parsing
347
- 2. Add support for returning expiry date with custom certificates
348
- 3. Consider adding validation for custom certificate format
349
- 4. Add events/hooks for certificate provisioning lifecycle
350
-
351
- ## HTTPS/TLS Configuration Guide
352
-
353
- SmartProxy supports three TLS modes for handling HTTPS traffic. Understanding when to use each mode is crucial for correct configuration.
354
-
355
- ### TLS Mode: Passthrough (SNI Routing)
356
-
357
- **When to use**: Backend server handles its own TLS certificates.
358
-
359
- **How it works**:
360
- 1. Client connects with TLS ClientHello containing SNI (Server Name Indication)
361
- 2. SmartProxy extracts the SNI hostname without decrypting
362
- 3. Connection is forwarded to backend as-is (still encrypted)
363
- 4. Backend server terminates TLS with its own certificate
364
-
365
- **Configuration**:
366
- ```typescript
367
- {
368
- match: { ports: 443, domains: 'backend.example.com' },
369
- action: {
370
- type: 'forward',
371
- targets: [{ host: 'backend-server', port: 443 }],
372
- tls: { mode: 'passthrough' }
373
- }
374
- }
375
- ```
376
-
377
- **Requirements**:
378
- - Backend must have valid TLS certificate for the domain
379
- - Client's SNI must be present (session tickets without SNI will be rejected)
380
- - No HTTP-level inspection possible (encrypted end-to-end)
381
-
382
- ### TLS Mode: Terminate
383
-
384
- **When to use**: SmartProxy handles TLS, backend receives plain HTTP.
385
-
386
- **How it works**:
387
- 1. Client connects with TLS ClientHello
388
- 2. SmartProxy terminates TLS (decrypts traffic)
389
- 3. Decrypted HTTP is forwarded to backend on plain HTTP port
390
- 4. Backend receives unencrypted traffic
391
-
392
- **Configuration**:
393
- ```typescript
394
- {
395
- match: { ports: 443, domains: 'api.example.com' },
396
- action: {
397
- type: 'forward',
398
- targets: [{ host: 'localhost', port: 8080 }], // HTTP backend
399
- tls: {
400
- mode: 'terminate',
401
- certificate: 'auto' // Let's Encrypt, or provide { key, cert }
402
- }
403
- }
404
- }
405
- ```
406
-
407
- **Requirements**:
408
- - ACME email configured for auto certificates: `acme: { email: 'admin@example.com' }`
409
- - Port 80 available for HTTP-01 challenges (or use DNS-01)
410
- - Backend accessible on HTTP port
411
-
412
- ### TLS Mode: Terminate and Re-encrypt
413
-
414
- **When to use**: SmartProxy handles client TLS, but backend also requires TLS.
415
-
416
- **How it works**:
417
- 1. Client connects with TLS ClientHello
418
- 2. SmartProxy terminates client TLS (decrypts)
419
- 3. SmartProxy creates new TLS connection to backend
420
- 4. Traffic is re-encrypted for the backend connection
421
-
422
- **Configuration**:
423
- ```typescript
424
- {
425
- match: { ports: 443, domains: 'secure.example.com' },
426
- action: {
427
- type: 'forward',
428
- targets: [{ host: 'backend-tls', port: 443 }], // HTTPS backend
429
- tls: {
430
- mode: 'terminate-and-reencrypt',
431
- certificate: 'auto'
432
- }
433
- }
434
- }
435
- ```
436
-
437
- **Requirements**:
438
- - Same as 'terminate' mode
439
- - Backend must have valid TLS (can be self-signed for internal use)
440
-
441
- ### HttpProxy Integration
442
-
443
- For TLS termination modes (`terminate` and `terminate-and-reencrypt`), SmartProxy uses an internal HttpProxy component:
444
-
445
- - HttpProxy listens on an internal port (default: 8443)
446
- - SmartProxy forwards TLS connections to HttpProxy for termination
447
- - Client IP is preserved via `CLIENT_IP:` header protocol
448
- - HTTP/2 and WebSocket are supported after TLS termination
449
-
450
- **Configuration**:
451
- ```typescript
452
- {
453
- useHttpProxy: [443], // Ports that use HttpProxy for TLS termination
454
- httpProxyPort: 8443, // Internal HttpProxy port
455
- acme: {
456
- email: 'admin@example.com',
457
- useProduction: true // false for Let's Encrypt staging
458
- }
459
- }
460
- ```
461
-
462
- ### Common Configuration Patterns
463
-
464
- **HTTP to HTTPS Redirect**:
465
- ```typescript
466
- import { SocketHandlers } from '@push.rocks/smartproxy';
467
-
468
- const redirectRoute = {
469
- name: 'http-to-https',
470
- match: { ports: 80, domains: ['example.com', 'www.example.com'] },
471
- action: {
472
- type: 'socket-handler' as const,
473
- socketHandler: SocketHandlers.httpRedirect('https://{domain}:443{path}', 301)
474
- }
475
- };
476
- ```
477
-
478
- **Complete HTTPS Server (with redirect)**:
479
- ```typescript
480
- const routes = [
481
- {
482
- name: 'https-server',
483
- match: { ports: 443, domains: 'example.com' },
484
- action: {
485
- type: 'forward' as const,
486
- targets: [{ host: 'localhost', port: 8080 }],
487
- tls: { mode: 'terminate' as const, certificate: 'auto' as const }
488
- }
489
- },
490
- {
491
- name: 'http-redirect',
492
- match: { ports: 80, domains: 'example.com' },
493
- action: {
494
- type: 'socket-handler' as const,
495
- socketHandler: SocketHandlers.httpRedirect('https://{domain}:443{path}', 301)
496
- }
497
- }
498
- ];
499
- ```
500
-
501
- **Load Balancer with Health Checks**:
502
- ```typescript
503
- const lbRoute = {
504
- name: 'load-balancer',
505
- match: { ports: 443, domains: 'api.example.com' },
506
- action: {
507
- type: 'forward' as const,
508
- targets: [
509
- { host: 'backend1', port: 8080 },
510
- { host: 'backend2', port: 8080 },
511
- { host: 'backend3', port: 8080 }
512
- ],
513
- tls: { mode: 'terminate' as const, certificate: 'auto' as const },
514
- loadBalancing: { algorithm: 'round-robin' as const }
515
- }
516
- };
517
- ```
518
-
519
- ### Smart SNI Requirement (v22.3+)
520
-
521
- SmartProxy automatically determines when SNI is required for routing. Session tickets (TLS resumption without SNI) are now allowed in more scenarios:
522
-
523
- **SNI NOT required (session tickets allowed):**
524
- - Single passthrough route with static target(s) and no domain restriction
525
- - Single passthrough route with wildcard-only domain (`*` or `['*']`)
526
- - TLS termination routes (`terminate` or `terminate-and-reencrypt`)
527
- - Mixed terminate + passthrough routes (termination takes precedence)
528
-
529
- **SNI IS required (session tickets blocked):**
530
- - Multiple passthrough routes on the same port (need SNI to pick correct route)
531
- - Route has dynamic host function (e.g., `host: (ctx) => ctx.domain === 'api.example.com' ? 'api-backend' : 'web-backend'`)
532
- - Route has specific domain restriction (e.g., `domains: 'api.example.com'` or `domains: '*.example.com'`)
533
-
534
- This allows simple single-target passthrough setups to work with TLS session resumption, improving performance for clients that reuse connections.
535
-
536
- ### Troubleshooting
537
-
538
- **"No SNI detected" errors**:
539
- - Client is using TLS session resumption without SNI
540
- - Solution: Configure route for TLS termination (allows session resumption), or ensure you have a single-target passthrough route with no domain restrictions
541
-
542
- **"HttpProxy not available" errors**:
543
- - `useHttpProxy` not configured for the port
544
- - Solution: Add port to `useHttpProxy` array in settings
545
-
546
- **Certificate provisioning failures**:
547
- - Port 80 not accessible for HTTP-01 challenges
548
- - ACME email not configured
549
- - Solution: Ensure port 80 is available and `acme.email` is set
550
-
551
- **Connection timeouts to HttpProxy**:
552
- - CLIENT_IP header parsing timeout (default: 2000ms)
553
- - Network congestion between SmartProxy and HttpProxy
554
- - Solution: Check localhost connectivity, increase timeout if needed
555
-
556
- ## Static Rust Binaries
557
-
558
- - The Rust binaries in `dist_rust/` are statically linked (static-pie) via `"static": true` in the `@git.zone/tsrust` block of `.smartconfig.json` (tsrust >= 1.4.1). They run on both glibc (Debian/Ubuntu) and musl (Alpine) systems.
559
- - tsrust injects `RUSTFLAGS="-C target-feature=+crt-static"` only into its own per-target cargo invocations and verifies the result (no `PT_INTERP` ELF header). Keep `rust/.cargo/config.toml` free of `rustflags` entries: the injected env variable would replace them, and a repo-wide `rustflags` would also break plain `cargo test`/`cargo check` (proc-macros cannot build with `+crt-static` on linux-gnu without an explicit `--target`). The repo previously carried such `rustflags` lines; they were removed when the tsrust `static` option was adopted.
560
- - `pnpm run test:rust` runs the Rust unit tests; plain `cargo test` in `rust/` works as well.
561
- - Verify linkage manually with `ldd dist_rust/<binary>_linux_amd64` → "statically linked".