@serve.zone/dcrouter 13.18.0 → 13.19.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/dist_serve/bundle.js +6 -5
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.dcrouter.d.ts +2 -0
- package/dist_ts/classes.dcrouter.js +50 -39
- package/dist_ts/config/classes.route-config-manager.d.ts +13 -5
- package/dist_ts/config/classes.route-config-manager.js +76 -36
- package/dist_ts/db/documents/classes.route.doc.d.ts +2 -0
- package/dist_ts/db/documents/classes.route.doc.js +11 -2
- package/dist_ts/email/classes.email-domain.manager.js +9 -28
- package/dist_ts/email/email-dns-records.d.ts +14 -0
- package/dist_ts/email/email-dns-records.js +34 -0
- package/dist_ts/email/index.d.ts +1 -0
- package/dist_ts/email/index.js +2 -1
- package/dist_ts/opsserver/handlers/route-management.handler.js +5 -7
- package/dist_ts_interfaces/data/route-management.d.ts +2 -0
- package/dist_ts_migrations/index.js +25 -1
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/appstate.js +13 -4
- package/dist_ts_web/elements/network/ops-view-routes.d.ts +2 -0
- package/dist_ts_web/elements/network/ops-view-routes.js +44 -21
- package/package.json +2 -3
- package/readme.md +190 -1543
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.dcrouter.ts +61 -47
- package/ts/config/classes.route-config-manager.ts +97 -42
- package/ts/db/documents/classes.route.doc.ts +7 -0
- package/ts/email/classes.email-domain.manager.ts +8 -28
- package/ts/email/email-dns-records.ts +53 -0
- package/ts/email/index.ts +1 -0
- package/ts/opsserver/handlers/route-management.handler.ts +4 -6
- package/ts_apiclient/readme.md +69 -195
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/appstate.ts +16 -4
- package/ts_web/elements/network/ops-view-routes.ts +47 -29
- package/ts_web/readme.md +41 -242
package/readme.md
CHANGED
|
@@ -1,139 +1,44 @@
|
|
|
1
1
|
# @serve.zone/dcrouter
|
|
2
2
|
|
|
3
|
-

|
|
3
|
+

|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`dcrouter` is a TypeScript control plane for running a serious multi-protocol edge or datacenter gateway from one process. It orchestrates HTTP/HTTPS and TCP routing through SmartProxy, email through smartmta, authoritative DNS and DNS-over-HTTPS, RADIUS, remote ingress tunnels, VPN access control, a typed Ops API, and a web dashboard.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
It is built for operators who want one place to define routes, expose services, manage certificates, register domains and DNS providers, control VPN-only access, and inspect what is going on in production.
|
|
8
8
|
|
|
9
9
|
## Issue Reporting and Security
|
|
10
10
|
|
|
11
11
|
For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
|
|
12
12
|
|
|
13
|
-
##
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
- [API Reference](#api-reference)
|
|
33
|
-
- [Sub-Modules](#sub-modules)
|
|
34
|
-
- [Testing](#testing)
|
|
35
|
-
- [Docker / OCI Container Deployment](#docker--oci-container-deployment)
|
|
36
|
-
- [License and Legal Information](#license-and-legal-information)
|
|
37
|
-
|
|
38
|
-
## Features
|
|
39
|
-
|
|
40
|
-
### 🌐 Universal Traffic Router
|
|
41
|
-
- **HTTP/HTTPS routing** with domain matching, path-based forwarding, and automatic TLS
|
|
42
|
-
- **HTTP/3 (QUIC) enabled by default** — qualifying HTTPS routes automatically get QUIC/H3 support with zero configuration
|
|
43
|
-
- **TCP/SNI proxy** for any protocol with TLS termination or passthrough
|
|
44
|
-
- **DNS server** (Rust-powered via [SmartDNS](https://code.foss.global/push.rocks/smartdns)) with authoritative zones, dynamic record management, and DNS-over-HTTPS
|
|
45
|
-
- **Multi-protocol support** on the same infrastructure via [SmartProxy](https://code.foss.global/push.rocks/smartproxy)
|
|
46
|
-
|
|
47
|
-
### 📧 Complete Email Infrastructure (powered by [smartmta](https://code.foss.global/push.rocks/smartmta))
|
|
48
|
-
- **Multi-domain SMTP server** on standard ports (25, 587, 465)
|
|
49
|
-
- **Pattern-based email routing** with four action types: forward, process, deliver, reject
|
|
50
|
-
- **DKIM signing & verification**, SPF, DMARC authentication stack
|
|
51
|
-
- **Enterprise deliverability** with IP warmup schedules and sender reputation tracking
|
|
52
|
-
- **Bounce handling** with automatic suppression lists
|
|
53
|
-
- **Hierarchical rate limiting** — global, per-domain, per-sender
|
|
54
|
-
|
|
55
|
-
### 🔒 Enterprise Security
|
|
56
|
-
- **Automatic TLS certificates** via ACME (smartacme v9) with Cloudflare DNS-01 challenges
|
|
57
|
-
- **Smart certificate scheduling** — per-domain deduplication, controlled parallelism, and account rate limiting handled automatically
|
|
58
|
-
- **Per-domain exponential backoff** — failed provisioning attempts are tracked and backed off to avoid hammering ACME servers
|
|
59
|
-
- **IP reputation checking** with caching and configurable thresholds
|
|
60
|
-
- **Content scanning** for spam, viruses, and malicious attachments
|
|
61
|
-
- **Security event logging** with structured audit trails
|
|
62
|
-
|
|
63
|
-
### 📡 RADIUS Server
|
|
64
|
-
- **MAC Authentication Bypass (MAB)** for network device authentication
|
|
65
|
-
- **VLAN assignment** based on exact MAC, OUI prefix, or wildcard patterns
|
|
66
|
-
- **RADIUS accounting** for session tracking, traffic metering, and billing
|
|
67
|
-
- **Real-time management** via OpsServer API
|
|
68
|
-
|
|
69
|
-
### 🌍 Remote Ingress (powered by [remoteingress](https://code.foss.global/serve.zone/remoteingress))
|
|
70
|
-
- **Distributed edge networking** — accept traffic at remote edge nodes and tunnel it to the hub
|
|
71
|
-
- **Edge registration CRUD** with secret-based authentication
|
|
72
|
-
- **Auto-derived ports** — edges automatically pick up ports from routes tagged with `remoteIngress.enabled`
|
|
73
|
-
- **Connection tokens** — generate a single opaque base64url token containing hubHost, hubPort, edgeId, and secret for easy edge provisioning
|
|
74
|
-
- **Real-time status monitoring** — connected/disconnected state, public IP, active tunnels, heartbeat tracking
|
|
75
|
-
- **OpsServer dashboard** with enable/disable, edit, secret regeneration, token copy, and delete actions
|
|
76
|
-
|
|
77
|
-
### 🔐 VPN Access Control (powered by [smartvpn](https://code.foss.global/push.rocks/smartvpn))
|
|
78
|
-
- **WireGuard + native transports** — standard WireGuard clients (iOS, Android, macOS, Windows, Linux) plus custom WebSocket/QUIC tunnels
|
|
79
|
-
- **Route-level VPN gating** — mark any route with `vpn: { enabled: true }` to restrict access to VPN clients only, or `vpn: { enabled: true, mandatory: false }` to add VPN clients alongside existing access rules
|
|
80
|
-
- **Tag-based access control** — assign `serverDefinedClientTags` to clients and restrict routes with `allowedServerDefinedClientTags`
|
|
81
|
-
- **Constructor-defined clients** — pre-define VPN clients with tags in config for declarative, code-driven setup
|
|
82
|
-
- **Rootless operation** — uses userspace NAT (smoltcp) with no root required
|
|
83
|
-
- **Destination policy** — configurable `forceTarget`, `block`, or `allow` with allowList/blockList for granular traffic control
|
|
84
|
-
- **Client management** — create, enable, disable, rotate keys, export WireGuard/SmartVPN configs via OpsServer API and dashboard
|
|
85
|
-
- **IP-based enforcement** — VPN clients get IPs from a configurable subnet; SmartProxy enforces `ipAllowList` per route
|
|
86
|
-
- **PROXY protocol v2** — the NAT engine sends PP v2 on outbound connections to preserve VPN client identity
|
|
87
|
-
|
|
88
|
-
### ⚡ High Performance
|
|
89
|
-
- **Rust-powered proxy engine** via SmartProxy for maximum throughput
|
|
90
|
-
- **Rust-powered MTA engine** via smartmta (TypeScript + Rust hybrid) for reliable email delivery
|
|
91
|
-
- **Rust-powered DNS engine** via SmartDNS for high-performance UDP and DNS-over-HTTPS
|
|
92
|
-
- **Connection pooling** for outbound SMTP and backend services
|
|
93
|
-
- **Socket-handler mode** — direct socket passing eliminates internal port hops
|
|
94
|
-
- **Real-time metrics** via SmartMetrics (CPU, memory, connections, throughput)
|
|
95
|
-
|
|
96
|
-
### 💾 Unified Database
|
|
97
|
-
- **Two deployment modes**: embedded LocalSmartDb (zero-config) or external MongoDB
|
|
98
|
-
- **15 document classes** covering routes, certs, VPN, RADIUS, security profiles, network targets, and caches
|
|
99
|
-
- **Automatic TTL-based cleanup** for cached emails and IP reputation data
|
|
100
|
-
- **Reusable references** — security profiles and network targets that propagate changes to all referencing routes
|
|
101
|
-
|
|
102
|
-
### 🖥️ OpsServer Dashboard
|
|
103
|
-
- **Web-based management interface** with real-time monitoring
|
|
104
|
-
- **JWT authentication** with session persistence
|
|
105
|
-
- **Live views** for connections, email queues, DNS queries, RADIUS sessions, certificates, remote ingress edges, VPN clients, and security events
|
|
106
|
-
- **Domain-centric certificate overview** with backoff status and one-click reprovisioning
|
|
107
|
-
- **Remote ingress management** with connection token generation and one-click copy
|
|
108
|
-
- **Security profiles & network targets** — reusable security configurations and host:port targets with propagation to referencing routes
|
|
109
|
-
- **Global warning banners** when database is disabled (management features unavailable)
|
|
110
|
-
- **Read-only configuration display** for system overview
|
|
111
|
-
- **Smart tab visibility handling** — auto-pauses all polling, WebSocket connections, and chart updates when the browser tab is hidden, preventing resource waste and tab freezing
|
|
112
|
-
|
|
113
|
-
### 🔧 Programmatic API Client
|
|
114
|
-
- **Object-oriented API** — resource classes (`Route`, `Certificate`, `ApiToken`, `RemoteIngress`, `Email`) with instance methods
|
|
115
|
-
- **Builder pattern** — fluent `.setName().setMatch().save()` chains for creating routes, tokens, and edges
|
|
116
|
-
- **Auto-injected auth** — JWT identity and API tokens included automatically in every request
|
|
117
|
-
- **Dual auth modes** — login with credentials (JWT) or pass an API token for programmatic access
|
|
118
|
-
- **Full coverage** — wraps every OpsServer endpoint with typed request/response pairs
|
|
13
|
+
## Why dcrouter
|
|
14
|
+
|
|
15
|
+
- 🌐 Run HTTP/HTTPS, TCP/SNI, email, DNS, RADIUS, VPN, and remote ingress from one orchestrated service.
|
|
16
|
+
- 🔐 Keep certificates, routes, tokens, domains, and reusable route references in one management plane.
|
|
17
|
+
- 🧠 Use system-managed routes for config-, email-, and DNS-derived traffic, plus API-managed routes for dynamic additions.
|
|
18
|
+
- 📊 Get an Ops UI and TypedRequest API for monitoring, automation, and day-2 operations.
|
|
19
|
+
- ⚡ Lean on Rust-backed data planes where it matters: proxying, DNS, email delivery, remote ingress, and VPN.
|
|
20
|
+
|
|
21
|
+
## What It Covers
|
|
22
|
+
|
|
23
|
+
| Area | What dcrouter does |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| HTTP / HTTPS / TCP | SmartProxy-based routing, TLS termination or passthrough, path/domain matching, optional HTTP/3 augmentation |
|
|
26
|
+
| Email | smartmta-based SMTP ingress and delivery, route-based email handling, DKIM-aware domain support |
|
|
27
|
+
| DNS | Authoritative DNS, DNS-over-HTTPS bootstrap routes, provider-backed and dcrouter-hosted domains and records |
|
|
28
|
+
| Certificates | ACME-aware certificate management with dashboard and API support |
|
|
29
|
+
| Access control | Source profiles, network targets, VPN-gated routes, API tokens, admin auth |
|
|
30
|
+
| Network edge | Remote ingress hub for edge nodes tunneling traffic into the router |
|
|
31
|
+
| Operations | Web dashboard, TypedRequest API, logs, metrics, health, route and token management |
|
|
119
32
|
|
|
120
33
|
## Installation
|
|
121
34
|
|
|
122
35
|
```bash
|
|
123
36
|
pnpm add @serve.zone/dcrouter
|
|
124
|
-
# or
|
|
125
|
-
npm install @serve.zone/dcrouter
|
|
126
37
|
```
|
|
127
38
|
|
|
128
|
-
### Prerequisites
|
|
129
|
-
|
|
130
|
-
- **Node.js 20+** with ES module support
|
|
131
|
-
- Valid domain with DNS control (for ACME certificate automation)
|
|
132
|
-
- Cloudflare API token (for DNS-01 challenges) — optional
|
|
133
|
-
|
|
134
39
|
## Quick Start
|
|
135
40
|
|
|
136
|
-
|
|
41
|
+
This is the smallest realistic setup: one HTTP route, embedded database enabled, and the Ops dashboard on port `3000`.
|
|
137
42
|
|
|
138
43
|
```typescript
|
|
139
44
|
import { DcRouter } from '@serve.zone/dcrouter';
|
|
@@ -142,1533 +47,275 @@ const router = new DcRouter({
|
|
|
142
47
|
smartProxyConfig: {
|
|
143
48
|
routes: [
|
|
144
49
|
{
|
|
145
|
-
name: '
|
|
146
|
-
match: {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
tls: { mode: 'terminate', certificate: 'auto' }
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
],
|
|
154
|
-
acme: {
|
|
155
|
-
email: 'admin@example.com',
|
|
156
|
-
enabled: true,
|
|
157
|
-
useProduction: true
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
await router.start();
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
### Basic Email Server
|
|
166
|
-
|
|
167
|
-
```typescript
|
|
168
|
-
import { DcRouter } from '@serve.zone/dcrouter';
|
|
169
|
-
|
|
170
|
-
const router = new DcRouter({
|
|
171
|
-
emailConfig: {
|
|
172
|
-
ports: [25, 587, 465],
|
|
173
|
-
hostname: 'mail.example.com',
|
|
174
|
-
domains: [
|
|
175
|
-
{
|
|
176
|
-
domain: 'example.com',
|
|
177
|
-
dnsMode: 'external-dns'
|
|
178
|
-
}
|
|
179
|
-
],
|
|
180
|
-
routes: [
|
|
181
|
-
{
|
|
182
|
-
name: 'process-all',
|
|
183
|
-
match: { recipients: '*@example.com' },
|
|
184
|
-
action: {
|
|
185
|
-
type: 'process',
|
|
186
|
-
process: { scan: true, dkim: true, queue: 'normal' }
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
]
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
await router.start();
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### Full Stack with Dashboard
|
|
197
|
-
|
|
198
|
-
```typescript
|
|
199
|
-
import { DcRouter } from '@serve.zone/dcrouter';
|
|
200
|
-
|
|
201
|
-
const router = new DcRouter({
|
|
202
|
-
// HTTP/HTTPS routing
|
|
203
|
-
smartProxyConfig: {
|
|
204
|
-
routes: [
|
|
205
|
-
{
|
|
206
|
-
name: 'website',
|
|
207
|
-
match: { domains: ['example.com'], ports: [443] },
|
|
50
|
+
name: 'app',
|
|
51
|
+
match: {
|
|
52
|
+
domains: ['app.example.com'],
|
|
53
|
+
ports: [80],
|
|
54
|
+
},
|
|
208
55
|
action: {
|
|
209
56
|
type: 'forward',
|
|
210
|
-
targets: [{ host: '
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
}
|
|
214
|
-
],
|
|
215
|
-
acme: { email: 'ssl@example.com', enabled: true, useProduction: true }
|
|
216
|
-
},
|
|
217
|
-
|
|
218
|
-
// Email system (powered by smartmta)
|
|
219
|
-
emailConfig: {
|
|
220
|
-
ports: [25, 587, 465],
|
|
221
|
-
hostname: 'mail.example.com',
|
|
222
|
-
domains: [{ domain: 'example.com', dnsMode: 'external-dns' }],
|
|
223
|
-
routes: [
|
|
224
|
-
{
|
|
225
|
-
name: 'inbound-mail',
|
|
226
|
-
match: { recipients: '*@example.com' },
|
|
227
|
-
action: { type: 'process', process: { scan: true, dkim: true, queue: 'normal' } }
|
|
228
|
-
}
|
|
229
|
-
]
|
|
230
|
-
},
|
|
231
|
-
|
|
232
|
-
// Authoritative DNS
|
|
233
|
-
dnsNsDomains: ['ns1.example.com', 'ns2.example.com'],
|
|
234
|
-
dnsScopes: ['example.com'],
|
|
235
|
-
publicIp: '203.0.113.1',
|
|
236
|
-
dnsRecords: [
|
|
237
|
-
{ name: 'example.com', type: 'A', value: '203.0.113.1' },
|
|
238
|
-
{ name: 'www.example.com', type: 'CNAME', value: 'example.com' }
|
|
239
|
-
],
|
|
240
|
-
|
|
241
|
-
// RADIUS authentication
|
|
242
|
-
radiusConfig: {
|
|
243
|
-
authPort: 1812,
|
|
244
|
-
acctPort: 1813,
|
|
245
|
-
clients: [
|
|
246
|
-
{ name: 'switch-1', ipRange: '192.168.1.0/24', secret: 'radius-secret', enabled: true }
|
|
57
|
+
targets: [{ host: '127.0.0.1', port: 3001 }],
|
|
58
|
+
},
|
|
59
|
+
},
|
|
247
60
|
],
|
|
248
|
-
vlanAssignment: {
|
|
249
|
-
defaultVlan: 100,
|
|
250
|
-
allowUnknownMacs: true,
|
|
251
|
-
mappings: [
|
|
252
|
-
{ mac: 'aa:bb:cc:dd:ee:ff', vlan: 10, enabled: true },
|
|
253
|
-
{ mac: 'aa:bb:cc', vlan: 20, enabled: true } // OUI prefix
|
|
254
|
-
]
|
|
255
|
-
},
|
|
256
|
-
accounting: { enabled: true, retentionDays: 30 }
|
|
257
61
|
},
|
|
258
|
-
|
|
259
|
-
// Remote Ingress — edge nodes tunnel traffic to this hub
|
|
260
|
-
remoteIngressConfig: {
|
|
62
|
+
dbConfig: {
|
|
261
63
|
enabled: true,
|
|
262
|
-
tunnelPort: 8443,
|
|
263
|
-
hubDomain: 'hub.example.com',
|
|
264
64
|
},
|
|
265
|
-
|
|
266
|
-
// VPN — restrict sensitive routes to VPN clients
|
|
267
|
-
vpnConfig: {
|
|
268
|
-
enabled: true,
|
|
269
|
-
serverEndpoint: 'vpn.example.com',
|
|
270
|
-
clients: [
|
|
271
|
-
{ clientId: 'dev-laptop', serverDefinedClientTags: ['engineering'] },
|
|
272
|
-
],
|
|
273
|
-
},
|
|
274
|
-
|
|
275
|
-
// Unified database (embedded LocalSmartDb or external MongoDB)
|
|
276
|
-
dbConfig: { enabled: true },
|
|
277
|
-
|
|
278
|
-
// TLS & ACME
|
|
279
|
-
tls: { contactEmail: 'admin@example.com' },
|
|
280
|
-
dnsChallenge: { cloudflareApiKey: process.env.CLOUDFLARE_API_KEY }
|
|
65
|
+
opsServerPort: 3000,
|
|
281
66
|
});
|
|
282
67
|
|
|
283
68
|
await router.start();
|
|
284
|
-
// OpsServer dashboard available at http://localhost:3000
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
## Architecture
|
|
288
|
-
|
|
289
|
-
### System Overview
|
|
290
|
-
|
|
291
|
-
```mermaid
|
|
292
|
-
graph TB
|
|
293
|
-
subgraph "External Traffic"
|
|
294
|
-
HTTP[HTTP/HTTPS Clients]
|
|
295
|
-
SMTP[SMTP Clients]
|
|
296
|
-
TCP[TCP Clients]
|
|
297
|
-
DNS[DNS Queries]
|
|
298
|
-
RAD[RADIUS Clients]
|
|
299
|
-
EDGE[Edge Nodes]
|
|
300
|
-
VPN[VPN Clients]
|
|
301
|
-
end
|
|
302
|
-
|
|
303
|
-
subgraph "DcRouter Core"
|
|
304
|
-
DC[DcRouter Orchestrator]
|
|
305
|
-
SP[SmartProxy Engine<br/><i>Rust-powered</i>]
|
|
306
|
-
ES[smartmta Email Server<br/><i>TypeScript + Rust</i>]
|
|
307
|
-
DS[SmartDNS Server<br/><i>Rust-powered</i>]
|
|
308
|
-
RS[SmartRadius Server]
|
|
309
|
-
RI[RemoteIngress Hub<br/><i>Rust data plane</i>]
|
|
310
|
-
VS[SmartVPN Server<br/><i>Rust data plane</i>]
|
|
311
|
-
CM[Certificate Manager<br/><i>smartacme v9</i>]
|
|
312
|
-
OS[OpsServer Dashboard]
|
|
313
|
-
MM[Metrics Manager]
|
|
314
|
-
DB2[DcRouterDb<br/><i>smartdata + smartdb</i>]
|
|
315
|
-
end
|
|
316
|
-
|
|
317
|
-
subgraph "Backend Services"
|
|
318
|
-
WEB[Web Services]
|
|
319
|
-
MAIL[Mail Servers]
|
|
320
|
-
DB[Databases]
|
|
321
|
-
API[Internal APIs]
|
|
322
|
-
end
|
|
323
|
-
|
|
324
|
-
HTTP --> SP
|
|
325
|
-
TCP --> SP
|
|
326
|
-
SMTP --> ES
|
|
327
|
-
DNS --> DS
|
|
328
|
-
RAD --> RS
|
|
329
|
-
EDGE --> RI
|
|
330
|
-
VPN --> VS
|
|
331
|
-
|
|
332
|
-
DC --> SP
|
|
333
|
-
DC --> ES
|
|
334
|
-
DC --> DS
|
|
335
|
-
DC --> RS
|
|
336
|
-
DC --> RI
|
|
337
|
-
DC --> VS
|
|
338
|
-
DC --> CM
|
|
339
|
-
DC --> OS
|
|
340
|
-
DC --> MM
|
|
341
|
-
DC --> DB2
|
|
342
|
-
|
|
343
|
-
SP --> WEB
|
|
344
|
-
SP --> API
|
|
345
|
-
ES --> MAIL
|
|
346
|
-
ES --> DB
|
|
347
|
-
RI --> SP
|
|
348
|
-
|
|
349
|
-
CM -.-> SP
|
|
350
|
-
CM -.-> ES
|
|
351
|
-
```
|
|
352
|
-
|
|
353
|
-
### Core Components
|
|
354
|
-
|
|
355
|
-
| Component | Package | Description |
|
|
356
|
-
|-----------|---------|-------------|
|
|
357
|
-
| **DcRouter** | `@serve.zone/dcrouter` | Central orchestrator — starts, stops, and coordinates all services |
|
|
358
|
-
| **SmartProxy** | `@push.rocks/smartproxy` | High-performance HTTP/HTTPS and TCP/SNI proxy with route-based config (Rust engine) |
|
|
359
|
-
| **UnifiedEmailServer** | `@push.rocks/smartmta` | Full SMTP server with pattern-based routing, DKIM, queue management (TypeScript + Rust) |
|
|
360
|
-
| **DNS Server** | `@push.rocks/smartdns` | Authoritative DNS with dynamic records and DKIM TXT auto-generation (Rust engine) |
|
|
361
|
-
| **SmartAcme** | `@push.rocks/smartacme` | ACME certificate management with per-domain dedup, concurrency control, and rate limiting |
|
|
362
|
-
| **RADIUS Server** | `@push.rocks/smartradius` | Network authentication with MAB, VLAN assignment, and accounting |
|
|
363
|
-
| **RemoteIngress** | `@serve.zone/remoteingress` | Distributed edge tunneling with Rust data plane and TS management |
|
|
364
|
-
| **OpsServer** | `@api.global/typedserver` | Web dashboard + TypedRequest API for monitoring and management |
|
|
365
|
-
| **MetricsManager** | `@push.rocks/smartmetrics` | Real-time metrics collection (CPU, memory, email, DNS, security) |
|
|
366
|
-
| **DcRouterDb** | `@push.rocks/smartdata` + `@push.rocks/smartdb` | Unified database — embedded LocalSmartDb or external MongoDB for all persistence |
|
|
367
|
-
|
|
368
|
-
### How It Works
|
|
369
|
-
|
|
370
|
-
DcRouter acts purely as an **orchestrator** — it doesn't implement protocols itself. Instead, it wires together best-in-class packages for each protocol:
|
|
371
|
-
|
|
372
|
-
1. **On `start()`**: DcRouter initializes OpsServer (default port 3000, configurable via `opsServerPort`), then spins up SmartProxy, smartmta, SmartDNS, SmartRadius, RemoteIngress, and SmartVPN based on which configs are provided. Services start in dependency order via `ServiceManager`.
|
|
373
|
-
2. **During operation**: Each service handles its own protocol independently. SmartProxy uses a Rust-powered engine for maximum throughput. smartmta uses a hybrid TypeScript + Rust architecture for reliable email delivery. RemoteIngress runs a Rust data plane for edge tunnel networking. SmartVPN runs a Rust data plane for WireGuard and custom transports. SmartAcme v9 handles all certificate operations with built-in concurrency control and rate limiting.
|
|
374
|
-
3. **On `stop()`**: All services are gracefully shut down in parallel, including cleanup of HTTP agents and DNS clients.
|
|
375
|
-
|
|
376
|
-
### Rust-Powered Architecture
|
|
377
|
-
|
|
378
|
-
DcRouter itself is a pure TypeScript orchestrator, but several of its core sub-components ship with **compiled Rust binaries** for performance-critical paths. At runtime each package detects the platform, unpacks the correct binary, and communicates with TypeScript over IPC/FFI — so you get the ergonomics of TypeScript with the throughput of native code.
|
|
379
|
-
|
|
380
|
-
| Component | Rust Binary | What It Handles |
|
|
381
|
-
|-----------|-------------|-----------------|
|
|
382
|
-
| **SmartProxy** | `smartproxy-bin` | All TCP/TLS/HTTP proxy networking, NFTables integration, connection metrics |
|
|
383
|
-
| **smartmta** | `mailer-bin` | SMTP server + client, DKIM/SPF/DMARC, content scanning, IP reputation |
|
|
384
|
-
| **SmartDNS** | `smartdns-bin` | DNS server (UDP + DNS-over-HTTPS), DNSSEC, DNS client resolution |
|
|
385
|
-
| **RemoteIngress** | `remoteingress-bin` | Edge tunnel data plane, multiplexed streams, heartbeat management |
|
|
386
|
-
| **SmartVPN** | `smartvpn_daemon` | WireGuard (boringtun), Noise IK handshake, QUIC/WS transports, userspace NAT (smoltcp) |
|
|
387
|
-
| **SmartRadius** | — | Pure TypeScript (no Rust component) |
|
|
388
|
-
|
|
389
|
-
## Configuration Reference
|
|
390
|
-
|
|
391
|
-
### `IDcRouterOptions`
|
|
392
|
-
|
|
393
|
-
```typescript
|
|
394
|
-
interface IDcRouterOptions {
|
|
395
|
-
// ── Base ───────────────────────────────────────────────────────
|
|
396
|
-
/** Base directory for all dcrouter data. Defaults to ~/.serve.zone/dcrouter */
|
|
397
|
-
baseDir?: string;
|
|
398
|
-
|
|
399
|
-
// ── Traffic Routing ────────────────────────────────────────────
|
|
400
|
-
/** SmartProxy config for HTTP/HTTPS and TCP/SNI routing */
|
|
401
|
-
smartProxyConfig?: ISmartProxyOptions;
|
|
402
|
-
|
|
403
|
-
// ── Email ──────────────────────────────────────────────────────
|
|
404
|
-
/** Unified email server configuration (smartmta) */
|
|
405
|
-
emailConfig?: IUnifiedEmailServerOptions;
|
|
406
|
-
|
|
407
|
-
/** Custom email port mapping overrides */
|
|
408
|
-
emailPortConfig?: {
|
|
409
|
-
portMapping?: Record<number, number>;
|
|
410
|
-
portSettings?: Record<number, any>;
|
|
411
|
-
receivedEmailsPath?: string;
|
|
412
|
-
};
|
|
413
|
-
|
|
414
|
-
// ── DNS ────────────────────────────────────────────────────────
|
|
415
|
-
/** Nameserver domains — get A records automatically */
|
|
416
|
-
dnsNsDomains?: string[];
|
|
417
|
-
/** Domains this server is authoritative for */
|
|
418
|
-
dnsScopes?: string[];
|
|
419
|
-
/** Public IP for NS A records */
|
|
420
|
-
publicIp?: string;
|
|
421
|
-
/** Ingress proxy IPs (hides real server IP) */
|
|
422
|
-
proxyIps?: string[];
|
|
423
|
-
/** Custom DNS records */
|
|
424
|
-
dnsRecords?: Array<{
|
|
425
|
-
name: string;
|
|
426
|
-
type: 'A' | 'AAAA' | 'CNAME' | 'MX' | 'TXT' | 'NS' | 'SOA';
|
|
427
|
-
value: string;
|
|
428
|
-
ttl?: number;
|
|
429
|
-
useIngressProxy?: boolean;
|
|
430
|
-
}>;
|
|
431
|
-
|
|
432
|
-
// ── RADIUS ─────────────────────────────────────────────────────
|
|
433
|
-
/** RADIUS server for network authentication */
|
|
434
|
-
radiusConfig?: {
|
|
435
|
-
authPort?: number; // default: 1812
|
|
436
|
-
acctPort?: number; // default: 1813
|
|
437
|
-
clients: IRadiusClient[];
|
|
438
|
-
vlanAssignment?: IVlanManagerConfig;
|
|
439
|
-
accounting?: { enabled: boolean; retentionDays?: number };
|
|
440
|
-
};
|
|
441
|
-
|
|
442
|
-
// ── Remote Ingress ─────────────────────────────────────────────
|
|
443
|
-
/** Remote Ingress hub for edge tunnel connections */
|
|
444
|
-
remoteIngressConfig?: {
|
|
445
|
-
enabled?: boolean; // default: false
|
|
446
|
-
tunnelPort?: number; // default: 8443
|
|
447
|
-
hubDomain?: string; // External hostname for connection tokens
|
|
448
|
-
tls?: {
|
|
449
|
-
certPath?: string;
|
|
450
|
-
keyPath?: string;
|
|
451
|
-
};
|
|
452
|
-
};
|
|
453
|
-
|
|
454
|
-
// ── VPN ───────────────────────────────────────────────────────
|
|
455
|
-
/** VPN server for route-level access control */
|
|
456
|
-
vpnConfig?: {
|
|
457
|
-
enabled?: boolean; // default: false
|
|
458
|
-
subnet?: string; // default: '10.8.0.0/24'
|
|
459
|
-
wgListenPort?: number; // default: 51820
|
|
460
|
-
dns?: string[]; // DNS servers pushed to VPN clients
|
|
461
|
-
serverEndpoint?: string; // Hostname in generated client configs
|
|
462
|
-
clients?: Array<{ // Pre-defined VPN clients
|
|
463
|
-
clientId: string;
|
|
464
|
-
serverDefinedClientTags?: string[];
|
|
465
|
-
description?: string;
|
|
466
|
-
}>;
|
|
467
|
-
destinationPolicy?: { // Traffic routing policy
|
|
468
|
-
default: 'forceTarget' | 'block' | 'allow';
|
|
469
|
-
target?: string; // IP for forceTarget (default: '127.0.0.1')
|
|
470
|
-
allowList?: string[]; // Pass through directly
|
|
471
|
-
blockList?: string[]; // Always block (overrides allowList)
|
|
472
|
-
};
|
|
473
|
-
};
|
|
474
|
-
|
|
475
|
-
// ── HTTP/3 (QUIC) ────────────────────────────────────────────
|
|
476
|
-
/** HTTP/3 config — enabled by default on qualifying HTTPS routes */
|
|
477
|
-
http3?: {
|
|
478
|
-
enabled?: boolean; // default: true
|
|
479
|
-
quicSettings?: {
|
|
480
|
-
maxIdleTimeout?: number; // default: 30000ms
|
|
481
|
-
maxConcurrentBidiStreams?: number; // default: 100
|
|
482
|
-
maxConcurrentUniStreams?: number; // default: 100
|
|
483
|
-
initialCongestionWindow?: number;
|
|
484
|
-
};
|
|
485
|
-
altSvc?: {
|
|
486
|
-
port?: number; // default: listening port
|
|
487
|
-
maxAge?: number; // default: 86400s
|
|
488
|
-
};
|
|
489
|
-
udpSettings?: {
|
|
490
|
-
sessionTimeout?: number; // default: 60000ms
|
|
491
|
-
maxSessionsPerIP?: number; // default: 1000
|
|
492
|
-
maxDatagramSize?: number; // default: 65535
|
|
493
|
-
};
|
|
494
|
-
};
|
|
495
|
-
|
|
496
|
-
// ── OpsServer ────────────────────────────────────────────────
|
|
497
|
-
/** Port for the OpsServer web dashboard (default: 3000) */
|
|
498
|
-
opsServerPort?: number;
|
|
499
|
-
|
|
500
|
-
// ── TLS & Certificates ────────────────────────────────────────
|
|
501
|
-
tls?: {
|
|
502
|
-
contactEmail: string;
|
|
503
|
-
domain?: string;
|
|
504
|
-
certPath?: string;
|
|
505
|
-
keyPath?: string;
|
|
506
|
-
};
|
|
507
|
-
dnsChallenge?: { cloudflareApiKey?: string };
|
|
508
|
-
|
|
509
|
-
// ── Database ────────────────────────────────────────────────────
|
|
510
|
-
/** Unified database for all persistence (routes, certs, VPN, RADIUS, etc.) */
|
|
511
|
-
dbConfig?: {
|
|
512
|
-
enabled?: boolean; // default: true
|
|
513
|
-
mongoDbUrl?: string; // External MongoDB URL (omit for embedded LocalSmartDb)
|
|
514
|
-
storagePath?: string; // default: '~/.serve.zone/dcrouter/tsmdb'
|
|
515
|
-
dbName?: string; // default: 'dcrouter'
|
|
516
|
-
cleanupIntervalHours?: number; // default: 1
|
|
517
|
-
seedOnEmpty?: boolean; // Seed default profiles/targets if DB is empty
|
|
518
|
-
seedData?: object; // Custom seed data
|
|
519
|
-
};
|
|
520
|
-
}
|
|
521
|
-
```
|
|
522
|
-
|
|
523
|
-
## HTTP/HTTPS & TCP/SNI Routing
|
|
524
|
-
|
|
525
|
-
DcRouter uses [SmartProxy](https://code.foss.global/push.rocks/smartproxy) for all HTTP/HTTPS and TCP/SNI routing. Routes are pattern-matched by domain, port, or both.
|
|
526
|
-
|
|
527
|
-
### HTTPS with Auto-TLS
|
|
528
|
-
|
|
529
|
-
```typescript
|
|
530
|
-
{
|
|
531
|
-
name: 'api-gateway',
|
|
532
|
-
match: { domains: ['api.example.com'], ports: [443] },
|
|
533
|
-
action: {
|
|
534
|
-
type: 'forward',
|
|
535
|
-
targets: [{ host: '192.168.1.20', port: 8080 }],
|
|
536
|
-
tls: { mode: 'terminate', certificate: 'auto' }
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
```
|
|
540
|
-
|
|
541
|
-
### TLS Passthrough (SNI Routing)
|
|
542
|
-
|
|
543
|
-
```typescript
|
|
544
|
-
{
|
|
545
|
-
name: 'secure-backend',
|
|
546
|
-
match: { domains: ['secure.example.com'], ports: [8443] },
|
|
547
|
-
action: {
|
|
548
|
-
type: 'forward',
|
|
549
|
-
targets: [{ host: '192.168.1.40', port: 8443 }],
|
|
550
|
-
tls: { mode: 'passthrough' }
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
```
|
|
554
|
-
|
|
555
|
-
### TCP Port Range Forwarding
|
|
556
|
-
|
|
557
|
-
```typescript
|
|
558
|
-
{
|
|
559
|
-
name: 'database-cluster',
|
|
560
|
-
match: { ports: [{ from: 5432, to: 5439 }] },
|
|
561
|
-
action: {
|
|
562
|
-
type: 'forward',
|
|
563
|
-
targets: [{ host: '192.168.1.30', port: 'preserve' }],
|
|
564
|
-
security: { ipAllowList: ['192.168.1.0/24'] }
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
69
|
```
|
|
568
70
|
|
|
569
|
-
|
|
71
|
+
Once the router is running, you can:
|
|
570
72
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
action: { type: 'redirect', redirect: { to: 'https://{domain}{path}' } }
|
|
576
|
-
}
|
|
577
|
-
```
|
|
73
|
+
- open the Ops dashboard on `http://localhost:3000`
|
|
74
|
+
- inspect the route in the System Routes view
|
|
75
|
+
- add API-managed routes through the dashboard or API client
|
|
76
|
+
- enable DNS, email, VPN, remote ingress, or RADIUS by adding the corresponding config blocks
|
|
578
77
|
|
|
579
|
-
##
|
|
78
|
+
## Mental Model
|
|
580
79
|
|
|
581
|
-
|
|
80
|
+
`dcrouter` is not a toy reverse proxy with a few side features. It is an orchestrator that wires multiple specialized services into one management plane.
|
|
582
81
|
|
|
583
|
-
|
|
82
|
+
| Layer | Responsibility |
|
|
83
|
+
| --- | --- |
|
|
84
|
+
| `DcRouter` | Startup order, shutdown, service wiring, configuration assembly, route hydration |
|
|
85
|
+
| SmartProxy | HTTP/HTTPS, TCP/SNI, TLS, HTTP/3-capable route execution |
|
|
86
|
+
| smartmta | SMTP ingress, queueing, DKIM-aware email processing and delivery |
|
|
87
|
+
| SmartDNS | Authoritative DNS and DoH request handling |
|
|
88
|
+
| smartradius | Network authentication, VLAN assignment, accounting |
|
|
89
|
+
| remoteingress | Edge tunnel registrations and runtime forwarding into the hub |
|
|
90
|
+
| smartvpn | VPN server and client access mediation for protected routes |
|
|
91
|
+
| OpsServer + dashboard | Typed API and browser UI for operations |
|
|
92
|
+
| smartdata-backed DB | Persistent routes, tokens, domains, records, profiles, cert metadata, caches |
|
|
584
93
|
|
|
585
|
-
|
|
586
|
-
- `match.transport: 'all'` — listen on both TCP (HTTP/1.1 + HTTP/2) and UDP (QUIC/HTTP/3) on the same port
|
|
587
|
-
- `action.udp.quic` — QUIC configuration with `enableHttp3: true` and `altSvcMaxAge: 86400`
|
|
94
|
+
## Route Model
|
|
588
95
|
|
|
589
|
-
|
|
96
|
+
Routes fall into two ownership classes:
|
|
590
97
|
|
|
591
|
-
|
|
98
|
+
| Route kind | Origin | Ownership | What users can do |
|
|
99
|
+
| --- | --- | --- | --- |
|
|
100
|
+
| System routes | `config`, `email`, `dns` | Derived from config or runtime-managed subsystems | View and toggle only |
|
|
101
|
+
| API routes | `api` | Created through route-management API | Create, edit, delete, toggle |
|
|
592
102
|
|
|
593
|
-
|
|
594
|
-
- Port includes **443** (single number, array, or range)
|
|
595
|
-
- Action type is **`forward`** (not `socket-handler`)
|
|
596
|
-
- **TLS is enabled** (passthrough, terminate, or terminate-and-reencrypt)
|
|
597
|
-
- Route is **not** an email route (ports 25/587/465)
|
|
598
|
-
- Route doesn't already have `transport: 'all'` or existing `udp.quic` config
|
|
103
|
+
Important details:
|
|
599
104
|
|
|
600
|
-
|
|
105
|
+
- system routes are persisted with a stable `systemKey`
|
|
106
|
+
- config-, email-, and DNS-derived routes show up in the System Routes view
|
|
107
|
+
- DoH routes are persisted as system-route templates and get their live socket handlers attached at apply time
|
|
108
|
+
- system routes are managed by the system, not edited directly by operators
|
|
601
109
|
|
|
602
|
-
|
|
603
|
-
// HTTP/3 is ON by default — this route automatically gets QUIC/H3:
|
|
604
|
-
const router = new DcRouter({
|
|
605
|
-
smartProxyConfig: {
|
|
606
|
-
routes: [{
|
|
607
|
-
name: 'web-app',
|
|
608
|
-
match: { domains: ['example.com'], ports: [443] },
|
|
609
|
-
action: {
|
|
610
|
-
type: 'forward',
|
|
611
|
-
targets: [{ host: '192.168.1.10', port: 8080 }],
|
|
612
|
-
tls: { mode: 'terminate', certificate: 'auto' }
|
|
613
|
-
}
|
|
614
|
-
}]
|
|
615
|
-
}
|
|
616
|
-
});
|
|
617
|
-
```
|
|
110
|
+
## Core Features
|
|
618
111
|
|
|
619
|
-
###
|
|
112
|
+
### Traffic Routing
|
|
620
113
|
|
|
621
|
-
|
|
114
|
+
- Domain-, port-, and path-based SmartProxy routes
|
|
115
|
+
- HTTP/HTTPS reverse proxying and generic TCP/SNI forwarding
|
|
116
|
+
- Optional HTTP/3 augmentation for qualifying HTTPS routes
|
|
117
|
+
- Reusable source profiles and network targets for route composition
|
|
118
|
+
- Remote ingress aware routing for edge-delivered traffic
|
|
622
119
|
|
|
623
|
-
|
|
624
|
-
{
|
|
625
|
-
name: 'legacy-app',
|
|
626
|
-
match: { domains: ['legacy.example.com'], ports: [443] },
|
|
627
|
-
action: {
|
|
628
|
-
type: 'forward',
|
|
629
|
-
targets: [{ host: '192.168.1.50', port: 8080 }],
|
|
630
|
-
tls: { mode: 'terminate', certificate: 'auto' },
|
|
631
|
-
options: { http3: false } // ← This route stays TCP-only
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
```
|
|
120
|
+
### Email
|
|
635
121
|
|
|
636
|
-
|
|
122
|
+
- smartmta-based inbound email handling
|
|
123
|
+
- Route-based mail actions such as forward, process, deliver, reject
|
|
124
|
+
- DKIM-aware domain handling and DNS record generation support
|
|
125
|
+
- Email-domain management through the Ops API and UI
|
|
126
|
+
- Queue, resend, failure, and delivery inspection through the dashboard and API
|
|
637
127
|
|
|
638
|
-
|
|
128
|
+
### DNS
|
|
639
129
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
```
|
|
130
|
+
- Authoritative scopes via `dnsScopes`
|
|
131
|
+
- Bootstrap nameserver domains via `dnsNsDomains`
|
|
132
|
+
- DNS-over-HTTPS endpoints for `/dns-query` and `/resolve`
|
|
133
|
+
- Managed domains, managed records, and provider-backed DNS integrations
|
|
134
|
+
- Internal email DNS record generation for `internal-dns` email domains
|
|
646
135
|
|
|
647
|
-
###
|
|
136
|
+
### Certificates and ACME
|
|
648
137
|
|
|
649
|
-
|
|
138
|
+
- Certificate overview and operations through OpsServer
|
|
139
|
+
- Import, export, delete, and reprovision flows
|
|
140
|
+
- DB-backed ACME configuration management
|
|
141
|
+
- Integration with managed DNS for certificate provisioning flows
|
|
142
|
+
- Routes can declare `certificate: 'auto'`, but actual automated issuance depends on ACME being configured in the management plane
|
|
650
143
|
|
|
651
|
-
|
|
652
|
-
const router = new DcRouter({
|
|
653
|
-
http3: {
|
|
654
|
-
quicSettings: {
|
|
655
|
-
maxIdleTimeout: 60000, // 60s idle timeout
|
|
656
|
-
maxConcurrentBidiStreams: 200, // More parallel streams
|
|
657
|
-
maxConcurrentUniStreams: 50,
|
|
658
|
-
},
|
|
659
|
-
altSvc: {
|
|
660
|
-
maxAge: 3600, // 1 hour Alt-Svc cache
|
|
661
|
-
},
|
|
662
|
-
udpSettings: {
|
|
663
|
-
sessionTimeout: 120000, // 2 min UDP session timeout
|
|
664
|
-
maxSessionsPerIP: 500,
|
|
665
|
-
}
|
|
666
|
-
},
|
|
667
|
-
smartProxyConfig: { routes: [/* ... */] }
|
|
668
|
-
});
|
|
669
|
-
```
|
|
144
|
+
### VPN, RADIUS, and Remote Ingress
|
|
670
145
|
|
|
671
|
-
|
|
146
|
+
- VPN-gated routes with target-profile-based access matching
|
|
147
|
+
- WireGuard-oriented VPN management with dcrouter-side client lifecycle support
|
|
148
|
+
- RADIUS MAB, VLAN assignment, and accounting
|
|
149
|
+
- Remote ingress hub for edge nodes tunneling traffic into central routes
|
|
672
150
|
|
|
673
|
-
|
|
151
|
+
### Operations Plane
|
|
674
152
|
|
|
675
|
-
|
|
153
|
+
- Web dashboard with overview, network, routes, access, security, domains, certificates, logs, and email views
|
|
154
|
+
- TypedRequest API for automation and external control
|
|
155
|
+
- API tokens with scoped access
|
|
156
|
+
- Metrics, health, logs, and per-feature operational views
|
|
676
157
|
|
|
677
|
-
|
|
158
|
+
## Configuration Overview
|
|
678
159
|
|
|
679
|
-
|
|
160
|
+
The main entry point is `IDcRouterOptions`.
|
|
680
161
|
|
|
681
|
-
|
|
162
|
+
| Option | Purpose |
|
|
163
|
+
| --- | --- |
|
|
164
|
+
| `smartProxyConfig` | Main HTTP/HTTPS and TCP/SNI routing configuration |
|
|
165
|
+
| `emailConfig` | smartmta server config and email routes |
|
|
166
|
+
| `emailPortConfig` | External-to-internal email port mapping and email storage path tuning |
|
|
167
|
+
| `dnsNsDomains` | Nameserver hostnames used for NS bootstrap and DoH routes |
|
|
168
|
+
| `dnsScopes` | Authoritative DNS zones managed by dcrouter |
|
|
169
|
+
| `dnsRecords` | Static constructor-defined records |
|
|
170
|
+
| `publicIp` / `proxyIps` | DNS A-record exposure strategy |
|
|
171
|
+
| `dbConfig` | Embedded or external Mongo-backed persistence and seeding |
|
|
172
|
+
| `radiusConfig` | RADIUS authentication, VLAN, and accounting setup |
|
|
173
|
+
| `remoteIngressConfig` | Edge tunnel hub setup |
|
|
174
|
+
| `vpnConfig` | VPN server and client access configuration |
|
|
175
|
+
| `http3` | Global HTTP/3 behavior for qualifying routes |
|
|
176
|
+
| `opsServerPort` | Dashboard and TypedRequest API port |
|
|
682
177
|
|
|
683
|
-
|
|
684
|
-
Simple forwarding without local DNS management:
|
|
685
|
-
```typescript
|
|
686
|
-
{
|
|
687
|
-
domain: 'forwarded.com',
|
|
688
|
-
dnsMode: 'forward',
|
|
689
|
-
dns: { forward: { skipDnsValidation: true, targetDomain: 'mail.target.com' } }
|
|
690
|
-
}
|
|
691
|
-
```
|
|
178
|
+
## Example: Enabling DNS, Email, and VPN
|
|
692
179
|
|
|
693
|
-
#### Internal DNS Mode
|
|
694
|
-
Uses DcRouter's built-in DNS server (requires `dnsNsDomains` + `dnsScopes`):
|
|
695
180
|
```typescript
|
|
696
|
-
{
|
|
697
|
-
domain: 'mail.example.com',
|
|
698
|
-
dnsMode: 'internal-dns',
|
|
699
|
-
dns: { internal: { mxPriority: 10, ttl: 3600 } },
|
|
700
|
-
dkim: { selector: 'mail2024', keySize: 2048, rotateKeys: true, rotationInterval: 90 }
|
|
701
|
-
}
|
|
702
|
-
```
|
|
703
|
-
|
|
704
|
-
#### External DNS Mode
|
|
705
|
-
Uses existing DNS infrastructure with validation:
|
|
706
|
-
```typescript
|
|
707
|
-
{
|
|
708
|
-
domain: 'mail.external.com',
|
|
709
|
-
dnsMode: 'external-dns',
|
|
710
|
-
dns: { external: { requiredRecords: ['MX', 'SPF', 'DKIM', 'DMARC'] } },
|
|
711
|
-
rateLimits: {
|
|
712
|
-
inbound: { messagesPerMinute: 100, connectionsPerIp: 10 },
|
|
713
|
-
outbound: { messagesPerMinute: 200 }
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
```
|
|
717
|
-
|
|
718
|
-
### Email Route Actions
|
|
719
|
-
|
|
720
|
-
Routes define _behavior_ — what happens when an email matches:
|
|
721
|
-
|
|
722
|
-
#### Forward 📤
|
|
723
|
-
Routes emails to an external SMTP server:
|
|
724
|
-
```typescript
|
|
725
|
-
{
|
|
726
|
-
name: 'forward-to-internal',
|
|
727
|
-
match: { recipients: '*@company.com' },
|
|
728
|
-
action: {
|
|
729
|
-
type: 'forward',
|
|
730
|
-
forward: {
|
|
731
|
-
host: 'internal-mail.company.com',
|
|
732
|
-
port: 25,
|
|
733
|
-
auth: { user: 'relay-user', pass: 'relay-pass' },
|
|
734
|
-
addHeaders: { 'X-Forwarded-By': 'dcrouter' }
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
```
|
|
739
|
-
|
|
740
|
-
#### Process ⚙️
|
|
741
|
-
Full MTA processing with content scanning and delivery queues:
|
|
742
|
-
```typescript
|
|
743
|
-
{
|
|
744
|
-
name: 'process-notifications',
|
|
745
|
-
match: { recipients: '*@notifications.company.com' },
|
|
746
|
-
action: {
|
|
747
|
-
type: 'process',
|
|
748
|
-
process: { scan: true, dkim: true, queue: 'priority' }
|
|
749
|
-
}
|
|
750
|
-
}
|
|
751
|
-
```
|
|
752
|
-
|
|
753
|
-
#### Deliver 📥
|
|
754
|
-
Local mailbox delivery:
|
|
755
|
-
```typescript
|
|
756
|
-
{
|
|
757
|
-
name: 'deliver-local',
|
|
758
|
-
match: { recipients: '*@local.company.com' },
|
|
759
|
-
action: { type: 'deliver' }
|
|
760
|
-
}
|
|
761
|
-
```
|
|
762
|
-
|
|
763
|
-
#### Reject 🚫
|
|
764
|
-
Reject with custom SMTP response code:
|
|
765
|
-
```typescript
|
|
766
|
-
{
|
|
767
|
-
name: 'reject-spam-domain',
|
|
768
|
-
match: { senders: '*@spam-domain.com', sizeRange: { min: 1000000 } },
|
|
769
|
-
action: {
|
|
770
|
-
type: 'reject',
|
|
771
|
-
reject: { code: 550, message: 'Message rejected due to policy' }
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
```
|
|
775
|
-
|
|
776
|
-
### Route Matching
|
|
777
|
-
|
|
778
|
-
Routes support powerful matching criteria:
|
|
779
|
-
|
|
780
|
-
```typescript
|
|
781
|
-
// Recipient patterns
|
|
782
|
-
match: { recipients: '*@example.com' } // All addresses at domain
|
|
783
|
-
match: { recipients: 'admin@*' } // "admin" at any domain
|
|
784
|
-
match: { senders: ['*@trusted.com', '*@vip.com'] } // Multiple sender patterns
|
|
785
|
-
|
|
786
|
-
// IP-based matching (CIDR)
|
|
787
|
-
match: { clientIp: '192.168.0.0/16' }
|
|
788
|
-
match: { clientIp: ['10.0.0.0/8', '172.16.0.0/12'] }
|
|
789
|
-
|
|
790
|
-
// Authentication state
|
|
791
|
-
match: { authenticated: true }
|
|
792
|
-
|
|
793
|
-
// Header matching
|
|
794
|
-
match: { headers: { 'X-Priority': 'high', 'Subject': /urgent|emergency/i } }
|
|
795
|
-
|
|
796
|
-
// Size and content
|
|
797
|
-
match: { sizeRange: { min: 1000, max: 5000000 }, hasAttachments: true }
|
|
798
|
-
match: { subject: /invoice|receipt/i }
|
|
799
|
-
```
|
|
800
|
-
|
|
801
|
-
### Email Security Stack
|
|
802
|
-
|
|
803
|
-
- **DKIM** — Automatic key generation, signing, and rotation for all domains
|
|
804
|
-
- **SPF** — Sender Policy Framework verification on inbound mail
|
|
805
|
-
- **DMARC** — Domain-based Message Authentication verification
|
|
806
|
-
- **IP Reputation** — Real-time IP reputation checking with caching
|
|
807
|
-
- **Content Scanning** — Spam, virus, and attachment scanning
|
|
808
|
-
- **Rate Limiting** — Hierarchical limits (global → domain → sender)
|
|
809
|
-
- **Bounce Management** — Automatic bounce detection and suppression lists
|
|
810
|
-
|
|
811
|
-
### Email Deliverability
|
|
812
|
-
|
|
813
|
-
- **IP Warmup Manager** — Multi-stage warmup schedules for new IPs
|
|
814
|
-
- **Sender Reputation Monitor** — Per-domain reputation tracking and scoring
|
|
815
|
-
- **Connection Pooling** — Pooled outbound SMTP connections per destination
|
|
816
|
-
|
|
817
|
-
## DNS Server
|
|
818
|
-
|
|
819
|
-
DcRouter includes an authoritative DNS server built on [smartdns](https://code.foss.global/push.rocks/smartdns). It handles standard UDP DNS on port 53 and DNS-over-HTTPS via SmartProxy socket handler.
|
|
820
|
-
|
|
821
|
-
### Enabling DNS
|
|
822
|
-
|
|
823
|
-
DNS is activated when both `dnsNsDomains` and `dnsScopes` are configured:
|
|
824
|
-
|
|
825
|
-
```typescript
|
|
826
|
-
const router = new DcRouter({
|
|
827
|
-
dnsNsDomains: ['ns1.example.com', 'ns2.example.com'],
|
|
828
|
-
dnsScopes: ['example.com'],
|
|
829
|
-
publicIp: '203.0.113.1',
|
|
830
|
-
dnsRecords: [
|
|
831
|
-
{ name: 'example.com', type: 'A', value: '203.0.113.1' },
|
|
832
|
-
{ name: 'www.example.com', type: 'CNAME', value: 'example.com' },
|
|
833
|
-
{ name: 'example.com', type: 'MX', value: '10:mail.example.com' },
|
|
834
|
-
{ name: 'example.com', type: 'TXT', value: 'v=spf1 a mx ~all' }
|
|
835
|
-
]
|
|
836
|
-
});
|
|
837
|
-
```
|
|
838
|
-
|
|
839
|
-
### Automatic DNS Records
|
|
840
|
-
|
|
841
|
-
DcRouter auto-generates:
|
|
842
|
-
- **NS records** for all domains in `dnsScopes`
|
|
843
|
-
- **SOA records** for authoritative zones
|
|
844
|
-
- **A records** for nameserver domains (`dnsNsDomains`)
|
|
845
|
-
- **MX, SPF, DKIM, DMARC records** for email domains with `internal-dns` mode
|
|
846
|
-
- **ACME challenge records** for certificate provisioning
|
|
847
|
-
|
|
848
|
-
### Ingress Proxy Support
|
|
849
|
-
|
|
850
|
-
When `proxyIps` is configured, A records with `useIngressProxy: true` (default) will use the proxy IP instead of the real server IP — hiding your origin:
|
|
851
|
-
|
|
852
|
-
```typescript
|
|
853
|
-
{
|
|
854
|
-
proxyIps: ['198.51.100.1', '198.51.100.2'],
|
|
855
|
-
dnsRecords: [
|
|
856
|
-
{ name: 'example.com', type: 'A', value: '203.0.113.1' }, // Will resolve to 198.51.100.1
|
|
857
|
-
{ name: 'ns1.example.com', type: 'A', value: '203.0.113.1', useIngressProxy: false } // Stays real IP
|
|
858
|
-
]
|
|
859
|
-
}
|
|
860
|
-
```
|
|
861
|
-
|
|
862
|
-
## RADIUS Server
|
|
863
|
-
|
|
864
|
-
DcRouter includes a RADIUS server for network access control, built on [smartradius](https://code.foss.global/push.rocks/smartradius).
|
|
865
|
-
|
|
866
|
-
### Configuration
|
|
867
|
-
|
|
868
|
-
```typescript
|
|
869
|
-
const router = new DcRouter({
|
|
870
|
-
radiusConfig: {
|
|
871
|
-
authPort: 1812,
|
|
872
|
-
acctPort: 1813,
|
|
873
|
-
clients: [
|
|
874
|
-
{
|
|
875
|
-
name: 'core-switch',
|
|
876
|
-
ipRange: '192.168.1.0/24',
|
|
877
|
-
secret: 'shared-secret',
|
|
878
|
-
enabled: true
|
|
879
|
-
}
|
|
880
|
-
],
|
|
881
|
-
vlanAssignment: {
|
|
882
|
-
defaultVlan: 100,
|
|
883
|
-
allowUnknownMacs: true,
|
|
884
|
-
mappings: [
|
|
885
|
-
{ mac: 'aa:bb:cc:dd:ee:ff', vlan: 10, enabled: true }, // Exact MAC
|
|
886
|
-
{ mac: 'aa:bb:cc', vlan: 20, enabled: true }, // OUI prefix
|
|
887
|
-
]
|
|
888
|
-
},
|
|
889
|
-
accounting: {
|
|
890
|
-
enabled: true,
|
|
891
|
-
retentionDays: 30
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
});
|
|
895
|
-
```
|
|
896
|
-
|
|
897
|
-
### Components
|
|
898
|
-
|
|
899
|
-
| Component | Purpose |
|
|
900
|
-
|-----------|---------|
|
|
901
|
-
| **RadiusServer** | Main RADIUS server handling auth + accounting requests |
|
|
902
|
-
| **VlanManager** | MAC-to-VLAN mapping with exact, OUI, and wildcard patterns |
|
|
903
|
-
| **AccountingManager** | Session tracking, traffic metering, start/stop/interim updates |
|
|
904
|
-
|
|
905
|
-
### OpsServer API
|
|
906
|
-
|
|
907
|
-
RADIUS is fully manageable at runtime via the OpsServer API:
|
|
908
|
-
- Client management (add/remove/list NAS devices)
|
|
909
|
-
- VLAN mapping CRUD operations
|
|
910
|
-
- Session monitoring and forced disconnects
|
|
911
|
-
- Accounting summaries and statistics
|
|
912
|
-
|
|
913
|
-
## Remote Ingress
|
|
914
|
-
|
|
915
|
-
DcRouter can act as a **hub** for distributed edge nodes using [`@serve.zone/remoteingress`](https://code.foss.global/serve.zone/remoteingress). Edge nodes accept incoming traffic at remote locations and tunnel it back to the hub over a single multiplexed connection. This is ideal for scenarios where you need to accept traffic at multiple geographic locations but process it centrally.
|
|
916
|
-
|
|
917
|
-
### Enabling Remote Ingress
|
|
181
|
+
import { DcRouter } from '@serve.zone/dcrouter';
|
|
918
182
|
|
|
919
|
-
```typescript
|
|
920
183
|
const router = new DcRouter({
|
|
921
|
-
remoteIngressConfig: {
|
|
922
|
-
enabled: true,
|
|
923
|
-
tunnelPort: 8443,
|
|
924
|
-
hubDomain: 'hub.example.com', // Embedded in connection tokens
|
|
925
|
-
},
|
|
926
|
-
// Routes tagged with remoteIngress are auto-derived to edge listen ports
|
|
927
184
|
smartProxyConfig: {
|
|
928
185
|
routes: [
|
|
929
186
|
{
|
|
930
|
-
name: 'web-
|
|
931
|
-
match: {
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
targets: [{ host: '192.168.1.10', port: 8080 }],
|
|
935
|
-
tls: { mode: 'terminate', certificate: 'auto' }
|
|
187
|
+
name: 'web-app',
|
|
188
|
+
match: {
|
|
189
|
+
domains: ['app.example.com'],
|
|
190
|
+
ports: [443],
|
|
936
191
|
},
|
|
937
|
-
remoteIngress: { enabled: true } // Edges will listen on port 443
|
|
938
|
-
}
|
|
939
|
-
]
|
|
940
|
-
}
|
|
941
|
-
});
|
|
942
|
-
|
|
943
|
-
await router.start();
|
|
944
|
-
```
|
|
945
|
-
|
|
946
|
-
### Edge Registration
|
|
947
|
-
|
|
948
|
-
Edges are registered via the OpsServer API (or dashboard UI). Each edge gets a unique ID and secret:
|
|
949
|
-
|
|
950
|
-
```typescript
|
|
951
|
-
// Via TypedRequest API
|
|
952
|
-
const createReq = new TypedRequest<IReq_CreateRemoteIngress>(
|
|
953
|
-
'https://hub:3000/typedrequest', 'createRemoteIngress'
|
|
954
|
-
);
|
|
955
|
-
const { edge } = await createReq.fire({
|
|
956
|
-
identity,
|
|
957
|
-
name: 'edge-nyc-01',
|
|
958
|
-
autoDerivePorts: true,
|
|
959
|
-
tags: ['us-east'],
|
|
960
|
-
});
|
|
961
|
-
// edge.secret is returned only on creation — save it!
|
|
962
|
-
```
|
|
963
|
-
|
|
964
|
-
### Connection Tokens 🔑
|
|
965
|
-
|
|
966
|
-
Instead of configuring edges with four separate values (hubHost, hubPort, edgeId, secret), DcRouter can generate a single **connection token** — an opaque base64url string that encodes everything:
|
|
967
|
-
|
|
968
|
-
```typescript
|
|
969
|
-
// Via TypedRequest API
|
|
970
|
-
const tokenReq = new TypedRequest<IReq_GetRemoteIngressConnectionToken>(
|
|
971
|
-
'https://hub:3000/typedrequest', 'getRemoteIngressConnectionToken'
|
|
972
|
-
);
|
|
973
|
-
const { token } = await tokenReq.fire({ identity, edgeId: 'edge-uuid' });
|
|
974
|
-
// token = "eyJoIjoiaHViLmV4YW1wbGUuY29tIiwicCI6ODQ0MywiZSI6I..."
|
|
975
|
-
|
|
976
|
-
// On the edge side, just pass the token:
|
|
977
|
-
const edge = new RemoteIngressEdge({ token });
|
|
978
|
-
await edge.start();
|
|
979
|
-
```
|
|
980
|
-
|
|
981
|
-
The token is generated using `remoteingress.encodeConnectionToken()` and contains `{ hubHost, hubPort, edgeId, secret }`. The `hubHost` comes from `remoteIngressConfig.hubDomain` (or can be overridden per-request).
|
|
982
|
-
|
|
983
|
-
In the OpsServer dashboard, click **"Copy Token"** on any edge row to copy the connection token to your clipboard.
|
|
984
|
-
|
|
985
|
-
### Auto-Derived Ports
|
|
986
|
-
|
|
987
|
-
When routes have `remoteIngress: { enabled: true }`, edges with `autoDerivePorts: true` (default) automatically pick up those routes' ports. You can also use `edgeFilter` to restrict which edges get which ports:
|
|
988
|
-
|
|
989
|
-
```typescript
|
|
990
|
-
{
|
|
991
|
-
name: 'web-route',
|
|
992
|
-
match: { ports: [443] },
|
|
993
|
-
action: { /* ... */ },
|
|
994
|
-
remoteIngress: {
|
|
995
|
-
enabled: true,
|
|
996
|
-
edgeFilter: ['us-east', 'edge-uuid-123'] // Only edges with matching id or tags
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
```
|
|
1000
|
-
|
|
1001
|
-
### Dashboard Actions
|
|
1002
|
-
|
|
1003
|
-
The OpsServer Remote Ingress view provides:
|
|
1004
|
-
|
|
1005
|
-
| Action | Description |
|
|
1006
|
-
|--------|-------------|
|
|
1007
|
-
| **Create Edge Node** | Register a new edge with name, ports, tags |
|
|
1008
|
-
| **Enable / Disable** | Toggle an edge on or off |
|
|
1009
|
-
| **Edit** | Modify name, manual ports, auto-derive setting, tags |
|
|
1010
|
-
| **Regenerate Secret** | Issue a new secret (invalidates the old one) |
|
|
1011
|
-
| **Copy Token** | Generate and copy a base64url connection token to clipboard |
|
|
1012
|
-
| **Delete** | Remove the edge registration |
|
|
1013
|
-
|
|
1014
|
-
## VPN Access Control
|
|
1015
|
-
|
|
1016
|
-
DcRouter integrates [`@push.rocks/smartvpn`](https://code.foss.global/push.rocks/smartvpn) to provide VPN-based route access control. VPN clients connect via standard WireGuard or native WebSocket/QUIC transports, receive an IP from a configurable subnet, and can then access routes that are restricted to VPN-only traffic.
|
|
1017
|
-
|
|
1018
|
-
### How It Works
|
|
1019
|
-
|
|
1020
|
-
1. **SmartVPN daemon** runs inside dcrouter with a Rust data plane (WireGuard via `boringtun`, custom protocol via Noise IK)
|
|
1021
|
-
2. Clients connect and get assigned an IP from the VPN subnet (e.g. `10.8.0.0/24`)
|
|
1022
|
-
3. **Smart split tunnel** — generated WireGuard configs auto-include the VPN subnet plus DNS-resolved IPs of VPN-gated domains. Domains from routes with `vpn.enabled` are resolved at config generation time, so clients route only the necessary traffic through the tunnel
|
|
1023
|
-
4. Routes with `vpn: { enabled: true }` get `security.ipAllowList` dynamically injected (re-computed on every client change). With `mandatory: true` (default), the allowlist is replaced; with `mandatory: false`, VPN IPs are appended to existing rules
|
|
1024
|
-
5. When `allowedServerDefinedClientTags` is set, only matching client IPs are injected (not the whole subnet)
|
|
1025
|
-
6. SmartProxy enforces the allowlist — only authorized VPN clients can access protected routes
|
|
1026
|
-
7. All VPN traffic is forced through SmartProxy via userspace NAT with PROXY protocol v2 — no root required
|
|
1027
|
-
|
|
1028
|
-
### Destination Policy
|
|
1029
|
-
|
|
1030
|
-
By default, VPN client traffic is redirected to localhost (SmartProxy) via `forceTarget`. You can customize this with a destination policy:
|
|
1031
|
-
|
|
1032
|
-
```typescript
|
|
1033
|
-
// Default: all traffic → SmartProxy
|
|
1034
|
-
destinationPolicy: { default: 'forceTarget', target: '127.0.0.1' }
|
|
1035
|
-
|
|
1036
|
-
// Allow direct access to a backend subnet
|
|
1037
|
-
destinationPolicy: {
|
|
1038
|
-
default: 'forceTarget',
|
|
1039
|
-
target: '127.0.0.1',
|
|
1040
|
-
allowList: ['192.168.190.*'], // direct access to this subnet
|
|
1041
|
-
blockList: ['192.168.190.1'], // except the gateway
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
|
-
// Block everything except specific IPs
|
|
1045
|
-
destinationPolicy: {
|
|
1046
|
-
default: 'block',
|
|
1047
|
-
allowList: ['10.0.0.*', '192.168.1.*'],
|
|
1048
|
-
}
|
|
1049
|
-
```
|
|
1050
|
-
|
|
1051
|
-
### Configuration
|
|
1052
|
-
|
|
1053
|
-
```typescript
|
|
1054
|
-
const router = new DcRouter({
|
|
1055
|
-
vpnConfig: {
|
|
1056
|
-
enabled: true,
|
|
1057
|
-
subnet: '10.8.0.0/24', // VPN client IP pool (default)
|
|
1058
|
-
wgListenPort: 51820, // WireGuard UDP port (default)
|
|
1059
|
-
serverEndpoint: 'vpn.example.com', // Hostname in generated client configs
|
|
1060
|
-
dns: ['1.1.1.1', '8.8.8.8'], // DNS servers pushed to clients
|
|
1061
|
-
|
|
1062
|
-
// Pre-define VPN clients with server-defined tags
|
|
1063
|
-
clients: [
|
|
1064
|
-
{ clientId: 'alice-laptop', serverDefinedClientTags: ['engineering'], description: 'Dev laptop' },
|
|
1065
|
-
{ clientId: 'bob-phone', serverDefinedClientTags: ['engineering', 'mobile'] },
|
|
1066
|
-
{ clientId: 'carol-desktop', serverDefinedClientTags: ['finance'] },
|
|
1067
|
-
],
|
|
1068
|
-
|
|
1069
|
-
// Optional: customize destination policy (default: forceTarget → localhost)
|
|
1070
|
-
// destinationPolicy: { default: 'forceTarget', target: '127.0.0.1', allowList: ['192.168.1.*'] },
|
|
1071
|
-
},
|
|
1072
|
-
smartProxyConfig: {
|
|
1073
|
-
routes: [
|
|
1074
|
-
// 🔐 VPN-only: any VPN client can access
|
|
1075
|
-
{
|
|
1076
|
-
name: 'internal-app',
|
|
1077
|
-
match: { domains: ['internal.example.com'], ports: [443] },
|
|
1078
192
|
action: {
|
|
1079
193
|
type: 'forward',
|
|
1080
|
-
targets: [{ host: '
|
|
194
|
+
targets: [{ host: '127.0.0.1', port: 8080 }],
|
|
1081
195
|
tls: { mode: 'terminate', certificate: 'auto' },
|
|
1082
196
|
},
|
|
1083
|
-
vpn: { enabled: true },
|
|
1084
197
|
},
|
|
1085
|
-
|
|
198
|
+
],
|
|
199
|
+
},
|
|
200
|
+
emailConfig: {
|
|
201
|
+
hostname: 'mail.example.com',
|
|
202
|
+
ports: [25, 587, 465],
|
|
203
|
+
domains: [
|
|
1086
204
|
{
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
action: {
|
|
1090
|
-
type: 'forward',
|
|
1091
|
-
targets: [{ host: '192.168.1.51', port: 8080 }],
|
|
1092
|
-
tls: { mode: 'terminate', certificate: 'auto' },
|
|
1093
|
-
},
|
|
1094
|
-
vpn: { enabled: true, allowedServerDefinedClientTags: ['engineering'] },
|
|
1095
|
-
// → alice + bob can access, carol cannot
|
|
205
|
+
domain: 'example.com',
|
|
206
|
+
dnsMode: 'internal-dns',
|
|
1096
207
|
},
|
|
1097
|
-
|
|
208
|
+
],
|
|
209
|
+
routes: [
|
|
1098
210
|
{
|
|
1099
|
-
name: '
|
|
1100
|
-
match: {
|
|
211
|
+
name: 'inbound-mail',
|
|
212
|
+
match: { recipients: '*@example.com' },
|
|
1101
213
|
action: {
|
|
1102
214
|
type: 'forward',
|
|
1103
|
-
|
|
1104
|
-
tls: { mode: 'terminate', certificate: 'auto' },
|
|
215
|
+
forward: { host: 'mail-backend.example.com', port: 25 },
|
|
1105
216
|
},
|
|
1106
217
|
},
|
|
1107
218
|
],
|
|
1108
219
|
},
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
| Tag Type | Set By | Purpose |
|
|
1117
|
-
|----------|--------|---------|
|
|
1118
|
-
| `serverDefinedClientTags` | Admin (via config or API) | **Trusted** — used for route access control |
|
|
1119
|
-
| `clientDefinedClientTags` | Connecting client | **Informational** — displayed in dashboard, never used for security |
|
|
1120
|
-
|
|
1121
|
-
Routes with `allowedServerDefinedClientTags` only permit VPN clients whose admin-assigned tags match. Clients cannot influence their own server-defined tags.
|
|
1122
|
-
|
|
1123
|
-
### Client Management via OpsServer
|
|
1124
|
-
|
|
1125
|
-
The OpsServer dashboard and API provide full VPN client lifecycle management:
|
|
1126
|
-
|
|
1127
|
-
- **Create client** — generates WireGuard keypairs, assigns IP, returns a ready-to-use `.conf` file
|
|
1128
|
-
- **QR code** — scan with the WireGuard mobile app (iOS/Android) for instant setup
|
|
1129
|
-
- **Enable / Disable** — toggle client access without deleting
|
|
1130
|
-
- **Rotate keys** — generate fresh keypairs (invalidates old ones)
|
|
1131
|
-
- **Export config** — download in WireGuard (`.conf`), SmartVPN (`.json`), or scan as QR code
|
|
1132
|
-
- **Telemetry** — per-client bytes sent/received, keepalives, rate limiting
|
|
1133
|
-
- **Delete** — remove a client and revoke access
|
|
1134
|
-
|
|
1135
|
-
Standard WireGuard clients on any platform (iOS, Android, macOS, Windows, Linux) can connect using the generated `.conf` file or by scanning the QR code — no custom VPN software needed.
|
|
1136
|
-
|
|
1137
|
-
## Certificate Management
|
|
1138
|
-
|
|
1139
|
-
DcRouter uses [`@push.rocks/smartacme`](https://code.foss.global/push.rocks/smartacme) v9 for ACME certificate provisioning. smartacme v9 brings significant improvements over previous versions:
|
|
1140
|
-
|
|
1141
|
-
### How It Works
|
|
1142
|
-
|
|
1143
|
-
When a `dnsChallenge` is configured (e.g. with a Cloudflare API key), DcRouter creates a SmartAcme instance that handles DNS-01 challenges for automatic certificate provisioning. SmartProxy calls the `certProvisionFunction` whenever a route needs a TLS certificate, and SmartAcme takes care of the rest.
|
|
1144
|
-
|
|
1145
|
-
```typescript
|
|
1146
|
-
const router = new DcRouter({
|
|
1147
|
-
smartProxyConfig: {
|
|
1148
|
-
routes: [
|
|
220
|
+
dnsNsDomains: ['ns1.example.com', 'ns2.example.com'],
|
|
221
|
+
dnsScopes: ['example.com'],
|
|
222
|
+
publicIp: '203.0.113.10',
|
|
223
|
+
vpnConfig: {
|
|
224
|
+
enabled: true,
|
|
225
|
+
serverEndpoint: 'vpn.example.com',
|
|
226
|
+
clients: [
|
|
1149
227
|
{
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
type: 'forward',
|
|
1154
|
-
targets: [{ host: '192.168.1.10', port: 8080 }],
|
|
1155
|
-
tls: { mode: 'terminate', certificate: 'auto' } // ← triggers ACME provisioning
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
228
|
+
clientId: 'ops-laptop',
|
|
229
|
+
description: 'Operations laptop',
|
|
230
|
+
},
|
|
1158
231
|
],
|
|
1159
|
-
acme: { email: 'admin@example.com', enabled: true, useProduction: true }
|
|
1160
232
|
},
|
|
1161
|
-
|
|
1162
|
-
|
|
233
|
+
dbConfig: {
|
|
234
|
+
enabled: true,
|
|
235
|
+
},
|
|
1163
236
|
});
|
|
1164
|
-
```
|
|
1165
|
-
|
|
1166
|
-
### smartacme v9 Features
|
|
1167
|
-
|
|
1168
|
-
| Feature | Description |
|
|
1169
|
-
|---------|-------------|
|
|
1170
|
-
| **Per-domain deduplication** | Concurrent requests for the same domain share a single ACME operation |
|
|
1171
|
-
| **Global concurrency cap** | Default 5 parallel ACME operations to prevent overload |
|
|
1172
|
-
| **Account rate limiting** | Sliding window (250 orders / 3 hours) to stay within ACME provider limits |
|
|
1173
|
-
| **Structured errors** | `AcmeError` with `isRetryable`, `isRateLimited`, `retryAfter` fields |
|
|
1174
|
-
| **Clean shutdown** | `stop()` properly destroys HTTP agents and DNS clients |
|
|
1175
|
-
|
|
1176
|
-
### Per-Domain Backoff
|
|
1177
|
-
|
|
1178
|
-
DcRouter's `CertProvisionScheduler` adds **per-domain exponential backoff** on top of smartacme's built-in protections. If a DNS-01 challenge fails for a domain:
|
|
1179
|
-
|
|
1180
|
-
1. The failure is recorded (persisted to storage)
|
|
1181
|
-
2. The domain enters backoff: `min(failures² × 1 hour, 24 hours)`
|
|
1182
|
-
3. Subsequent requests for that domain are rejected until the backoff expires
|
|
1183
|
-
4. On success, the backoff is cleared
|
|
1184
|
-
|
|
1185
|
-
This prevents hammering ACME servers for domains with persistent issues (e.g. missing DNS delegation).
|
|
1186
|
-
|
|
1187
|
-
### Fallback to HTTP-01
|
|
1188
|
-
|
|
1189
|
-
If DNS-01 fails, the `certProvisionFunction` returns `'http01'` to tell SmartProxy to fall back to HTTP-01 challenge validation. This provides a safety net for domains where DNS-01 isn't viable.
|
|
1190
|
-
|
|
1191
|
-
### Certificate Storage
|
|
1192
|
-
|
|
1193
|
-
Certificates are persisted via the `StorageBackedCertManager` which uses DcRouter's `StorageManager`. This means certs survive restarts and don't need to be re-provisioned unless they expire.
|
|
1194
|
-
|
|
1195
|
-
### Dashboard
|
|
1196
|
-
|
|
1197
|
-
The OpsServer includes a **Certificates** view showing:
|
|
1198
|
-
- All domains with their certificate status (valid, expiring, expired, failed)
|
|
1199
|
-
- Certificate source (ACME, provision function, static)
|
|
1200
|
-
- Expiry dates and issuer information
|
|
1201
|
-
- Backoff status for failed domains
|
|
1202
|
-
- One-click reprovisioning per domain
|
|
1203
|
-
- Certificate import and export
|
|
1204
|
-
|
|
1205
|
-
## Storage & Database
|
|
1206
|
-
|
|
1207
|
-
DcRouter uses a **unified database** (`DcRouterDb`) powered by [`@push.rocks/smartdata`](https://code.foss.global/push.rocks/smartdata) + [`@push.rocks/smartdb`](https://code.foss.global/push.rocks/smartdb) for all persistence. It supports two modes:
|
|
1208
|
-
|
|
1209
|
-
### Embedded LocalSmartDb (Default)
|
|
1210
|
-
|
|
1211
|
-
Zero-config, file-based MongoDB-compatible database — no external services needed:
|
|
1212
|
-
|
|
1213
|
-
```typescript
|
|
1214
|
-
dbConfig: { enabled: true }
|
|
1215
|
-
// Data stored at ~/.serve.zone/dcrouter/tsmdb by default
|
|
1216
|
-
```
|
|
1217
|
-
|
|
1218
|
-
### External MongoDB
|
|
1219
|
-
|
|
1220
|
-
Connect to an existing MongoDB instance:
|
|
1221
237
|
|
|
1222
|
-
|
|
1223
|
-
dbConfig: {
|
|
1224
|
-
enabled: true,
|
|
1225
|
-
mongoDbUrl: 'mongodb://localhost:27017',
|
|
1226
|
-
dbName: 'dcrouter',
|
|
1227
|
-
}
|
|
1228
|
-
```
|
|
1229
|
-
|
|
1230
|
-
### Disabling the Database
|
|
1231
|
-
|
|
1232
|
-
For static, constructor-only deployments where no runtime management is needed:
|
|
1233
|
-
|
|
1234
|
-
```typescript
|
|
1235
|
-
dbConfig: { enabled: false }
|
|
1236
|
-
// Routes come exclusively from constructor config — no CRUD, no persistence
|
|
1237
|
-
// OpsServer still runs but management features are disabled
|
|
1238
|
-
```
|
|
1239
|
-
|
|
1240
|
-
### What's Stored
|
|
1241
|
-
|
|
1242
|
-
DcRouterDb persists all runtime state across 15 document classes:
|
|
1243
|
-
|
|
1244
|
-
| Category | Documents | Purpose |
|
|
1245
|
-
|----------|-----------|---------|
|
|
1246
|
-
| **Routes** | `StoredRouteDoc`, `RouteOverrideDoc` | Programmatic routes and hardcoded route overrides |
|
|
1247
|
-
| **Certificates** | `ProxyCertDoc`, `AcmeCertDoc`, `CertBackoffDoc` | TLS certs, ACME state, per-domain backoff |
|
|
1248
|
-
| **Auth** | `ApiTokenDoc` | API token storage |
|
|
1249
|
-
| **Remote Ingress** | `RemoteIngressEdgeDoc` | Edge node registrations |
|
|
1250
|
-
| **VPN** | `VpnServerKeysDoc`, `VpnClientDoc` | Server keys and client registrations |
|
|
1251
|
-
| **RADIUS** | `VlanMappingsDoc`, `AccountingSessionDoc` | VLAN mappings and accounting sessions |
|
|
1252
|
-
| **References** | `SecurityProfileDoc`, `NetworkTargetDoc` | Reusable security profiles and network targets |
|
|
1253
|
-
| **Cache** | `CachedEmailDoc`, `CachedIpReputationDoc` | TTL-based caches with automatic cleanup |
|
|
1254
|
-
|
|
1255
|
-
## Security Features
|
|
1256
|
-
|
|
1257
|
-
### IP Reputation Checking
|
|
1258
|
-
|
|
1259
|
-
Automatic IP reputation checks on inbound connections with configurable caching:
|
|
1260
|
-
|
|
1261
|
-
```typescript
|
|
1262
|
-
// IP reputation is checked automatically for inbound SMTP connections.
|
|
1263
|
-
// Results are cached according to cacheConfig.ttlConfig.ipReputation.
|
|
1264
|
-
```
|
|
1265
|
-
|
|
1266
|
-
### Rate Limiting
|
|
1267
|
-
|
|
1268
|
-
Hierarchical rate limits with three levels of specificity:
|
|
1269
|
-
|
|
1270
|
-
```typescript
|
|
1271
|
-
// Global defaults (via emailConfig.defaults.rateLimits)
|
|
1272
|
-
defaults: {
|
|
1273
|
-
rateLimits: {
|
|
1274
|
-
inbound: { messagesPerMinute: 50, connectionsPerIp: 5, recipientsPerMessage: 50 },
|
|
1275
|
-
outbound: { messagesPerMinute: 100 }
|
|
1276
|
-
}
|
|
1277
|
-
}
|
|
1278
|
-
|
|
1279
|
-
// Per-domain overrides (in domain config)
|
|
1280
|
-
{
|
|
1281
|
-
domain: 'high-volume.com',
|
|
1282
|
-
rateLimits: {
|
|
1283
|
-
outbound: { messagesPerMinute: 500 } // Override for this domain
|
|
1284
|
-
}
|
|
1285
|
-
}
|
|
1286
|
-
```
|
|
1287
|
-
|
|
1288
|
-
**Precedence**: Domain-specific > Pattern-specific > Global
|
|
1289
|
-
|
|
1290
|
-
### Content Scanning
|
|
1291
|
-
|
|
1292
|
-
```typescript
|
|
1293
|
-
action: {
|
|
1294
|
-
type: 'process',
|
|
1295
|
-
options: {
|
|
1296
|
-
contentScanning: true,
|
|
1297
|
-
scanners: [
|
|
1298
|
-
{ type: 'spam', threshold: 5.0, action: 'tag' },
|
|
1299
|
-
{ type: 'virus', action: 'reject' },
|
|
1300
|
-
{ type: 'attachment', blockedExtensions: ['.exe', '.bat', '.scr'], action: 'reject' }
|
|
1301
|
-
]
|
|
1302
|
-
}
|
|
1303
|
-
}
|
|
238
|
+
await router.start();
|
|
1304
239
|
```
|
|
1305
240
|
|
|
1306
|
-
##
|
|
241
|
+
## Operations API and Dashboard
|
|
1307
242
|
|
|
1308
|
-
|
|
243
|
+
With the database enabled, dcrouter exposes a management plane for:
|
|
1309
244
|
|
|
1310
|
-
|
|
245
|
+
- routes and route toggles
|
|
246
|
+
- API tokens
|
|
247
|
+
- source profiles and network targets
|
|
248
|
+
- DNS providers, domains, and records
|
|
249
|
+
- ACME configuration and certificate lifecycle
|
|
250
|
+
- email domains and email operations
|
|
251
|
+
- VPN clients, remote ingress edges, and RADIUS data
|
|
1311
252
|
|
|
1312
|
-
|
|
1313
|
-
|------|-------------|
|
|
1314
|
-
| 📊 **Overview** | Real-time server stats, CPU/memory, connection counts, email throughput |
|
|
1315
|
-
| 🌐 **Network** | Active connections, top IPs, throughput rates, SmartProxy metrics |
|
|
1316
|
-
| 📧 **Email** | Queue monitoring (queued/sent/failed), bounce records, security incidents |
|
|
1317
|
-
| 🛣️ **Routes** | Merged route list (hardcoded + programmatic), create/edit/toggle/override routes |
|
|
1318
|
-
| 🔑 **API Tokens** | Token management with scopes, create/revoke/roll/toggle |
|
|
1319
|
-
| 🔐 **Certificates** | Domain-centric certificate overview, status, backoff info, reprovisioning, import/export |
|
|
1320
|
-
| 🌍 **RemoteIngress** | Edge node management, connection status, token generation, enable/disable |
|
|
1321
|
-
| 🔐 **VPN** | VPN client management, server status, create/toggle/export/rotate/delete clients |
|
|
1322
|
-
| 🛡️ **Security Profiles** | Reusable security configurations (IP allow/block lists, rate limits) |
|
|
1323
|
-
| 🎯 **Network Targets** | Reusable host:port destinations for route references |
|
|
1324
|
-
| 📡 **RADIUS** | NAS client management, VLAN mappings, session monitoring, accounting |
|
|
1325
|
-
| 📜 **Logs** | Real-time log viewer with level filtering and search |
|
|
1326
|
-
| ⚙️ **Configuration** | Read-only view of current system configuration |
|
|
1327
|
-
| 🛡️ **Security** | IP reputation, rate limit status, blocked connections |
|
|
253
|
+
The browser dashboard is built from the `ts_web` package and is served by OpsServer. The same backend is accessible programmatically via TypedRequest or the dedicated API client package.
|
|
1328
254
|
|
|
1329
|
-
|
|
255
|
+
## Programmatic API Client
|
|
1330
256
|
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
```typescript
|
|
1334
|
-
// Authentication
|
|
1335
|
-
'adminLoginWithUsernameAndPassword' // Login with credentials → returns JWT identity
|
|
1336
|
-
'verifyIdentity' // Verify JWT token validity
|
|
1337
|
-
'adminLogout' // End admin session
|
|
1338
|
-
|
|
1339
|
-
// Statistics & Health
|
|
1340
|
-
'getServerStatistics' // Uptime, CPU, memory, connections
|
|
1341
|
-
'getHealthStatus' // System health check
|
|
1342
|
-
'getCombinedMetrics' // All metrics in one call
|
|
1343
|
-
|
|
1344
|
-
// Email Operations
|
|
1345
|
-
'getAllEmails' // List all emails (queued/sent/failed)
|
|
1346
|
-
'getEmailDetail' // Full detail for a specific email
|
|
1347
|
-
'resendEmail' // Re-queue a failed email
|
|
1348
|
-
|
|
1349
|
-
// Certificates
|
|
1350
|
-
'getCertificateOverview' // Domain-centric certificate status
|
|
1351
|
-
'reprovisionCertificate' // Reprovision by route name (legacy)
|
|
1352
|
-
'reprovisionCertificateDomain' // Reprovision by domain (preferred)
|
|
1353
|
-
'importCertificate' // Import a certificate
|
|
1354
|
-
'exportCertificate' // Export a certificate
|
|
1355
|
-
'deleteCertificate' // Delete a certificate
|
|
1356
|
-
|
|
1357
|
-
// Remote Ingress
|
|
1358
|
-
'getRemoteIngresses' // List all edge registrations
|
|
1359
|
-
'createRemoteIngress' // Register a new edge
|
|
1360
|
-
'updateRemoteIngress' // Update edge settings
|
|
1361
|
-
'deleteRemoteIngress' // Remove an edge
|
|
1362
|
-
'regenerateRemoteIngressSecret' // Issue a new secret
|
|
1363
|
-
'getRemoteIngressStatus' // Runtime status of all edges
|
|
1364
|
-
'getRemoteIngressConnectionToken' // Generate a connection token for an edge
|
|
1365
|
-
|
|
1366
|
-
// Route Management (JWT or API token auth)
|
|
1367
|
-
'getMergedRoutes' // List all routes (hardcoded + programmatic)
|
|
1368
|
-
'createRoute' // Create a new programmatic route
|
|
1369
|
-
'updateRoute' // Update a programmatic route
|
|
1370
|
-
'deleteRoute' // Delete a programmatic route
|
|
1371
|
-
'toggleRoute' // Enable/disable a programmatic route
|
|
1372
|
-
'setRouteOverride' // Override a hardcoded route
|
|
1373
|
-
'removeRouteOverride' // Remove a hardcoded route override
|
|
1374
|
-
|
|
1375
|
-
// API Token Management (admin JWT only)
|
|
1376
|
-
'createApiToken' // Create API token → returns raw value once
|
|
1377
|
-
'listApiTokens' // List all tokens (without secrets)
|
|
1378
|
-
'revokeApiToken' // Delete an API token
|
|
1379
|
-
'rollApiToken' // Regenerate token secret
|
|
1380
|
-
'toggleApiToken' // Enable/disable a token
|
|
1381
|
-
|
|
1382
|
-
// Configuration (read-only)
|
|
1383
|
-
'getConfiguration' // Current system config
|
|
1384
|
-
|
|
1385
|
-
// Logs
|
|
1386
|
-
'getRecentLogs' // Retrieve system logs with filtering
|
|
1387
|
-
'getLogStream' // Stream live logs
|
|
1388
|
-
|
|
1389
|
-
// VPN
|
|
1390
|
-
'getVpnClients' // List all registered VPN clients
|
|
1391
|
-
'getVpnStatus' // VPN server status (running, subnet, port, keys)
|
|
1392
|
-
'createVpnClient' // Create client → returns WireGuard config (shown once)
|
|
1393
|
-
'deleteVpnClient' // Remove a VPN client
|
|
1394
|
-
'enableVpnClient' // Enable a disabled client
|
|
1395
|
-
'disableVpnClient' // Disable a client
|
|
1396
|
-
'rotateVpnClientKey' // Generate new keys (invalidates old ones)
|
|
1397
|
-
'exportVpnClientConfig' // Export WireGuard (.conf) or SmartVPN (.json) config
|
|
1398
|
-
'getVpnClientTelemetry' // Per-client bytes sent/received, keepalives
|
|
1399
|
-
|
|
1400
|
-
// RADIUS
|
|
1401
|
-
'getRadiusSessions' // Active RADIUS sessions
|
|
1402
|
-
'getRadiusClients' // List NAS clients
|
|
1403
|
-
'getRadiusStatistics' // RADIUS stats
|
|
1404
|
-
'setRadiusClient' // Add/update NAS client
|
|
1405
|
-
'removeRadiusClient' // Remove NAS client
|
|
1406
|
-
'getVlanMappings' // List VLAN mappings
|
|
1407
|
-
'setVlanMapping' // Add/update VLAN mapping
|
|
1408
|
-
'removeVlanMapping' // Remove VLAN mapping
|
|
1409
|
-
'testVlanAssignment' // Test what VLAN a MAC gets
|
|
1410
|
-
|
|
1411
|
-
// Security Profiles
|
|
1412
|
-
'getSecurityProfiles' // List all security profiles
|
|
1413
|
-
'getSecurityProfile' // Get a single profile by ID
|
|
1414
|
-
'createSecurityProfile' // Create a reusable security profile
|
|
1415
|
-
'updateSecurityProfile' // Update a profile (propagates to referencing routes)
|
|
1416
|
-
'deleteSecurityProfile' // Delete a profile (with optional force)
|
|
1417
|
-
'getSecurityProfileUsage' // Get routes referencing a profile
|
|
1418
|
-
|
|
1419
|
-
// Network Targets
|
|
1420
|
-
'getNetworkTargets' // List all network targets
|
|
1421
|
-
'getNetworkTarget' // Get a single target by ID
|
|
1422
|
-
'createNetworkTarget' // Create a reusable host:port target
|
|
1423
|
-
'updateNetworkTarget' // Update a target (propagates to referencing routes)
|
|
1424
|
-
'deleteNetworkTarget' // Delete a target (with optional force)
|
|
1425
|
-
'getNetworkTargetUsage' // Get routes referencing a target
|
|
1426
|
-
```
|
|
1427
|
-
|
|
1428
|
-
## API Client
|
|
1429
|
-
|
|
1430
|
-
DcRouter ships with a typed, object-oriented API client for programmatic management of a running instance. Install it separately or import from the main package:
|
|
257
|
+
Use the API client when you want automation or integration code instead of clicking through the dashboard.
|
|
1431
258
|
|
|
1432
259
|
```bash
|
|
1433
260
|
pnpm add @serve.zone/dcrouter-apiclient
|
|
1434
|
-
# or import from the main package:
|
|
1435
|
-
# import { DcRouterApiClient } from '@serve.zone/dcrouter/apiclient';
|
|
1436
261
|
```
|
|
1437
262
|
|
|
1438
|
-
### Quick Example
|
|
1439
|
-
|
|
1440
263
|
```typescript
|
|
1441
264
|
import { DcRouterApiClient } from '@serve.zone/dcrouter/apiclient';
|
|
1442
265
|
|
|
1443
|
-
const client = new DcRouterApiClient({
|
|
266
|
+
const client = new DcRouterApiClient({
|
|
267
|
+
baseUrl: 'https://dcrouter.example.com',
|
|
268
|
+
});
|
|
269
|
+
|
|
1444
270
|
await client.login('admin', 'password');
|
|
1445
271
|
|
|
1446
|
-
// OO resource instances with methods
|
|
1447
272
|
const { routes } = await client.routes.list();
|
|
1448
|
-
|
|
273
|
+
const systemRoutes = routes.filter((route) => route.origin !== 'api');
|
|
274
|
+
|
|
275
|
+
if (systemRoutes[0]) {
|
|
276
|
+
await systemRoutes[0].toggle(false);
|
|
277
|
+
}
|
|
1449
278
|
|
|
1450
|
-
|
|
1451
|
-
const newRoute = await client.routes.build()
|
|
279
|
+
await client.routes.build()
|
|
1452
280
|
.setName('api-gateway')
|
|
1453
281
|
.setMatch({ ports: 443, domains: ['api.example.com'] })
|
|
1454
|
-
.setAction({ type: 'forward', targets: [{ host: '
|
|
1455
|
-
.setTls({ mode: 'terminate', certificate: 'auto' })
|
|
1456
|
-
.save();
|
|
1457
|
-
|
|
1458
|
-
// Manage certificates
|
|
1459
|
-
const { certificates, summary } = await client.certificates.list();
|
|
1460
|
-
await certificates[0].reprovision();
|
|
1461
|
-
|
|
1462
|
-
// Create API tokens with builder
|
|
1463
|
-
const token = await client.apiTokens.build()
|
|
1464
|
-
.setName('ci-token')
|
|
1465
|
-
.setScopes(['routes:read', 'routes:write'])
|
|
1466
|
-
.setExpiresInDays(90)
|
|
282
|
+
.setAction({ type: 'forward', targets: [{ host: '127.0.0.1', port: 8081 }] })
|
|
1467
283
|
.save();
|
|
1468
|
-
console.log(token.tokenValue); // only available at creation
|
|
1469
|
-
|
|
1470
|
-
// Remote ingress edges
|
|
1471
|
-
const edge = await client.remoteIngress.build()
|
|
1472
|
-
.setName('edge-nyc-01')
|
|
1473
|
-
.setListenPorts([80, 443])
|
|
1474
|
-
.save();
|
|
1475
|
-
const connToken = await edge.getConnectionToken();
|
|
1476
|
-
|
|
1477
|
-
// Read-only managers
|
|
1478
|
-
const health = await client.stats.getHealth();
|
|
1479
|
-
const config = await client.config.get();
|
|
1480
|
-
const { logs } = await client.logs.getRecent({ level: 'error', limit: 50 });
|
|
1481
|
-
```
|
|
1482
|
-
|
|
1483
|
-
### Resource Managers
|
|
1484
|
-
|
|
1485
|
-
| Manager | Operations |
|
|
1486
|
-
|---------|-----------|
|
|
1487
|
-
| `client.routes` | `list()`, `create()`, `build()` → Route: `update()`, `delete()`, `toggle()`, `setOverride()`, `removeOverride()` |
|
|
1488
|
-
| `client.certificates` | `list()`, `import()` → Certificate: `reprovision()`, `delete()`, `export()` |
|
|
1489
|
-
| `client.apiTokens` | `list()`, `create()`, `build()` → ApiToken: `revoke()`, `roll()`, `toggle()` |
|
|
1490
|
-
| `client.remoteIngress` | `list()`, `getStatuses()`, `create()`, `build()` → RemoteIngress: `update()`, `delete()`, `regenerateSecret()`, `getConnectionToken()` |
|
|
1491
|
-
| `client.stats` | `getServer()`, `getEmail()`, `getDns()`, `getSecurity()`, `getConnections()`, `getQueues()`, `getHealth()`, `getNetwork()`, `getCombined()` |
|
|
1492
|
-
| `client.config` | `get(section?)` |
|
|
1493
|
-
| `client.logs` | `getRecent()`, `getStream()` |
|
|
1494
|
-
| `client.emails` | `list()` → Email: `getDetail()`, `resend()` |
|
|
1495
|
-
| `client.radius` | `.clients`, `.vlans`, `.sessions` sub-managers + `getStatistics()`, `getAccountingSummary()` |
|
|
1496
|
-
|
|
1497
|
-
See the [full API client documentation](./ts_apiclient/readme.md) for detailed usage of every manager, builder, and resource class.
|
|
1498
|
-
|
|
1499
|
-
## API Reference
|
|
1500
|
-
|
|
1501
|
-
### DcRouter Class
|
|
1502
|
-
|
|
1503
|
-
```typescript
|
|
1504
|
-
import { DcRouter } from '@serve.zone/dcrouter';
|
|
1505
|
-
|
|
1506
|
-
const router = new DcRouter(options: IDcRouterOptions);
|
|
1507
284
|
```
|
|
1508
285
|
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
| Method | Description |
|
|
1512
|
-
|--------|-------------|
|
|
1513
|
-
| `start(): Promise<void>` | Start all configured services |
|
|
1514
|
-
| `stop(): Promise<void>` | Gracefully stop all services |
|
|
1515
|
-
| `updateSmartProxyConfig(config): Promise<void>` | Hot-update SmartProxy routes |
|
|
1516
|
-
| `updateEmailConfig(config): Promise<void>` | Hot-update email configuration |
|
|
1517
|
-
| `updateEmailRoutes(routes): Promise<void>` | Update email routing rules at runtime |
|
|
1518
|
-
| `updateRadiusConfig(config): Promise<void>` | Hot-update RADIUS configuration |
|
|
1519
|
-
| `getStats(): any` | Get real-time statistics from all services |
|
|
1520
|
-
|
|
1521
|
-
#### Properties
|
|
1522
|
-
|
|
1523
|
-
| Property | Type | Description |
|
|
1524
|
-
|----------|------|-------------|
|
|
1525
|
-
| `options` | `IDcRouterOptions` | Current configuration |
|
|
1526
|
-
| `smartProxy` | `SmartProxy` | SmartProxy instance |
|
|
1527
|
-
| `smartAcme` | `SmartAcme` | SmartAcme v9 certificate manager instance |
|
|
1528
|
-
| `emailServer` | `UnifiedEmailServer` | Email server instance (from smartmta) |
|
|
1529
|
-
| `dnsServer` | `DnsServer` | DNS server instance |
|
|
1530
|
-
| `radiusServer` | `RadiusServer` | RADIUS server instance |
|
|
1531
|
-
| `remoteIngressManager` | `RemoteIngressManager` | Edge registration CRUD manager |
|
|
1532
|
-
| `tunnelManager` | `TunnelManager` | Tunnel lifecycle and status manager |
|
|
1533
|
-
| `vpnManager` | `VpnManager` | VPN server lifecycle and client CRUD manager |
|
|
1534
|
-
| `opsServer` | `OpsServer` | OpsServer/dashboard instance |
|
|
1535
|
-
| `metricsManager` | `MetricsManager` | Metrics collector |
|
|
1536
|
-
| `dcRouterDb` | `DcRouterDb` | Unified database instance (smartdata + smartdb) |
|
|
1537
|
-
| `routeConfigManager` | `RouteConfigManager` | Programmatic route CRUD manager |
|
|
1538
|
-
| `apiTokenManager` | `ApiTokenManager` | API token management |
|
|
1539
|
-
| `referenceResolver` | `ReferenceResolver` | Security profile and network target resolver |
|
|
1540
|
-
|
|
1541
|
-
### Re-exported Types
|
|
1542
|
-
|
|
1543
|
-
DcRouter re-exports key types for convenience:
|
|
286
|
+
See `./ts_apiclient/readme.md` for the dedicated API-client package docs.
|
|
1544
287
|
|
|
1545
|
-
|
|
1546
|
-
import {
|
|
1547
|
-
DcRouter,
|
|
1548
|
-
IDcRouterOptions,
|
|
1549
|
-
UnifiedEmailServer,
|
|
1550
|
-
type IUnifiedEmailServerOptions,
|
|
1551
|
-
type IEmailRoute,
|
|
1552
|
-
type IEmailDomainConfig,
|
|
1553
|
-
type IHttp3Config,
|
|
1554
|
-
} from '@serve.zone/dcrouter';
|
|
1555
|
-
```
|
|
1556
|
-
|
|
1557
|
-
## Sub-Modules
|
|
288
|
+
## Published Modules
|
|
1558
289
|
|
|
1559
|
-
|
|
290
|
+
This repository publishes multiple modules from the same codebase.
|
|
1560
291
|
|
|
1561
|
-
|
|
|
1562
|
-
|
|
1563
|
-
|
|
|
1564
|
-
|
|
|
1565
|
-
|
|
|
1566
|
-
|
|
|
292
|
+
| Module | Purpose | Docs |
|
|
293
|
+
| --- | --- | --- |
|
|
294
|
+
| `@serve.zone/dcrouter` | Main orchestrator and server package | `./readme.md` |
|
|
295
|
+
| `@serve.zone/dcrouter-interfaces` | Shared TypedRequest request and data interfaces | `./ts_interfaces/readme.md` |
|
|
296
|
+
| `@serve.zone/dcrouter-migrations` | Startup migration runner for dcrouter data | `./ts_migrations/readme.md` |
|
|
297
|
+
| `@serve.zone/dcrouter-web` | Web dashboard entry and UI components | `./ts_web/readme.md` |
|
|
298
|
+
| `@serve.zone/dcrouter-apiclient` | Typed OO API client | `./ts_apiclient/readme.md` |
|
|
1567
299
|
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
```typescript
|
|
1571
|
-
import { data, requests } from '@serve.zone/dcrouter/interfaces';
|
|
1572
|
-
import { DcRouterApiClient } from '@serve.zone/dcrouter/apiclient';
|
|
1573
|
-
```
|
|
1574
|
-
|
|
1575
|
-
## Testing
|
|
1576
|
-
|
|
1577
|
-
DcRouter includes a comprehensive test suite covering all system components:
|
|
300
|
+
## Development and Testing
|
|
1578
301
|
|
|
1579
302
|
```bash
|
|
1580
|
-
|
|
303
|
+
pnpm run build
|
|
1581
304
|
pnpm test
|
|
1582
|
-
|
|
1583
|
-
# Run a specific test file
|
|
1584
|
-
tstest test/test.jwt-auth.ts --verbose
|
|
1585
|
-
|
|
1586
|
-
# Run with extended timeout
|
|
1587
|
-
tstest test/test.opsserver-api.ts --verbose --timeout 60
|
|
1588
305
|
```
|
|
1589
306
|
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
| Test File | Area | Tests |
|
|
1593
|
-
|-----------|------|-------|
|
|
1594
|
-
| `test.apiclient.ts` | API client instantiation, builders, resource hydration, exports | 18 |
|
|
1595
|
-
| `test.contentscanner.ts` | Content scanning (spam, phishing, malware, attachments) | 13 |
|
|
1596
|
-
| `test.dcrouter.email.ts` | Email config, domain and route setup | 4 |
|
|
1597
|
-
| `test.dns-server-config.ts` | DNS record parsing, grouping, extraction | 5 |
|
|
1598
|
-
| `test.dns-socket-handler.ts` | DNS socket handler and route generation | 6 |
|
|
1599
|
-
| `test.errors.ts` | Error classes, handler, retry utilities | 5 |
|
|
1600
|
-
| `test.http3-augmentation.ts` | HTTP/3 route augmentation, qualification, opt-in/out, QUIC settings | 20 |
|
|
1601
|
-
| `test.ipreputationchecker.ts` | IP reputation, DNSBL, caching, risk classification | 10 |
|
|
1602
|
-
| `test.jwt-auth.ts` | JWT login, verification, logout, invalid credentials | 8 |
|
|
1603
|
-
| `test.opsserver-api.ts` | Health, statistics, configuration, log APIs | 8 |
|
|
1604
|
-
| `test.protected-endpoint.ts` | Admin auth, identity verification, public endpoints | 8 |
|
|
1605
|
-
| `test.reference-resolver.ts` | Security profiles, network targets, route resolution | 20 |
|
|
1606
|
-
| `test.security-profiles-api.ts` | Profile/target API endpoints, auth enforcement | 13 |
|
|
1607
|
-
|
|
1608
|
-
## Docker / OCI Container Deployment
|
|
1609
|
-
|
|
1610
|
-
DcRouter ships with a production-ready `Dockerfile` and supports environment-variable-driven configuration for OCI container deployments. The container image includes tini as PID 1 (via the base image), proper health checks, and configurable resource limits. When `DCROUTER_MODE=OCI_CONTAINER` is set, DcRouter automatically reads configuration from environment variables (and optionally from a JSON config file).
|
|
1611
|
-
|
|
1612
|
-
### Running with Docker
|
|
307
|
+
Target a single test file while working on one area:
|
|
1613
308
|
|
|
1614
309
|
```bash
|
|
1615
|
-
|
|
1616
|
-
--ulimit nofile=65536:65536 \
|
|
1617
|
-
-e DCROUTER_TLS_EMAIL=admin@example.com \
|
|
1618
|
-
-e DCROUTER_PUBLIC_IP=203.0.113.1 \
|
|
1619
|
-
-e DCROUTER_DNS_NS_DOMAINS=ns1.example.com,ns2.example.com \
|
|
1620
|
-
-e DCROUTER_DNS_SCOPES=example.com \
|
|
1621
|
-
-p 80:80 -p 443:443 -p 25:25 -p 587:587 -p 465:465 \
|
|
1622
|
-
-p 53:53/udp -p 3000:3000 -p 8443:8443 \
|
|
1623
|
-
code.foss.global/serve.zone/dcrouter:latest
|
|
310
|
+
tstest test/test.dns-runtime-routes.node.ts --verbose
|
|
1624
311
|
```
|
|
1625
312
|
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
### Environment Variables
|
|
1629
|
-
|
|
1630
|
-
| Variable | Description | Default | Example |
|
|
1631
|
-
|----------|-------------|---------|---------|
|
|
1632
|
-
| `DCROUTER_MODE` | Container mode (set automatically in image) | `OCI_CONTAINER` | — |
|
|
1633
|
-
| `DCROUTER_CONFIG_PATH` | Path to JSON config file (env vars override) | — | `/config/dcrouter.json` |
|
|
1634
|
-
| `DCROUTER_BASE_DIR` | Base data directory | `~/.serve.zone/dcrouter` | `/data/dcrouter` |
|
|
1635
|
-
| `DCROUTER_TLS_EMAIL` | ACME contact email | — | `admin@example.com` |
|
|
1636
|
-
| `DCROUTER_TLS_DOMAIN` | Primary TLS domain | — | `example.com` |
|
|
1637
|
-
| `DCROUTER_PUBLIC_IP` | Public IP for DNS records | — | `203.0.113.1` |
|
|
1638
|
-
| `DCROUTER_PROXY_IPS` | Comma-separated ingress proxy IPs | — | `198.51.100.1,198.51.100.2` |
|
|
1639
|
-
| `DCROUTER_DNS_NS_DOMAINS` | Comma-separated nameserver domains | — | `ns1.example.com,ns2.example.com` |
|
|
1640
|
-
| `DCROUTER_DNS_SCOPES` | Comma-separated authoritative domains | — | `example.com,other.com` |
|
|
1641
|
-
| `DCROUTER_EMAIL_HOSTNAME` | SMTP server hostname | — | `mail.example.com` |
|
|
1642
|
-
| `DCROUTER_EMAIL_PORTS` | Comma-separated email ports | — | `25,587,465` |
|
|
1643
|
-
| `DCROUTER_CACHE_ENABLED` | Enable/disable cache database | `true` | `false` |
|
|
1644
|
-
| `DCROUTER_HEAP_SIZE` | Node.js V8 heap size in MB | `512` | `1024` |
|
|
1645
|
-
| `DCROUTER_MAX_CONNECTIONS` | Global max concurrent connections | `50000` | `100000` |
|
|
1646
|
-
| `DCROUTER_MAX_CONNECTIONS_PER_IP` | Max connections per source IP | `100` | `200` |
|
|
1647
|
-
| `DCROUTER_CONNECTION_RATE_LIMIT` | Max new connections/min per IP | `600` | `1200` |
|
|
1648
|
-
|
|
1649
|
-
### Exposed Ports
|
|
1650
|
-
|
|
1651
|
-
The container exposes all service ports:
|
|
1652
|
-
|
|
1653
|
-
| Port(s) | Protocol | Service |
|
|
1654
|
-
|---------|----------|---------|
|
|
1655
|
-
| 80, 443 | TCP | HTTP/HTTPS (SmartProxy) |
|
|
1656
|
-
| 25, 587, 465 | TCP | SMTP, Submission, SMTPS |
|
|
1657
|
-
| 53 | TCP/UDP | DNS |
|
|
1658
|
-
| 1812, 1813 | UDP | RADIUS auth/acct |
|
|
1659
|
-
| 3000 | TCP | OpsServer dashboard |
|
|
1660
|
-
| 8443 | TCP | Remote ingress tunnels |
|
|
1661
|
-
| 51820 | UDP | WireGuard VPN |
|
|
1662
|
-
| 29000–30000 | TCP | Dynamic port range |
|
|
1663
|
-
|
|
1664
|
-
### Building the Image
|
|
1665
|
-
|
|
1666
|
-
```bash
|
|
1667
|
-
pnpm run build:docker # Build the container image
|
|
1668
|
-
pnpm run release:docker # Push to registry
|
|
1669
|
-
```
|
|
313
|
+
## Notes for Operators
|
|
1670
314
|
|
|
1671
|
-
|
|
315
|
+
- Database-backed management features depend on `dbConfig.enabled !== false`.
|
|
316
|
+
- If you disable the DB, constructor-configured services still run, but persistent management features are limited.
|
|
317
|
+
- Nameserver domains are still required for DNS bootstrap and DoH route generation.
|
|
318
|
+
- HTTP/3 is enabled by default for qualifying HTTPS routes unless disabled globally or per route.
|
|
1672
319
|
|
|
1673
320
|
## License and Legal Information
|
|
1674
321
|
|