Skip to main content
Version: 2.0 PartyKit

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​

URLWhat 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_HOST is 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​

ModePUBLIC_PARTYKIT_HOSTWho proxies?
Mode A β€” local devlocalhost:1999None β€” direct
Mode B β€” Dockerlocalhost:4321nginx (front container)
Productionsommelier-arena.USERNAME.partykit.devCloudflare (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​

EnvironmentFrontend URLPartyKit/WebSocket
Mode A (local dev)http://localhost:4321localhost:1999
Mode B (Docker)http://localhost:4321internal (nginx proxies /parties/* to back:1999)
Productionhttps://your-domain.com<project>.partykit.dev

Environment variables​

VariableWhere to setValue
PUBLIC_PARTYKIT_HOSTfront/.env.local (Mode A)localhost:1999
PUBLIC_PARTYKIT_HOSTdocker-compose.yml build arg (Mode B)localhost:4321
PUBLIC_PARTYKIT_HOSTCloudflare 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 to ws://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 β€” only PUBLIC_PARTYKIT_HOST changes.