Field manual / Server operators
Run your own Q3JS server
This guide starts with a local health check, then publishes a persistent Quake III server that browser players can discover through the Q3JS master. The image combines the dedicated game server with the WebSocket gateway required by web clients.
Prepare the game data
Create a working directory with a baseq3 folder:
mkdir -p my-q3-server/baseq3
cd my-q3-serverCopy pak0.pk3 through pak8.pk3 directly into baseq3. Do not add another nested baseq3 directory.
my-q3-server/
└── baseq3/
├── pak0.pk3
├── pak1.pk3
├── ...
└── pak8.pk3Confirm that Docker will see the expected files:
ls -1 baseq3/pak*.pk3Test it locally
Run the pinned 1.0.0 image first. The named state volume preserves generated server files without changing your read-only game-data directory.
docker run --rm --name q3js-server-test -p 27960:27960/udp -p 27961:27961/tcp -v "$(pwd)/baseq3:/data/baseq3:ro" -v q3js-server-state:/state lukaklacar/q3js-server:1.0.0Wait for Q3JS server ready, then open another terminal and check the gateway:
curl -fsS http://localhost:27961/healthzA successful response means both the game server and browser gateway are ready. Stop the test with Control-C.
Choose the public address
You need the address that internet players can use to reach this machine. Use a public IPv4 address or a DNS hostname that points to it. Do not use localhost, 0.0.0.0, or a private address such as 192.168.x.x.
Direct connection
Publish TCP 27961 directly and keep Q3JS_SECURE=false.
TLS reverse proxy
Publish a hostname on TCP 443, proxy WebSockets to 27961, and set Q3JS_SECURE=true.
Start the public server
Replace YOUR_PUBLIC_IP_OR_HOSTNAME, then run this from my-q3-server:
docker run -d --name q3js-server --restart unless-stopped -p 27960:27960/udp -p 27961:27961/tcp -v "$(pwd)/baseq3:/data/baseq3:ro" -v q3js-server-state:/state -e Q3JS_MASTER_URL=https://master.q3js.com -e Q3JS_PUBLISH_HOST=YOUR_PUBLIC_IP_OR_HOSTNAME -e Q3JS_PUBLISH_PORT=27961 -e Q3JS_SECURE=false -e 'Q3JS_SERVER_CONFIG=seta sv_hostname "My Q3JS Server"; seta sv_maxclients "16"; seta g_gametype "0"; seta fraglimit "20"; seta timelimit "15"; map q3dm17' lukaklacar/q3js-server:1.0.0The server sends an anonymous heartbeat to master.q3js.com and is listed as a community server. No private Q3JS credential is required.
Open the network ports
If the Docker host is behind a router, forward both ports to its LAN address. Also allow them through the host firewall and any cloud-provider firewall.
27960 / UDP
Native Quake III traffic and server queries.
27961 / TCP
The WebSocket gateway used by browser players.
Carrier-grade NAT can prevent inbound connections even when local forwarding is correct. If your router has no public address, request one from your ISP or run the server on a VPS.
Verify the deployment
Check that the container is running and healthy:
docker ps --filter name=q3js-server
docker inspect --format='{{.State.Health.Status}}' q3js-server
docker logs --tail 100 q3js-serverVerify the local gateway directly:
curl -fsS http://localhost:27961/healthzFinally, open the Q3JS server browser. Registration is quick, but the master must also be able to connect back to the published host and query the server before it can display it.
Operate and update it
Follow live logs, restart the server, or remove the container with:
docker logs -f q3js-server
docker restart q3js-server
docker rm -f q3js-serverRemoving the container does not remove q3js-server-state. Re-run the public command to recreate it. Keep a versioned image tag for predictable deployments; use latest only when you intentionally want the newest release and have reviewed its migration notes.
Troubleshoot common failures
| Symptom | What to check |
|---|---|
| “Quake 3 data files are missing” | Mount to /data/baseq3 and confirm pak0.pk3 through pak8.pk3 are readable at the folder root. |
| Container is unhealthy or exits | Run docker logs q3js-server. Check the PK3 files, port conflicts, and the complete Q3JS_SERVER_CONFIG, including a map command. |
| Healthy but absent from the server browser | Confirm Q3JS_MASTER_URL, outbound HTTPS access, the public publish host, and inbound TCP 27961. |
| Listed but players cannot connect | Check DNS, port forwarding, firewalls, and that Q3JS_SECURE matches the actual ws:// or wss:// endpoint. |
| Works only on the local network | Verify the router’s WAN address, both forwarding rules, and whether the ISP uses carrier-grade NAT. |