Skip to content

Commit 9fa0bcb

Browse files
committed
init deployment doc
Squashed commit of the following: commit 1228a1d15f8ee7dec41d8af456d598173222821b Author: Lukas Herman <[email protected]> Date: Mon Dec 22 22:10:02 2025 -0500 init chart deployment
1 parent 60c4eaa commit 9fa0bcb

File tree

6 files changed

+1487
-83
lines changed

6 files changed

+1487
-83
lines changed

components/mdx/mermaid.tsx

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
'use client';
2+
3+
import { use, useEffect, useId, useState } from 'react';
4+
import { useTheme } from 'next-themes';
5+
6+
export function Mermaid({ chart }: { chart: string }) {
7+
const [mounted, setMounted] = useState(false);
8+
9+
useEffect(() => {
10+
setMounted(true);
11+
}, []);
12+
13+
if (!mounted) return;
14+
return <MermaidContent chart={chart} />;
15+
}
16+
17+
const cache = new Map<string, Promise<unknown>>();
18+
19+
function cachePromise<T>(
20+
key: string,
21+
setPromise: () => Promise<T>,
22+
): Promise<T> {
23+
const cached = cache.get(key);
24+
if (cached) return cached as Promise<T>;
25+
26+
const promise = setPromise();
27+
cache.set(key, promise);
28+
return promise;
29+
}
30+
31+
function MermaidContent({ chart }: { chart: string }) {
32+
const id = useId();
33+
const { resolvedTheme } = useTheme();
34+
const { default: mermaid } = use(
35+
cachePromise('mermaid', () => import('mermaid')),
36+
);
37+
38+
mermaid.initialize({
39+
startOnLoad: false,
40+
securityLevel: 'loose',
41+
fontFamily: 'inherit',
42+
themeCSS: 'margin: 1.5rem auto 0;',
43+
theme: resolvedTheme === 'dark' ? 'dark' : 'default',
44+
});
45+
46+
const { svg, bindFunctions } = use(
47+
cachePromise(`${chart}-${resolvedTheme}`, () => {
48+
return mermaid.render(id, chart.replaceAll('\\n', '\n'));
49+
}),
50+
);
51+
52+
return (
53+
<div
54+
ref={(container) => {
55+
if (container) bindFunctions?.(container);
56+
}}
57+
dangerouslySetInnerHTML={{ __html: svg }}
58+
/>
59+
);
60+
}

content/deployment.mdx

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,103 @@
11
---
22
title: Deployment
33
---
4+
5+
**WIP**
6+
7+
## Deployment Architectures
8+
9+
### 1. Single Node (Quick Start)
10+
11+
Best for testing, demos, or low-traffic internal tools. Caddy handles SSL
12+
termination and proxies signaling traffic to PulseBeam.
13+
14+
```mermaid
15+
graph TD
16+
User((User)) -- "HTTPS (443)" --> Caddy[Caddy Proxy]
17+
18+
subgraph Host ["Single VM / Docker Host"]
19+
Caddy -- "localhost:3000" --> PB[PulseBeam]
20+
end
21+
22+
```
23+
24+
```yaml
25+
version: "3.8"
26+
services:
27+
pulsebeam:
28+
image: ghcr.io/pulsebeamdev/pulsebeam:pulsebeam-v0.3.0
29+
restart: unless-stopped
30+
network_mode: "host"
31+
32+
caddy:
33+
image: caddy:2
34+
restart: unless-stopped
35+
network_mode: "host"
36+
volumes:
37+
- caddy_data:/data
38+
command:
39+
- caddy
40+
- reverse-proxy
41+
- --from
42+
- demo.pulsebeam.dev
43+
- --to
44+
- localhost:3000
45+
46+
volumes:
47+
caddy_data:
48+
```
49+
50+
### 2. Multi-Node (Production/High Availability)
51+
52+
For production environments requiring high availability, we recommend replacing
53+
Caddy with HAProxy. The reverse proxy must be configured with consistent hashing
54+
to ensure each participant connects to the correct node.
55+
56+
In the future, we will remove this limitation by allowing a single room to be
57+
handled by multiple nodes.
58+
59+
```mermaid
60+
graph TD
61+
%% Styling
62+
classDef haproxy fill:#fdfdfd,stroke:#005c94,stroke-width:2px;
63+
classDef sfu fill:#f9f9f9,stroke:#333,stroke-width:2px;
64+
65+
Client((Client)) -- "HTTPS" --> CLB[Cloud Load Balancer]
66+
67+
subgraph HA_Layer [HAProxy Fleet]
68+
HA1[HAProxy 1]
69+
HA2[HAProxy 2]
70+
end
71+
72+
subgraph SFU_Fleet [PulseBeam SFU Fleet]
73+
direction LR
74+
PB1[Node A]
75+
PB2[Node B]
76+
PB3[Node C]
77+
end
78+
79+
CLB --> HA1
80+
CLB --> HA2
81+
82+
%% Logical routing
83+
HA1 -. "Hash(Room-ID)" .-> PB1
84+
HA2 -. "Hash(Room-ID)" .-> PB1
85+
HA1 -. "Hash(Room-ID)" .-> PB3
86+
87+
class HA1,HA2 haproxy;
88+
class PB1,PB2,PB3 sfu;
89+
```
90+
91+
## Port & Firewall Requirements
92+
93+
| Port | Protocol | Traffic | Scope | Purpose |
94+
| -------- | -------- | ------- | -------- | --------------------------------- |
95+
| **443** | **UDP** | Inbound | Public | ICE over UDP |
96+
| **443** | **TCP** | Inbound | Public | ICE over TCP fallback |
97+
| **3000** | **TCP** | Inbound | Internal | Proxied HTTP signaling |
98+
| **6060** | **TCP** | Inbound | Private | Metrics, health checks, and pprof |
99+
100+
> **Note on Networking:** `network_mode: "host"` is required to eliminate the
101+
> overhead of Container’s network virtualization. For high-throughput real-time
102+
> traffic, removing NAT indirection is critical for performance and ensures the
103+
> SFU can correctly discover its public IP for ICE candidate gathering.

mdx-components.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import defaultMdxComponents from 'fumadocs-ui/mdx';
2+
import { Mermaid } from '@/components/mdx/mermaid';
23
import type { MDXComponents } from 'mdx/types';
34

45
export function getMDXComponents(components?: MDXComponents): MDXComponents {
56
return {
67
...defaultMdxComponents,
8+
Mermaid,
79
...components,
810
};
911
}

0 commit comments

Comments
 (0)