@push.rocks/smartproxy 19.6.2 → 19.6.7
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/dist_ts/proxies/smart-proxy/connection-manager.d.ts +4 -7
- package/dist_ts/proxies/smart-proxy/connection-manager.js +22 -22
- package/dist_ts/proxies/smart-proxy/http-proxy-bridge.d.ts +4 -3
- package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +9 -9
- package/dist_ts/proxies/smart-proxy/metrics-collector.d.ts +68 -56
- package/dist_ts/proxies/smart-proxy/metrics-collector.js +226 -176
- package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +5 -0
- package/dist_ts/proxies/smart-proxy/models/metrics-types.d.ts +94 -48
- package/dist_ts/proxies/smart-proxy/nftables-manager.d.ts +4 -4
- package/dist_ts/proxies/smart-proxy/nftables-manager.js +6 -6
- package/dist_ts/proxies/smart-proxy/port-manager.d.ts +4 -7
- package/dist_ts/proxies/smart-proxy/port-manager.js +6 -9
- package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +4 -15
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +128 -128
- package/dist_ts/proxies/smart-proxy/security-manager.d.ts +3 -3
- package/dist_ts/proxies/smart-proxy/security-manager.js +9 -9
- package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +20 -13
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +16 -13
- package/dist_ts/proxies/smart-proxy/throughput-tracker.d.ts +36 -0
- package/dist_ts/proxies/smart-proxy/throughput-tracker.js +117 -0
- package/dist_ts/proxies/smart-proxy/timeout-manager.d.ts +4 -3
- package/dist_ts/proxies/smart-proxy/timeout-manager.js +16 -16
- package/dist_ts/proxies/smart-proxy/tls-manager.d.ts +3 -3
- package/dist_ts/proxies/smart-proxy/tls-manager.js +12 -12
- package/package.json +8 -17
- package/readme.hints.md +0 -897
- package/readme.md +960 -54
- package/readme.plan.md +301 -562
- package/ts/proxies/smart-proxy/connection-manager.ts +23 -21
- package/ts/proxies/smart-proxy/http-proxy-bridge.ts +9 -8
- package/ts/proxies/smart-proxy/metrics-collector.ts +277 -189
- package/ts/proxies/smart-proxy/models/interfaces.ts +7 -0
- package/ts/proxies/smart-proxy/models/metrics-types.ts +93 -41
- package/ts/proxies/smart-proxy/nftables-manager.ts +5 -5
- package/ts/proxies/smart-proxy/port-manager.ts +6 -14
- package/ts/proxies/smart-proxy/route-connection-handler.ts +136 -136
- package/ts/proxies/smart-proxy/security-manager.ts +8 -8
- package/ts/proxies/smart-proxy/smart-proxy.ts +26 -35
- package/ts/proxies/smart-proxy/throughput-tracker.ts +144 -0
- package/ts/proxies/smart-proxy/timeout-manager.ts +16 -15
- package/ts/proxies/smart-proxy/tls-manager.ts +11 -11
- package/readme.connections.md +0 -724
- package/readme.delete.md +0 -187
- package/readme.memory-leaks-fixed.md +0 -45
- package/readme.metrics.md +0 -591
- package/readme.monitoring.md +0 -202
- package/readme.proxy-chain-summary.md +0 -112
- package/readme.proxy-protocol-example.md +0 -462
- package/readme.proxy-protocol.md +0 -415
- package/readme.routing.md +0 -341
- package/readme.websocket-keepalive-config.md +0 -140
- package/readme.websocket-keepalive-fix.md +0 -63
package/readme.md
CHANGED
|
@@ -665,6 +665,661 @@ redirect: {
|
|
|
665
665
|
}
|
|
666
666
|
```
|
|
667
667
|
|
|
668
|
+
## Forwarding Modes Guide
|
|
669
|
+
|
|
670
|
+
This section provides a comprehensive reference for all forwarding modes available in SmartProxy, helping you choose the right configuration for your use case.
|
|
671
|
+
|
|
672
|
+
### Visual Overview
|
|
673
|
+
|
|
674
|
+
```mermaid
|
|
675
|
+
graph TD
|
|
676
|
+
A[Incoming Traffic] --> B{Action Type?}
|
|
677
|
+
|
|
678
|
+
B -->|forward| C{TLS Mode?}
|
|
679
|
+
B -->|socket-handler| D[Custom Handler]
|
|
680
|
+
|
|
681
|
+
C -->|terminate| E[Decrypt TLS]
|
|
682
|
+
C -->|passthrough| F[Forward Encrypted]
|
|
683
|
+
C -->|terminate-and-reencrypt| G[Decrypt & Re-encrypt]
|
|
684
|
+
C -->|none/HTTP| H[Forward HTTP]
|
|
685
|
+
|
|
686
|
+
E --> I{Engine?}
|
|
687
|
+
F --> I
|
|
688
|
+
G --> I
|
|
689
|
+
H --> I
|
|
690
|
+
|
|
691
|
+
I -->|node| J[Node.js Processing]
|
|
692
|
+
I -->|nftables| K[Kernel NAT]
|
|
693
|
+
|
|
694
|
+
J --> L[Backend]
|
|
695
|
+
K --> L
|
|
696
|
+
D --> M[Custom Logic]
|
|
697
|
+
|
|
698
|
+
style B fill:#f9f,stroke:#333,stroke-width:2px
|
|
699
|
+
style C fill:#bbf,stroke:#333,stroke-width:2px
|
|
700
|
+
style I fill:#bfb,stroke:#333,stroke-width:2px
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
### Overview
|
|
704
|
+
|
|
705
|
+
SmartProxy offers flexible traffic forwarding through combinations of:
|
|
706
|
+
- **Action Types**: How to handle matched traffic
|
|
707
|
+
- **TLS Modes**: How to handle HTTPS/TLS connections
|
|
708
|
+
- **Forwarding Engines**: Where packet processing occurs
|
|
709
|
+
|
|
710
|
+
### Quick Reference
|
|
711
|
+
|
|
712
|
+
#### Modern Route-Based Configuration
|
|
713
|
+
|
|
714
|
+
| Use Case | Action Type | TLS Mode | Engine | Performance | Security |
|
|
715
|
+
|----------|------------|----------|---------|-------------|----------|
|
|
716
|
+
| HTTP web server | `forward` | N/A | `node` | Good | Basic |
|
|
717
|
+
| HTTPS web server (inspect traffic) | `forward` | `terminate` | `node` | Good | Full inspection |
|
|
718
|
+
| HTTPS passthrough (no inspection) | `forward` | `passthrough` | `node` | Better | End-to-end encryption |
|
|
719
|
+
| HTTPS gateway (re-encrypt to backend) | `forward` | `terminate-and-reencrypt` | `node` | Moderate | Full control |
|
|
720
|
+
| High-performance TCP forwarding | `forward` | `passthrough` | `nftables` | Excellent | Basic |
|
|
721
|
+
| Custom protocol handling | `socket-handler` | N/A | `node` | Varies | Custom |
|
|
722
|
+
|
|
723
|
+
#### Legacy Forwarding Types (Deprecated)
|
|
724
|
+
|
|
725
|
+
| Legacy Type | Modern Equivalent |
|
|
726
|
+
|------------|------------------|
|
|
727
|
+
| `http-only` | `action.type: 'forward'` with port 80 |
|
|
728
|
+
| `https-passthrough` | `action.type: 'forward'` + `tls.mode: 'passthrough'` |
|
|
729
|
+
| `https-terminate-to-http` | `action.type: 'forward'` + `tls.mode: 'terminate'` |
|
|
730
|
+
| `https-terminate-to-https` | `action.type: 'forward'` + `tls.mode: 'terminate-and-reencrypt'` |
|
|
731
|
+
|
|
732
|
+
### Forwarding Mode Categories
|
|
733
|
+
|
|
734
|
+
#### 1. Action Types
|
|
735
|
+
|
|
736
|
+
##### Forward Action
|
|
737
|
+
Routes traffic to a backend server. This is the most common action type.
|
|
738
|
+
|
|
739
|
+
```typescript
|
|
740
|
+
{
|
|
741
|
+
action: {
|
|
742
|
+
type: 'forward',
|
|
743
|
+
target: {
|
|
744
|
+
host: 'backend-server',
|
|
745
|
+
port: 8080
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
##### Socket Handler Action
|
|
752
|
+
Provides custom handling for any TCP protocol. Used for specialized protocols or custom logic.
|
|
753
|
+
|
|
754
|
+
```typescript
|
|
755
|
+
{
|
|
756
|
+
action: {
|
|
757
|
+
type: 'socket-handler',
|
|
758
|
+
socketHandler: async (socket, context) => {
|
|
759
|
+
// Custom protocol implementation
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
#### 2. TLS Modes (for Forward Action)
|
|
766
|
+
|
|
767
|
+
##### Passthrough Mode
|
|
768
|
+
- **What**: Forwards encrypted TLS traffic without decryption
|
|
769
|
+
- **When**: Backend handles its own TLS termination
|
|
770
|
+
- **Pros**: Maximum performance, true end-to-end encryption
|
|
771
|
+
- **Cons**: Cannot inspect or modify HTTPS traffic
|
|
772
|
+
|
|
773
|
+
```mermaid
|
|
774
|
+
graph LR
|
|
775
|
+
Client -->|TLS| SmartProxy
|
|
776
|
+
SmartProxy -->|TLS| Backend
|
|
777
|
+
style SmartProxy fill:#f9f,stroke:#333,stroke-width:2px
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
##### Terminate Mode
|
|
781
|
+
- **What**: Decrypts TLS, forwards as plain HTTP
|
|
782
|
+
- **When**: Backend doesn't support HTTPS or you need to inspect traffic
|
|
783
|
+
- **Pros**: Can modify headers, inspect content, add security headers
|
|
784
|
+
- **Cons**: Backend connection is unencrypted
|
|
785
|
+
|
|
786
|
+
```mermaid
|
|
787
|
+
graph LR
|
|
788
|
+
Client -->|TLS| SmartProxy
|
|
789
|
+
SmartProxy -->|HTTP| Backend
|
|
790
|
+
style SmartProxy fill:#f9f,stroke:#333,stroke-width:2px
|
|
791
|
+
```
|
|
792
|
+
|
|
793
|
+
##### Terminate-and-Reencrypt Mode
|
|
794
|
+
- **What**: Decrypts TLS, then creates new TLS connection to backend
|
|
795
|
+
- **When**: Need traffic inspection but backend requires HTTPS
|
|
796
|
+
- **Pros**: Full control while maintaining backend security
|
|
797
|
+
- **Cons**: Higher CPU usage, increased latency
|
|
798
|
+
|
|
799
|
+
```mermaid
|
|
800
|
+
graph LR
|
|
801
|
+
Client -->|TLS| SmartProxy
|
|
802
|
+
SmartProxy -->|New TLS| Backend
|
|
803
|
+
style SmartProxy fill:#f9f,stroke:#333,stroke-width:2px
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
#### 3. Forwarding Engines
|
|
807
|
+
|
|
808
|
+
##### Node.js Engine (Default)
|
|
809
|
+
- **Processing**: Application-level in Node.js event loop
|
|
810
|
+
- **Features**: Full protocol support, header manipulation, WebSockets
|
|
811
|
+
- **Performance**: Good for most use cases
|
|
812
|
+
- **Use when**: You need application-layer features
|
|
813
|
+
|
|
814
|
+
##### NFTables Engine
|
|
815
|
+
- **Processing**: Kernel-level packet forwarding
|
|
816
|
+
- **Features**: Basic NAT, minimal overhead
|
|
817
|
+
- **Performance**: Excellent, near wire-speed
|
|
818
|
+
- **Use when**: Maximum performance is critical
|
|
819
|
+
- **Requirements**: Linux, root permissions, NFTables installed
|
|
820
|
+
|
|
821
|
+
### Detailed Mode Explanations
|
|
822
|
+
|
|
823
|
+
#### HTTP Forwarding (Port 80)
|
|
824
|
+
|
|
825
|
+
Simple HTTP forwarding without encryption:
|
|
826
|
+
|
|
827
|
+
```typescript
|
|
828
|
+
{
|
|
829
|
+
match: { ports: 80, domains: 'example.com' },
|
|
830
|
+
action: {
|
|
831
|
+
type: 'forward',
|
|
832
|
+
target: { host: 'localhost', port: 8080 }
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
```
|
|
836
|
+
|
|
837
|
+
**Data Flow**: Client → SmartProxy (HTTP) → Backend (HTTP)
|
|
838
|
+
|
|
839
|
+
#### HTTPS with TLS Termination
|
|
840
|
+
|
|
841
|
+
Decrypt HTTPS and forward as HTTP:
|
|
842
|
+
|
|
843
|
+
```typescript
|
|
844
|
+
{
|
|
845
|
+
match: { ports: 443, domains: 'secure.example.com' },
|
|
846
|
+
action: {
|
|
847
|
+
type: 'forward',
|
|
848
|
+
target: { host: 'localhost', port: 8080 },
|
|
849
|
+
tls: {
|
|
850
|
+
mode: 'terminate',
|
|
851
|
+
certificate: 'auto' // Use Let's Encrypt
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
```
|
|
856
|
+
|
|
857
|
+
**Data Flow**: Client → SmartProxy (HTTPS decrypt) → Backend (HTTP)
|
|
858
|
+
|
|
859
|
+
#### HTTPS Passthrough
|
|
860
|
+
|
|
861
|
+
Forward encrypted traffic without decryption:
|
|
862
|
+
|
|
863
|
+
```typescript
|
|
864
|
+
{
|
|
865
|
+
match: { ports: 443, domains: 'legacy.example.com' },
|
|
866
|
+
action: {
|
|
867
|
+
type: 'forward',
|
|
868
|
+
target: { host: '192.168.1.10', port: 443 },
|
|
869
|
+
tls: {
|
|
870
|
+
mode: 'passthrough'
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
```
|
|
875
|
+
|
|
876
|
+
**Data Flow**: Client → SmartProxy (TLS forwarding) → Backend (Original TLS)
|
|
877
|
+
|
|
878
|
+
#### HTTPS Gateway (Terminate and Re-encrypt)
|
|
879
|
+
|
|
880
|
+
Decrypt, inspect, then re-encrypt to backend:
|
|
881
|
+
|
|
882
|
+
```typescript
|
|
883
|
+
{
|
|
884
|
+
match: { ports: 443, domains: 'api.example.com' },
|
|
885
|
+
action: {
|
|
886
|
+
type: 'forward',
|
|
887
|
+
target: { host: 'api-backend', port: 443 },
|
|
888
|
+
tls: {
|
|
889
|
+
mode: 'terminate-and-reencrypt',
|
|
890
|
+
certificate: 'auto'
|
|
891
|
+
},
|
|
892
|
+
advanced: {
|
|
893
|
+
headers: {
|
|
894
|
+
'X-Forwarded-Proto': 'https',
|
|
895
|
+
'X-Real-IP': '{clientIp}'
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
```
|
|
901
|
+
|
|
902
|
+
**Data Flow**: Client → SmartProxy (HTTPS decrypt) → SmartProxy (New HTTPS) → Backend
|
|
903
|
+
|
|
904
|
+
#### High-Performance NFTables Forwarding
|
|
905
|
+
|
|
906
|
+
Kernel-level forwarding for maximum performance:
|
|
907
|
+
|
|
908
|
+
```typescript
|
|
909
|
+
{
|
|
910
|
+
match: { ports: 443, domains: 'fast.example.com' },
|
|
911
|
+
action: {
|
|
912
|
+
type: 'forward',
|
|
913
|
+
target: { host: 'backend', port: 443 },
|
|
914
|
+
tls: { mode: 'passthrough' },
|
|
915
|
+
forwardingEngine: 'nftables',
|
|
916
|
+
nftables: {
|
|
917
|
+
preserveSourceIP: true,
|
|
918
|
+
maxRate: '10gbps'
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
```
|
|
923
|
+
|
|
924
|
+
**Data Flow**: Client → Kernel (NFTables NAT) → Backend
|
|
925
|
+
|
|
926
|
+
#### Custom Socket Handler
|
|
927
|
+
|
|
928
|
+
Handle custom protocols or implement specialized logic:
|
|
929
|
+
|
|
930
|
+
```typescript
|
|
931
|
+
{
|
|
932
|
+
match: { ports: 9000, domains: 'custom.example.com' },
|
|
933
|
+
action: {
|
|
934
|
+
type: 'socket-handler',
|
|
935
|
+
socketHandler: async (socket, context) => {
|
|
936
|
+
console.log(`Connection from ${context.clientIp}`);
|
|
937
|
+
|
|
938
|
+
socket.write('Welcome to custom protocol server\n');
|
|
939
|
+
|
|
940
|
+
socket.on('data', (data) => {
|
|
941
|
+
// Handle custom protocol
|
|
942
|
+
const response = processCustomProtocol(data);
|
|
943
|
+
socket.write(response);
|
|
944
|
+
});
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
```
|
|
949
|
+
|
|
950
|
+
### Decision Guide
|
|
951
|
+
|
|
952
|
+
#### Choose HTTP Forwarding When:
|
|
953
|
+
- Backend only supports HTTP
|
|
954
|
+
- Internal services not exposed to internet
|
|
955
|
+
- Development/testing environments
|
|
956
|
+
|
|
957
|
+
#### Choose HTTPS Termination When:
|
|
958
|
+
- Need to inspect/modify HTTP traffic
|
|
959
|
+
- Backend doesn't support HTTPS
|
|
960
|
+
- Want to add security headers
|
|
961
|
+
- Need to cache responses
|
|
962
|
+
|
|
963
|
+
#### Choose HTTPS Passthrough When:
|
|
964
|
+
- Backend manages its own certificates
|
|
965
|
+
- Need true end-to-end encryption
|
|
966
|
+
- Compliance requires no MITM
|
|
967
|
+
- WebSocket connections to backend
|
|
968
|
+
|
|
969
|
+
#### Choose HTTPS Terminate-and-Reencrypt When:
|
|
970
|
+
- Need traffic inspection AND backend requires HTTPS
|
|
971
|
+
- API gateway scenarios
|
|
972
|
+
- Adding authentication layers
|
|
973
|
+
- Different certificates for client/backend
|
|
974
|
+
|
|
975
|
+
#### Choose NFTables Engine When:
|
|
976
|
+
- Handling 1Gbps+ traffic
|
|
977
|
+
- Thousands of concurrent connections
|
|
978
|
+
- Minimal latency is critical
|
|
979
|
+
- Don't need application-layer features
|
|
980
|
+
|
|
981
|
+
#### Choose Socket Handler When:
|
|
982
|
+
- Implementing custom protocols
|
|
983
|
+
- Need fine-grained connection control
|
|
984
|
+
- Building protocol adapters
|
|
985
|
+
- Special authentication flows
|
|
986
|
+
|
|
987
|
+
### Complete Examples
|
|
988
|
+
|
|
989
|
+
#### Example 1: Complete Web Application
|
|
990
|
+
|
|
991
|
+
```typescript
|
|
992
|
+
const proxy = new SmartProxy({
|
|
993
|
+
routes: [
|
|
994
|
+
// HTTP to HTTPS redirect
|
|
995
|
+
{
|
|
996
|
+
match: { ports: 80, domains: ['example.com', 'www.example.com'] },
|
|
997
|
+
action: {
|
|
998
|
+
type: 'socket-handler',
|
|
999
|
+
socketHandler: SocketHandlers.httpRedirect('https://{domain}{path}')
|
|
1000
|
+
}
|
|
1001
|
+
},
|
|
1002
|
+
|
|
1003
|
+
// Main website with TLS termination
|
|
1004
|
+
{
|
|
1005
|
+
match: { ports: 443, domains: ['example.com', 'www.example.com'] },
|
|
1006
|
+
action: {
|
|
1007
|
+
type: 'forward',
|
|
1008
|
+
target: { host: 'web-backend', port: 3000 },
|
|
1009
|
+
tls: {
|
|
1010
|
+
mode: 'terminate',
|
|
1011
|
+
certificate: 'auto'
|
|
1012
|
+
},
|
|
1013
|
+
websocket: { enabled: true }
|
|
1014
|
+
}
|
|
1015
|
+
},
|
|
1016
|
+
|
|
1017
|
+
// API with re-encryption
|
|
1018
|
+
{
|
|
1019
|
+
match: { ports: 443, domains: 'api.example.com' },
|
|
1020
|
+
action: {
|
|
1021
|
+
type: 'forward',
|
|
1022
|
+
target: { host: 'api-backend', port: 443 },
|
|
1023
|
+
tls: {
|
|
1024
|
+
mode: 'terminate-and-reencrypt',
|
|
1025
|
+
certificate: 'auto'
|
|
1026
|
+
}
|
|
1027
|
+
},
|
|
1028
|
+
security: {
|
|
1029
|
+
ipAllowList: ['10.0.0.0/8'],
|
|
1030
|
+
rateLimit: {
|
|
1031
|
+
enabled: true,
|
|
1032
|
+
maxRequests: 100,
|
|
1033
|
+
window: 60
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
]
|
|
1038
|
+
});
|
|
1039
|
+
```
|
|
1040
|
+
|
|
1041
|
+
#### Example 2: Multi-Mode Proxy Setup
|
|
1042
|
+
|
|
1043
|
+
```typescript
|
|
1044
|
+
const proxy = new SmartProxy({
|
|
1045
|
+
routes: [
|
|
1046
|
+
// Legacy app with passthrough
|
|
1047
|
+
{
|
|
1048
|
+
match: { ports: 443, domains: 'legacy.example.com' },
|
|
1049
|
+
action: {
|
|
1050
|
+
type: 'forward',
|
|
1051
|
+
target: { host: 'legacy-server', port: 443 },
|
|
1052
|
+
tls: { mode: 'passthrough' }
|
|
1053
|
+
}
|
|
1054
|
+
},
|
|
1055
|
+
|
|
1056
|
+
// High-performance streaming with NFTables
|
|
1057
|
+
{
|
|
1058
|
+
match: { ports: 8080, domains: 'stream.example.com' },
|
|
1059
|
+
action: {
|
|
1060
|
+
type: 'forward',
|
|
1061
|
+
target: { host: 'stream-backend', port: 8080 },
|
|
1062
|
+
forwardingEngine: 'nftables',
|
|
1063
|
+
nftables: {
|
|
1064
|
+
protocol: 'tcp',
|
|
1065
|
+
preserveSourceIP: true
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
},
|
|
1069
|
+
|
|
1070
|
+
// Custom protocol handler
|
|
1071
|
+
{
|
|
1072
|
+
match: { ports: 9999 },
|
|
1073
|
+
action: {
|
|
1074
|
+
type: 'socket-handler',
|
|
1075
|
+
socketHandler: SocketHandlers.proxy('custom-backend', 9999)
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
]
|
|
1079
|
+
});
|
|
1080
|
+
```
|
|
1081
|
+
|
|
1082
|
+
### Performance Considerations
|
|
1083
|
+
|
|
1084
|
+
#### Node.js Engine Performance
|
|
1085
|
+
|
|
1086
|
+
| Metric | Typical Performance |
|
|
1087
|
+
|--------|-------------------|
|
|
1088
|
+
| Throughput | 1-10 Gbps |
|
|
1089
|
+
| Connections | 10,000-50,000 concurrent |
|
|
1090
|
+
| Latency | 1-5ms added |
|
|
1091
|
+
| CPU Usage | Moderate |
|
|
1092
|
+
|
|
1093
|
+
**Best for**: Most web applications, APIs, sites needing inspection
|
|
1094
|
+
|
|
1095
|
+
#### NFTables Engine Performance
|
|
1096
|
+
|
|
1097
|
+
| Metric | Typical Performance |
|
|
1098
|
+
|--------|-------------------|
|
|
1099
|
+
| Throughput | 10-100 Gbps |
|
|
1100
|
+
| Connections | 100,000+ concurrent |
|
|
1101
|
+
| Latency | <0.1ms added |
|
|
1102
|
+
| CPU Usage | Minimal |
|
|
1103
|
+
|
|
1104
|
+
**Best for**: High-traffic services, streaming, gaming, TCP forwarding
|
|
1105
|
+
|
|
1106
|
+
#### Performance Tips
|
|
1107
|
+
|
|
1108
|
+
1. **Use passthrough mode** when you don't need inspection
|
|
1109
|
+
2. **Enable NFTables** for high-traffic services
|
|
1110
|
+
3. **Terminate TLS only when necessary** - it adds CPU overhead
|
|
1111
|
+
4. **Use connection pooling** for terminate-and-reencrypt mode
|
|
1112
|
+
5. **Enable HTTP/2** for better multiplexing
|
|
1113
|
+
|
|
1114
|
+
### Security Implications
|
|
1115
|
+
|
|
1116
|
+
#### TLS Termination Security
|
|
1117
|
+
|
|
1118
|
+
**Pros:**
|
|
1119
|
+
- Inspect traffic for threats
|
|
1120
|
+
- Add security headers
|
|
1121
|
+
- Implement WAF rules
|
|
1122
|
+
- Log requests for audit
|
|
1123
|
+
|
|
1124
|
+
**Cons:**
|
|
1125
|
+
- Proxy has access to decrypted data
|
|
1126
|
+
- Requires secure certificate storage
|
|
1127
|
+
- Potential compliance issues
|
|
1128
|
+
|
|
1129
|
+
**Best Practices:**
|
|
1130
|
+
- Use auto-renewal with Let's Encrypt
|
|
1131
|
+
- Store certificates securely
|
|
1132
|
+
- Implement proper access controls
|
|
1133
|
+
- Use strong TLS configurations
|
|
1134
|
+
|
|
1135
|
+
#### Passthrough Security
|
|
1136
|
+
|
|
1137
|
+
**Pros:**
|
|
1138
|
+
- True end-to-end encryption
|
|
1139
|
+
- No MITM concerns
|
|
1140
|
+
- Backend controls security
|
|
1141
|
+
|
|
1142
|
+
**Cons:**
|
|
1143
|
+
- Cannot inspect traffic
|
|
1144
|
+
- Cannot add security headers
|
|
1145
|
+
- Limited DDoS protection
|
|
1146
|
+
|
|
1147
|
+
#### Socket Handler Security
|
|
1148
|
+
|
|
1149
|
+
**Risks:**
|
|
1150
|
+
- Custom code may have vulnerabilities
|
|
1151
|
+
- Resource exhaustion possible
|
|
1152
|
+
- Authentication bypass risks
|
|
1153
|
+
|
|
1154
|
+
**Mitigations:**
|
|
1155
|
+
```typescript
|
|
1156
|
+
{
|
|
1157
|
+
action: {
|
|
1158
|
+
type: 'socket-handler',
|
|
1159
|
+
socketHandler: async (socket, context) => {
|
|
1160
|
+
// Always validate and sanitize input
|
|
1161
|
+
socket.on('data', (data) => {
|
|
1162
|
+
if (data.length > MAX_SIZE) {
|
|
1163
|
+
socket.destroy();
|
|
1164
|
+
return;
|
|
1165
|
+
}
|
|
1166
|
+
// Process safely...
|
|
1167
|
+
});
|
|
1168
|
+
|
|
1169
|
+
// Set timeouts
|
|
1170
|
+
socket.setTimeout(30000);
|
|
1171
|
+
|
|
1172
|
+
// Rate limit connections
|
|
1173
|
+
if (connectionsFromIP(context.clientIp) > 10) {
|
|
1174
|
+
socket.destroy();
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
```
|
|
1180
|
+
|
|
1181
|
+
### Migration from Legacy Types
|
|
1182
|
+
|
|
1183
|
+
#### From `http-only`
|
|
1184
|
+
|
|
1185
|
+
**Old:**
|
|
1186
|
+
```typescript
|
|
1187
|
+
{
|
|
1188
|
+
type: 'http-only',
|
|
1189
|
+
target: { host: 'localhost', port: 8080 }
|
|
1190
|
+
}
|
|
1191
|
+
```
|
|
1192
|
+
|
|
1193
|
+
**New:**
|
|
1194
|
+
```typescript
|
|
1195
|
+
{
|
|
1196
|
+
match: { ports: 80, domains: 'example.com' },
|
|
1197
|
+
action: {
|
|
1198
|
+
type: 'forward',
|
|
1199
|
+
target: { host: 'localhost', port: 8080 }
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
```
|
|
1203
|
+
|
|
1204
|
+
#### From `https-passthrough`
|
|
1205
|
+
|
|
1206
|
+
**Old:**
|
|
1207
|
+
```typescript
|
|
1208
|
+
{
|
|
1209
|
+
type: 'https-passthrough',
|
|
1210
|
+
target: { host: 'backend', port: 443 }
|
|
1211
|
+
}
|
|
1212
|
+
```
|
|
1213
|
+
|
|
1214
|
+
**New:**
|
|
1215
|
+
```typescript
|
|
1216
|
+
{
|
|
1217
|
+
match: { ports: 443, domains: 'example.com' },
|
|
1218
|
+
action: {
|
|
1219
|
+
type: 'forward',
|
|
1220
|
+
target: { host: 'backend', port: 443 },
|
|
1221
|
+
tls: { mode: 'passthrough' }
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
```
|
|
1225
|
+
|
|
1226
|
+
#### From `https-terminate-to-http`
|
|
1227
|
+
|
|
1228
|
+
**Old:**
|
|
1229
|
+
```typescript
|
|
1230
|
+
{
|
|
1231
|
+
type: 'https-terminate-to-http',
|
|
1232
|
+
target: { host: 'localhost', port: 8080 },
|
|
1233
|
+
ssl: { /* certs */ }
|
|
1234
|
+
}
|
|
1235
|
+
```
|
|
1236
|
+
|
|
1237
|
+
**New:**
|
|
1238
|
+
```typescript
|
|
1239
|
+
{
|
|
1240
|
+
match: { ports: 443, domains: 'example.com' },
|
|
1241
|
+
action: {
|
|
1242
|
+
type: 'forward',
|
|
1243
|
+
target: { host: 'localhost', port: 8080 },
|
|
1244
|
+
tls: {
|
|
1245
|
+
mode: 'terminate',
|
|
1246
|
+
certificate: 'auto' // or provide cert/key
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
```
|
|
1251
|
+
|
|
1252
|
+
#### From `https-terminate-to-https`
|
|
1253
|
+
|
|
1254
|
+
**Old:**
|
|
1255
|
+
```typescript
|
|
1256
|
+
{
|
|
1257
|
+
type: 'https-terminate-to-https',
|
|
1258
|
+
target: { host: 'backend', port: 443 },
|
|
1259
|
+
ssl: { /* certs */ }
|
|
1260
|
+
}
|
|
1261
|
+
```
|
|
1262
|
+
|
|
1263
|
+
**New:**
|
|
1264
|
+
```typescript
|
|
1265
|
+
{
|
|
1266
|
+
match: { ports: 443, domains: 'example.com' },
|
|
1267
|
+
action: {
|
|
1268
|
+
type: 'forward',
|
|
1269
|
+
target: { host: 'backend', port: 443 },
|
|
1270
|
+
tls: {
|
|
1271
|
+
mode: 'terminate-and-reencrypt',
|
|
1272
|
+
certificate: 'auto'
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
```
|
|
1277
|
+
|
|
1278
|
+
### Helper Functions Quick Reference
|
|
1279
|
+
|
|
1280
|
+
SmartProxy provides helper functions for common configurations:
|
|
1281
|
+
|
|
1282
|
+
```typescript
|
|
1283
|
+
// HTTP forwarding
|
|
1284
|
+
createHttpRoute('example.com', { host: 'localhost', port: 8080 })
|
|
1285
|
+
|
|
1286
|
+
// HTTPS with termination
|
|
1287
|
+
createHttpsTerminateRoute('secure.com', { host: 'localhost', port: 8080 }, {
|
|
1288
|
+
certificate: 'auto'
|
|
1289
|
+
})
|
|
1290
|
+
|
|
1291
|
+
// HTTPS passthrough
|
|
1292
|
+
createHttpsPassthroughRoute('legacy.com', { host: 'backend', port: 443 })
|
|
1293
|
+
|
|
1294
|
+
// Complete HTTPS setup (includes HTTP redirect)
|
|
1295
|
+
...createCompleteHttpsServer('example.com', { host: 'localhost', port: 8080 }, {
|
|
1296
|
+
certificate: 'auto'
|
|
1297
|
+
})
|
|
1298
|
+
|
|
1299
|
+
// NFTables high-performance
|
|
1300
|
+
createNfTablesRoute('fast.com', { host: 'backend', port: 8080 }, {
|
|
1301
|
+
ports: 80,
|
|
1302
|
+
preserveSourceIP: true
|
|
1303
|
+
})
|
|
1304
|
+
|
|
1305
|
+
// Custom socket handler
|
|
1306
|
+
createSocketHandlerRoute('custom.com', 9000, async (socket, context) => {
|
|
1307
|
+
// Handler implementation
|
|
1308
|
+
})
|
|
1309
|
+
```
|
|
1310
|
+
|
|
1311
|
+
### Summary
|
|
1312
|
+
|
|
1313
|
+
SmartProxy's forwarding modes provide flexibility for any proxy scenario:
|
|
1314
|
+
|
|
1315
|
+
- **Simple HTTP/HTTPS forwarding** for most web applications
|
|
1316
|
+
- **TLS passthrough** for end-to-end encryption
|
|
1317
|
+
- **TLS termination** for traffic inspection and modification
|
|
1318
|
+
- **NFTables** for extreme performance requirements
|
|
1319
|
+
- **Socket handlers** for custom protocols
|
|
1320
|
+
|
|
1321
|
+
Choose based on your security requirements, performance needs, and whether you need to inspect or modify traffic. The modern route-based configuration provides a consistent interface regardless of the forwarding mode you choose.
|
|
1322
|
+
|
|
668
1323
|
### Route Metadata and Prioritization
|
|
669
1324
|
|
|
670
1325
|
You can add metadata to routes to help with organization and control matching priority:
|
|
@@ -921,122 +1576,316 @@ Available helper functions:
|
|
|
921
1576
|
|
|
922
1577
|
## Metrics and Monitoring
|
|
923
1578
|
|
|
924
|
-
SmartProxy includes a comprehensive metrics collection system that provides real-time insights into proxy performance, connection statistics, and throughput data.
|
|
1579
|
+
SmartProxy includes a comprehensive metrics collection system that provides real-time insights into proxy performance, connection statistics, and throughput data. The metrics system uses a clean, grouped API design for intuitive access to different metric categories.
|
|
925
1580
|
|
|
926
|
-
###
|
|
1581
|
+
### Enabling Metrics
|
|
927
1582
|
|
|
928
1583
|
```typescript
|
|
929
|
-
const proxy = new SmartProxy({
|
|
1584
|
+
const proxy = new SmartProxy({
|
|
1585
|
+
// Enable metrics collection
|
|
1586
|
+
metrics: {
|
|
1587
|
+
enabled: true,
|
|
1588
|
+
sampleIntervalMs: 1000, // Sample throughput every second
|
|
1589
|
+
retentionSeconds: 3600 // Keep 1 hour of history
|
|
1590
|
+
},
|
|
1591
|
+
routes: [/* your routes */]
|
|
1592
|
+
});
|
|
1593
|
+
|
|
930
1594
|
await proxy.start();
|
|
1595
|
+
```
|
|
931
1596
|
|
|
932
|
-
|
|
933
|
-
const stats = proxy.getStats();
|
|
1597
|
+
### Getting Metrics
|
|
934
1598
|
|
|
935
|
-
|
|
936
|
-
|
|
1599
|
+
```typescript
|
|
1600
|
+
// Access metrics through the getMetrics() method
|
|
1601
|
+
const metrics = proxy.getMetrics();
|
|
937
1602
|
|
|
938
|
-
//
|
|
939
|
-
|
|
1603
|
+
// The metrics object provides grouped methods for different categories
|
|
1604
|
+
```
|
|
940
1605
|
|
|
941
|
-
|
|
942
|
-
console.log(`Current RPS: ${stats.getRequestsPerSecond()}`);
|
|
1606
|
+
### Connection Metrics
|
|
943
1607
|
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
1608
|
+
Monitor active connections, total connections, and connection distribution:
|
|
1609
|
+
|
|
1610
|
+
```typescript
|
|
1611
|
+
// Get current active connections
|
|
1612
|
+
console.log(`Active connections: ${metrics.connections.active()}`);
|
|
1613
|
+
|
|
1614
|
+
// Get total connections since start
|
|
1615
|
+
console.log(`Total connections: ${metrics.connections.total()}`);
|
|
948
1616
|
|
|
949
1617
|
// Get connections by route
|
|
950
|
-
const routeConnections =
|
|
1618
|
+
const routeConnections = metrics.connections.byRoute();
|
|
951
1619
|
for (const [route, count] of routeConnections) {
|
|
952
1620
|
console.log(`Route ${route}: ${count} connections`);
|
|
953
1621
|
}
|
|
954
1622
|
|
|
955
1623
|
// Get connections by IP address
|
|
956
|
-
const ipConnections =
|
|
1624
|
+
const ipConnections = metrics.connections.byIP();
|
|
957
1625
|
for (const [ip, count] of ipConnections) {
|
|
958
1626
|
console.log(`IP ${ip}: ${count} connections`);
|
|
959
1627
|
}
|
|
1628
|
+
|
|
1629
|
+
// Get top IPs by connection count
|
|
1630
|
+
const topIPs = metrics.connections.topIPs(10);
|
|
1631
|
+
topIPs.forEach(({ ip, count }) => {
|
|
1632
|
+
console.log(`${ip}: ${count} connections`);
|
|
1633
|
+
});
|
|
1634
|
+
```
|
|
1635
|
+
|
|
1636
|
+
### Throughput Metrics
|
|
1637
|
+
|
|
1638
|
+
Real-time and historical throughput data with customizable time windows:
|
|
1639
|
+
|
|
1640
|
+
```typescript
|
|
1641
|
+
// Get instant throughput (last 1 second)
|
|
1642
|
+
const instant = metrics.throughput.instant();
|
|
1643
|
+
console.log(`Current: ${instant.in} bytes/sec in, ${instant.out} bytes/sec out`);
|
|
1644
|
+
|
|
1645
|
+
// Get recent throughput (last 10 seconds average)
|
|
1646
|
+
const recent = metrics.throughput.recent();
|
|
1647
|
+
console.log(`Recent: ${recent.in} bytes/sec in, ${recent.out} bytes/sec out`);
|
|
1648
|
+
|
|
1649
|
+
// Get average throughput (last 60 seconds)
|
|
1650
|
+
const average = metrics.throughput.average();
|
|
1651
|
+
console.log(`Average: ${average.in} bytes/sec in, ${average.out} bytes/sec out`);
|
|
1652
|
+
|
|
1653
|
+
// Get custom time window (e.g., last 5 minutes)
|
|
1654
|
+
const custom = metrics.throughput.custom(300);
|
|
1655
|
+
console.log(`5-min avg: ${custom.in} bytes/sec in, ${custom.out} bytes/sec out`);
|
|
1656
|
+
|
|
1657
|
+
// Get throughput history for graphing
|
|
1658
|
+
const history = metrics.throughput.history(300); // Last 5 minutes
|
|
1659
|
+
history.forEach(point => {
|
|
1660
|
+
console.log(`${new Date(point.timestamp)}: ${point.in} in, ${point.out} out`);
|
|
1661
|
+
});
|
|
1662
|
+
|
|
1663
|
+
// Get throughput by route
|
|
1664
|
+
const routeThroughput = metrics.throughput.byRoute(60); // Last 60 seconds
|
|
1665
|
+
routeThroughput.forEach((stats, route) => {
|
|
1666
|
+
console.log(`Route ${route}: ${stats.in} in, ${stats.out} out bytes/sec`);
|
|
1667
|
+
});
|
|
1668
|
+
|
|
1669
|
+
// Get throughput by IP
|
|
1670
|
+
const ipThroughput = metrics.throughput.byIP(60);
|
|
1671
|
+
ipThroughput.forEach((stats, ip) => {
|
|
1672
|
+
console.log(`IP ${ip}: ${stats.in} in, ${stats.out} out bytes/sec`);
|
|
1673
|
+
});
|
|
1674
|
+
```
|
|
1675
|
+
|
|
1676
|
+
### Request Metrics
|
|
1677
|
+
|
|
1678
|
+
Track request rates:
|
|
1679
|
+
|
|
1680
|
+
```typescript
|
|
1681
|
+
// Get requests per second
|
|
1682
|
+
console.log(`RPS: ${metrics.requests.perSecond()}`);
|
|
1683
|
+
|
|
1684
|
+
// Get requests per minute
|
|
1685
|
+
console.log(`RPM: ${metrics.requests.perMinute()}`);
|
|
1686
|
+
|
|
1687
|
+
// Get total requests
|
|
1688
|
+
console.log(`Total requests: ${metrics.requests.total()}`);
|
|
1689
|
+
```
|
|
1690
|
+
|
|
1691
|
+
### Cumulative Totals
|
|
1692
|
+
|
|
1693
|
+
Track total bytes transferred and connections:
|
|
1694
|
+
|
|
1695
|
+
```typescript
|
|
1696
|
+
// Get total bytes
|
|
1697
|
+
console.log(`Total bytes in: ${metrics.totals.bytesIn()}`);
|
|
1698
|
+
console.log(`Total bytes out: ${metrics.totals.bytesOut()}`);
|
|
1699
|
+
console.log(`Total connections: ${metrics.totals.connections()}`);
|
|
960
1700
|
```
|
|
961
1701
|
|
|
962
|
-
###
|
|
1702
|
+
### Performance Percentiles
|
|
963
1703
|
|
|
964
|
-
|
|
1704
|
+
Get percentile statistics (when implemented):
|
|
965
1705
|
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
-
|
|
970
|
-
|
|
971
|
-
|
|
1706
|
+
```typescript
|
|
1707
|
+
// Connection duration percentiles
|
|
1708
|
+
const durations = metrics.percentiles.connectionDuration();
|
|
1709
|
+
console.log(`Connection durations - P50: ${durations.p50}ms, P95: ${durations.p95}ms, P99: ${durations.p99}ms`);
|
|
1710
|
+
|
|
1711
|
+
// Bytes transferred percentiles
|
|
1712
|
+
const bytes = metrics.percentiles.bytesTransferred();
|
|
1713
|
+
console.log(`Bytes in - P50: ${bytes.in.p50}, P95: ${bytes.in.p95}, P99: ${bytes.in.p99}`);
|
|
1714
|
+
console.log(`Bytes out - P50: ${bytes.out.p50}, P95: ${bytes.out.p95}, P99: ${bytes.out.p99}`);
|
|
1715
|
+
```
|
|
972
1716
|
|
|
973
|
-
### Monitoring Example
|
|
1717
|
+
### Complete Monitoring Example
|
|
974
1718
|
|
|
975
1719
|
```typescript
|
|
976
|
-
// Create a monitoring
|
|
1720
|
+
// Create a monitoring dashboard
|
|
977
1721
|
setInterval(() => {
|
|
978
|
-
const
|
|
1722
|
+
const metrics = proxy.getMetrics();
|
|
979
1723
|
|
|
980
1724
|
// Log key metrics
|
|
981
1725
|
console.log({
|
|
982
1726
|
timestamp: new Date().toISOString(),
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
1727
|
+
connections: {
|
|
1728
|
+
active: metrics.connections.active(),
|
|
1729
|
+
total: metrics.connections.total()
|
|
1730
|
+
},
|
|
1731
|
+
throughput: {
|
|
1732
|
+
instant: metrics.throughput.instant(),
|
|
1733
|
+
average: metrics.throughput.average()
|
|
1734
|
+
},
|
|
1735
|
+
requests: {
|
|
1736
|
+
rps: metrics.requests.perSecond(),
|
|
1737
|
+
total: metrics.requests.total()
|
|
1738
|
+
},
|
|
1739
|
+
totals: {
|
|
1740
|
+
bytesIn: metrics.totals.bytesIn(),
|
|
1741
|
+
bytesOut: metrics.totals.bytesOut()
|
|
1742
|
+
}
|
|
986
1743
|
});
|
|
987
1744
|
|
|
988
|
-
//
|
|
989
|
-
const
|
|
990
|
-
|
|
1745
|
+
// Alert on high connection counts
|
|
1746
|
+
const topIPs = metrics.connections.topIPs(5);
|
|
1747
|
+
topIPs.forEach(({ ip, count }) => {
|
|
991
1748
|
if (count > 100) {
|
|
992
1749
|
console.warn(`High connection count from ${ip}: ${count}`);
|
|
993
1750
|
}
|
|
1751
|
+
});
|
|
1752
|
+
|
|
1753
|
+
// Alert on high throughput
|
|
1754
|
+
const instant = metrics.throughput.instant();
|
|
1755
|
+
if (instant.in > 100_000_000) { // 100 MB/s
|
|
1756
|
+
console.warn(`High incoming throughput: ${instant.in} bytes/sec`);
|
|
994
1757
|
}
|
|
995
1758
|
}, 10000); // Every 10 seconds
|
|
996
1759
|
```
|
|
997
1760
|
|
|
998
1761
|
### Exporting Metrics
|
|
999
1762
|
|
|
1000
|
-
|
|
1763
|
+
Export metrics in various formats for external monitoring systems:
|
|
1001
1764
|
|
|
1002
1765
|
```typescript
|
|
1003
1766
|
// Export as JSON
|
|
1004
1767
|
app.get('/metrics.json', (req, res) => {
|
|
1005
|
-
const
|
|
1768
|
+
const metrics = proxy.getMetrics();
|
|
1006
1769
|
res.json({
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1770
|
+
connections: {
|
|
1771
|
+
active: metrics.connections.active(),
|
|
1772
|
+
total: metrics.connections.total(),
|
|
1773
|
+
byRoute: Object.fromEntries(metrics.connections.byRoute()),
|
|
1774
|
+
byIP: Object.fromEntries(metrics.connections.byIP())
|
|
1775
|
+
},
|
|
1776
|
+
throughput: {
|
|
1777
|
+
instant: metrics.throughput.instant(),
|
|
1778
|
+
recent: metrics.throughput.recent(),
|
|
1779
|
+
average: metrics.throughput.average()
|
|
1780
|
+
},
|
|
1781
|
+
requests: {
|
|
1782
|
+
perSecond: metrics.requests.perSecond(),
|
|
1783
|
+
perMinute: metrics.requests.perMinute(),
|
|
1784
|
+
total: metrics.requests.total()
|
|
1785
|
+
},
|
|
1786
|
+
totals: {
|
|
1787
|
+
bytesIn: metrics.totals.bytesIn(),
|
|
1788
|
+
bytesOut: metrics.totals.bytesOut(),
|
|
1789
|
+
connections: metrics.totals.connections()
|
|
1790
|
+
}
|
|
1013
1791
|
});
|
|
1014
1792
|
});
|
|
1015
1793
|
|
|
1016
1794
|
// Export as Prometheus format
|
|
1017
1795
|
app.get('/metrics', (req, res) => {
|
|
1018
|
-
const
|
|
1796
|
+
const metrics = proxy.getMetrics();
|
|
1797
|
+
const instant = metrics.throughput.instant();
|
|
1798
|
+
|
|
1019
1799
|
res.set('Content-Type', 'text/plain');
|
|
1020
1800
|
res.send(`
|
|
1021
|
-
# HELP
|
|
1022
|
-
# TYPE
|
|
1023
|
-
|
|
1801
|
+
# HELP smartproxy_connections_active Current active connections
|
|
1802
|
+
# TYPE smartproxy_connections_active gauge
|
|
1803
|
+
smartproxy_connections_active ${metrics.connections.active()}
|
|
1804
|
+
|
|
1805
|
+
# HELP smartproxy_connections_total Total connections since start
|
|
1806
|
+
# TYPE smartproxy_connections_total counter
|
|
1807
|
+
smartproxy_connections_total ${metrics.connections.total()}
|
|
1808
|
+
|
|
1809
|
+
# HELP smartproxy_throughput_bytes_per_second Current throughput in bytes per second
|
|
1810
|
+
# TYPE smartproxy_throughput_bytes_per_second gauge
|
|
1811
|
+
smartproxy_throughput_bytes_per_second{direction="in"} ${instant.in}
|
|
1812
|
+
smartproxy_throughput_bytes_per_second{direction="out"} ${instant.out}
|
|
1024
1813
|
|
|
1025
1814
|
# HELP smartproxy_requests_per_second Current requests per second
|
|
1026
1815
|
# TYPE smartproxy_requests_per_second gauge
|
|
1027
|
-
smartproxy_requests_per_second ${
|
|
1816
|
+
smartproxy_requests_per_second ${metrics.requests.perSecond()}
|
|
1028
1817
|
|
|
1029
|
-
# HELP
|
|
1030
|
-
# TYPE
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
# HELP smartproxy_bytes_out Total bytes sent
|
|
1034
|
-
# TYPE smartproxy_bytes_out counter
|
|
1035
|
-
smartproxy_bytes_out ${stats.getThroughput().bytesOut}
|
|
1818
|
+
# HELP smartproxy_bytes_total Total bytes transferred
|
|
1819
|
+
# TYPE smartproxy_bytes_total counter
|
|
1820
|
+
smartproxy_bytes_total{direction="in"} ${metrics.totals.bytesIn()}
|
|
1821
|
+
smartproxy_bytes_total{direction="out"} ${metrics.totals.bytesOut()}
|
|
1036
1822
|
`);
|
|
1037
1823
|
});
|
|
1038
1824
|
```
|
|
1039
1825
|
|
|
1826
|
+
### Metrics API Reference
|
|
1827
|
+
|
|
1828
|
+
The metrics API is organized into logical groups:
|
|
1829
|
+
|
|
1830
|
+
```typescript
|
|
1831
|
+
interface IMetrics {
|
|
1832
|
+
connections: {
|
|
1833
|
+
active(): number;
|
|
1834
|
+
total(): number;
|
|
1835
|
+
byRoute(): Map<string, number>;
|
|
1836
|
+
byIP(): Map<string, number>;
|
|
1837
|
+
topIPs(limit?: number): Array<{ ip: string; count: number }>;
|
|
1838
|
+
};
|
|
1839
|
+
|
|
1840
|
+
throughput: {
|
|
1841
|
+
instant(): IThroughputData; // Last 1 second
|
|
1842
|
+
recent(): IThroughputData; // Last 10 seconds
|
|
1843
|
+
average(): IThroughputData; // Last 60 seconds
|
|
1844
|
+
custom(seconds: number): IThroughputData;
|
|
1845
|
+
history(seconds: number): Array<IThroughputHistoryPoint>;
|
|
1846
|
+
byRoute(windowSeconds?: number): Map<string, IThroughputData>;
|
|
1847
|
+
byIP(windowSeconds?: number): Map<string, IThroughputData>;
|
|
1848
|
+
};
|
|
1849
|
+
|
|
1850
|
+
requests: {
|
|
1851
|
+
perSecond(): number;
|
|
1852
|
+
perMinute(): number;
|
|
1853
|
+
total(): number;
|
|
1854
|
+
};
|
|
1855
|
+
|
|
1856
|
+
totals: {
|
|
1857
|
+
bytesIn(): number;
|
|
1858
|
+
bytesOut(): number;
|
|
1859
|
+
connections(): number;
|
|
1860
|
+
};
|
|
1861
|
+
|
|
1862
|
+
percentiles: {
|
|
1863
|
+
connectionDuration(): { p50: number; p95: number; p99: number };
|
|
1864
|
+
bytesTransferred(): {
|
|
1865
|
+
in: { p50: number; p95: number; p99: number };
|
|
1866
|
+
out: { p50: number; p95: number; p99: number };
|
|
1867
|
+
};
|
|
1868
|
+
};
|
|
1869
|
+
}
|
|
1870
|
+
```
|
|
1871
|
+
|
|
1872
|
+
Where `IThroughputData` is:
|
|
1873
|
+
```typescript
|
|
1874
|
+
interface IThroughputData {
|
|
1875
|
+
in: number; // Bytes per second incoming
|
|
1876
|
+
out: number; // Bytes per second outgoing
|
|
1877
|
+
}
|
|
1878
|
+
```
|
|
1879
|
+
|
|
1880
|
+
And `IThroughputHistoryPoint` is:
|
|
1881
|
+
```typescript
|
|
1882
|
+
interface IThroughputHistoryPoint {
|
|
1883
|
+
timestamp: number; // Unix timestamp in milliseconds
|
|
1884
|
+
in: number; // Bytes per second at this point
|
|
1885
|
+
out: number; // Bytes per second at this point
|
|
1886
|
+
}
|
|
1887
|
+
```
|
|
1888
|
+
|
|
1040
1889
|
## Other Components
|
|
1041
1890
|
|
|
1042
1891
|
While SmartProxy provides a unified API for most needs, you can also use individual components:
|
|
@@ -1736,6 +2585,62 @@ createHttpToHttpsRedirect('old.example.com', 443)
|
|
|
1736
2585
|
}
|
|
1737
2586
|
```
|
|
1738
2587
|
|
|
2588
|
+
## WebSocket Keep-Alive Configuration
|
|
2589
|
+
|
|
2590
|
+
If your WebSocket connections are disconnecting every 30 seconds in SNI passthrough mode, here's how to configure keep-alive settings:
|
|
2591
|
+
|
|
2592
|
+
### Extended Keep-Alive Treatment (Recommended)
|
|
2593
|
+
|
|
2594
|
+
```typescript
|
|
2595
|
+
const proxy = new SmartProxy({
|
|
2596
|
+
// Extend timeout for keep-alive connections
|
|
2597
|
+
keepAliveTreatment: 'extended',
|
|
2598
|
+
keepAliveInactivityMultiplier: 10, // 10x the base timeout
|
|
2599
|
+
inactivityTimeout: 14400000, // 4 hours base (40 hours with multiplier)
|
|
2600
|
+
|
|
2601
|
+
routes: [
|
|
2602
|
+
{
|
|
2603
|
+
name: 'websocket-passthrough',
|
|
2604
|
+
match: {
|
|
2605
|
+
ports: 443,
|
|
2606
|
+
domains: ['ws.example.com', 'wss.example.com']
|
|
2607
|
+
},
|
|
2608
|
+
action: {
|
|
2609
|
+
type: 'forward',
|
|
2610
|
+
target: { host: 'backend', port: 443 },
|
|
2611
|
+
tls: { mode: 'passthrough' }
|
|
2612
|
+
}
|
|
2613
|
+
}
|
|
2614
|
+
]
|
|
2615
|
+
});
|
|
2616
|
+
```
|
|
2617
|
+
|
|
2618
|
+
### Immortal Connections (Never Timeout)
|
|
2619
|
+
|
|
2620
|
+
```typescript
|
|
2621
|
+
const proxy = new SmartProxy({
|
|
2622
|
+
// Never timeout keep-alive connections
|
|
2623
|
+
keepAliveTreatment: 'immortal',
|
|
2624
|
+
|
|
2625
|
+
routes: [
|
|
2626
|
+
// ... same as above
|
|
2627
|
+
]
|
|
2628
|
+
});
|
|
2629
|
+
```
|
|
2630
|
+
|
|
2631
|
+
### Understanding the Issue
|
|
2632
|
+
|
|
2633
|
+
In SNI passthrough mode:
|
|
2634
|
+
1. **WebSocket Heartbeat**: The HTTP proxy's WebSocket handler sends ping frames every 30 seconds
|
|
2635
|
+
2. **SNI Passthrough**: In passthrough mode, traffic is encrypted end-to-end
|
|
2636
|
+
3. **Can't Inject Pings**: The proxy can't inject ping frames into encrypted traffic
|
|
2637
|
+
4. **Connection Terminated**: After 30 seconds, connection is marked inactive and closed
|
|
2638
|
+
|
|
2639
|
+
The solution involves:
|
|
2640
|
+
- Longer grace periods for encrypted connections (5 minutes vs 30 seconds)
|
|
2641
|
+
- Relying on OS-level TCP keep-alive instead of application-level heartbeat
|
|
2642
|
+
- Different timeout strategies per route type
|
|
2643
|
+
|
|
1739
2644
|
## Configuration Options
|
|
1740
2645
|
|
|
1741
2646
|
### SmartProxy (IRoutedSmartProxyOptions)
|
|
@@ -1746,6 +2651,7 @@ createHttpToHttpsRedirect('old.example.com', 443)
|
|
|
1746
2651
|
- `httpProxyPort` (number, default 8443) - Port where HttpProxy listens for forwarded connections
|
|
1747
2652
|
- Connection timeouts: `initialDataTimeout`, `socketTimeout`, `inactivityTimeout`, etc.
|
|
1748
2653
|
- Socket opts: `noDelay`, `keepAlive`, `enableKeepAliveProbes`
|
|
2654
|
+
- Keep-alive configuration: `keepAliveTreatment` ('standard'|'extended'|'immortal'), `keepAliveInactivityMultiplier`
|
|
1749
2655
|
- `certProvisionFunction` (callback) - Custom certificate provisioning
|
|
1750
2656
|
|
|
1751
2657
|
#### SmartProxy Dynamic Port Management Methods
|