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 (or .env.local.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 (internal only, not exposed to the browser directly)
# 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:4321 β set via Docker build arg
The browser connects to ws://localhost:4321/parties/main/{code}. nginx then proxies that to http://back:1999/parties/main/{code} (inside the Docker network β back is the service name).
Browser ββws://localhost:4321/parties/main/1234βββΊ nginx (front:4321)
β
proxy_pass βΌ
PartyKit (back:1999) [Docker internal]
Why go via nginx instead of directly to 1999?
- The Astro build is static β
PUBLIC_PARTYKIT_HOSTis baked at build time, not runtime. There is no way to change it after the image is built. - Using the same origin (
localhost:4321) avoids cross-origin WebSocket upgrades. - In production the exact same pattern applies (your domain instead of
localhost:4321).
Use localhost:4321 (proxied) for:
- Beta testing the full stack in Docker
- Simulating the production network topology
You can still access PartyKit directly at localhost:1999 for low-level debugging (e.g. testing a WebSocket message with wscat), but the running app always uses the proxied URL.
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:4321 | nginx (front container) |
| 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 |
|---|---|---|
| Mode A (local dev) | http://localhost:4321 | localhost:1999 |
| Mode B (Docker) | http://localhost:4321 | internal (nginx proxies /parties/* to back:1999) |
| Production | https://your-domain.com | <project>.partykit.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:4321 |
PUBLIC_PARTYKIT_HOST | Cloudflare Pages dashboard (Production) | <project>.partykit.dev |
Mode B note: In Docker, nginx proxies WebSocket connections from
localhost:4321/parties/*to the PartyKit container on port 1999. The frontend sees a single origin (localhost:4321) for both HTTP and WebSocket β no cross-origin issues.
localhost:1999 vs localhost:4321 in dev: When running Mode A (local dev with
npx partykit dev), PartyKit listens on port 1999 directly. Your browser connects tows://localhost:1999/parties/main/{code}. In Mode B (Docker), PartyKit is internal-only; nginx at port 4321 accepts WebSocket upgrades at/parties/*and proxies them to the PartyKit container. The app code is identical in both modes β onlyPUBLIC_PARTYKIT_HOSTchanges.