Networking URLs
Sommelier Arena exposes two WebSocket-capable endpoints depending on how you run the stack. Understanding the difference is useful when debugging or setting up a new environment.
The two URLsβ
| URL | What it is |
|---|---|
ws://localhost:1999/parties/main/{code} | Direct PartyKit dev server |
ws://localhost:4321/parties/main/{code} | Proxied β browser β nginx β PartyKit |
Both reach the same Durable Object and the same game logic. The difference is purely in the network path.
Mode A β Local development (no Docker)β
npx partykit dev --port 1999 # PartyKit listens on 1999
cd front && npm run dev # Astro dev server on 4321
front/.env.local (copied from front/.env.example) sets:
PUBLIC_PARTYKIT_HOST=localhost:1999
The browser connects directly to ws://localhost:1999/parties/main/{code}. No proxy is involved. The Astro dev server and PartyKit are two separate processes on two separate ports.
Use localhost:1999 for:
- Rapid frontend iteration with Vite HMR
- Debugging PartyKit logs directly in your terminal
Mode B β Docker (docker-compose up)β
docker-compose up --build -d
# front (nginx) β localhost:4321
# back (PartyKit) β localhost:1999 (exposed directly to the browser)
# docs (Docusaurus) β localhost:3002
In this mode, the Astro static site is built into nginx. At build time, the env var is baked in:
PUBLIC_PARTYKIT_HOST=localhost:1999 β set via Docker build arg
The browser connects directly to ws://localhost:1999/parties/main/{code} β the same URL as Mode A. nginx serves only static HTML/JS/CSS files and handles SPA routing; it does not proxy WebSocket traffic.
Browser ββws://localhost:1999/parties/main/1234βββΊ PartyKit (back:1999) [exposed on host port 1999]
Use Mode B for:
- Beta testing the full stack in Docker
- Running E2E tests against the production-like build
Production β Cloudflareβ
In production the PartyKit server is deployed to Cloudflare Workers via npx partykit deploy. The game URL becomes:
wss://sommelier-arena.USERNAME.partykit.dev/parties/main/{code}
The Cloudflare Pages frontend is built with:
PUBLIC_PARTYKIT_HOST=sommelier-arena.USERNAME.partykit.dev
The browser connects directly to the PartyKit Workers URL β no nginx proxy is needed because Cloudflare handles TLS, routing, and WebSocket upgrades natively.
Browser ββwss://sommelier-arena.USERNAME.partykit.dev/parties/main/1234βββΊ Cloudflare Workers (PartyKit DO)
Summaryβ
| Mode | PUBLIC_PARTYKIT_HOST | Who proxies? |
|---|---|---|
| Mode A β local dev | localhost:1999 | None β direct |
| Mode B β Docker | localhost:1999 | None β direct (back exposed on host port 1999) |
| Production | sommelier-arena.USERNAME.partykit.dev | Cloudflare (native) |
The PartyKit WebSocket path is always /parties/main/{sessionCode} β main matches the "main" entry point in partykit.json, and {sessionCode} is the 4-digit room ID.
Port referenceβ
| Environment | Frontend URL | PartyKit/WebSocket | Wine Answers Worker |
|---|---|---|---|
| Mode A (local dev) | http://localhost:4321 | localhost:1999 (direct) | http://localhost:1998 (optional) |
| Mode B (Docker) | http://localhost:4321 | localhost:1999 (direct β back exposed on host port 1999) | http://localhost:1998 (wine-answers container) |
| Production | https://your-domain.com | <project>.partykit.dev | https://<wine-answers-worker>.workers.dev |
Environment variablesβ
| Variable | Where to set | Value |
|---|---|---|
PUBLIC_PARTYKIT_HOST | front/.env.local (Mode A) | localhost:1999 |
PUBLIC_PARTYKIT_HOST | docker-compose.yml build arg (Mode B) | localhost:1999 |
PUBLIC_PARTYKIT_HOST | Cloudflare Pages dashboard (Production) | <project>.partykit.dev |
PUBLIC_WINE_ANSWERS_URL | front/.env.local (Mode A) | http://localhost:1998 |
PUBLIC_WINE_ANSWERS_URL | docker-compose.yml build arg (Mode B) | http://localhost:1998 |
PUBLIC_WINE_ANSWERS_URL | Cloudflare Pages dashboard (Production) | https://<wine-answers-worker>.workers.dev |
Mode B note: In Docker, the browser connects directly to
localhost:1999for WebSocket traffic (thebackcontainer is exposed on host port 1999). nginx in thefrontcontainer only serves static files and handles SPA routing β no WebSocket proxy needed.
Mode A and Mode B use the same
PUBLIC_PARTYKIT_HOST: Both modes setPUBLIC_PARTYKIT_HOST=localhost:1999. The browser always connects tows://localhost:1999/parties/main/{code}directly. The app code is identical in both modes.