Architecture
p2pstream is one server process with two network surfaces: public listeners for user traffic, and management for operators plus agents.
What It Is
The server runs the management UI/API, public proxy runtime, SQLite storage, public policy layers, TLS automation, and optional agent forwarding.
| Component | Role |
|---|---|
| Management UI/API | Serves the Vue UI, ConnectRPC API, and authenticated agent Yamux tunnel on MANAGEMENT_PORT, default 8081. |
| Public listeners | Bind configured HTTP/HTTPS ports and receive public user traffic. |
| WAF | Applies ordered block, captcha, and waiting-room rules before rate limits and routing. |
| Router | Selects a route by listener, host, path prefix, and priority. |
| Target executor | Forwards directly, returns static responses, redirects, or sends requests to a label-selected agent. |
| SQLite | Stores users, sessions, agents, public proxy config, TLS metadata, and observability events. |
When It Matters
Understand the architecture when choosing between direct targets and agent targets, deciding which ports to expose, planning backups, or troubleshooting where a request stopped.
Runtime Behavior
Direct target flow:
- A client connects to a public listener.
- ACME HTTP challenges and reserved WAF endpoints are handled before normal policy evaluation.
- WAF rules may block, require captcha, or place the visitor in a waiting room.
- Rate limit rules run before route resolution.
- A traffic shaper may wrap upload/download body streams.
- The router selects a route target, or a listener default route target if no explicit route matches.
- Cache rules can serve eligible proxy assets after route/target selection.
- The server forwards directly to the upstream origin or returns a redirect/static response.
- Observability records status, duration, policy IDs, listener/route/target IDs, agent ID, and byte counts.
Agent target flow:
- An agent connects outbound to management over management TLS and upgrades
GET /agent/tunnelwithUpgrade: p2pstream-yamux. - The agent authenticates with its generated agent ID and token.
- A route target is configured with agent transport and a label selector.
- For matching requests, the server selects a label-matched connected agent using the target's agent load-balancing policy.
- The server opens one Yamux stream for the upstream TCP connection.
- The server-owned HTTP transport runs over that stream; the agent only dials the origin and relays bytes.
Common Mistakes
- Exposing management
8081as if it were a public app listener. - Expecting Docker to publish a new listener port that was only created in the UI.
- Forgetting that agent target origins are resolved from the selected agent host.
- Running old WebSocket agents against a Yamux-tunnel server; agent and server versions must match after this breaking transport change.
- Deleting
/dataand losing SQLite, TLS material, ACME state, and the management CA.