isputnik-games
Docker app from isputnik-games' Repository
Overview
Readme
View on GitHubisputnik.games
An add-on for isputnik.home:
family games in a project and container of their own. It requires the
isputnik.home container, is installed beside it and is reached only through
home's /games gateway; on its own it does nothing. Board games: Dots,
Star Battle, Chess, Dominoes, and Checkers (Russian draughts).
Arcade games: Sputnik Catch and Torpedo Run.
Alpha. Two on one screen, against the computer, and online between family members (invite, accept, play from any device; the page polls for the other side's moves).
How it fits together
The games container never faces the network. The home app proxies /games/* to
it over the Docker network and forwards who is signed in, so the family signs in
once, in isputnik.home, and every control it has (two-factor, trusted networks,
rate limits) applies to the games too. The full design and the contract between
the two projects is in docs/plan.md.
browser ──► isputnik.home (:4000) ──► isputnik.games (:4200, internal only)
Running it
With Docker, beside the home app — see docker-compose.yml.
Generate one secret (openssl rand -hex 32) and set it as GAMES_GATEWAY_SECRET
on the home container and GATEWAY_SECRET on this one; point the home container's
GAMES_URL at this container. A "Games" entry then appears in the home app.
The two containers must share a user-defined Docker network. The home
container reaches this one by name (http://isputnik-games:4200), and names
resolve only on a network you created — Docker's default bridge has no DNS
between containers. Compose makes such a network for every project, so the
compose file above needs nothing more. With plain docker run, or on Unraid,
create it once and start both containers on it:
docker network create isputnik
The image is ghcr.io/isputnikdotnet/isputnik.games (what the compose file
and the Unraid template pull) and, the same bytes, isputnikdotnet/isputnik.games
on Docker Hub. Both are published by every release tag; latest is the newest
release.
Unraid — the repository carries a Community Applications template,
isputnik-games.xml, listed in CA as isputnik-games.
It publishes port 4200 on bridge, maps /config to
/mnt/user/appdata/isputnik-games, runs as 99:100 to match a default appdata
share, and asks for one thing: the gateway secret. Pair it from the home app
(Control panel → Settings → Apps → Games): the address is
http://<unraid IP>:4200, Generate secret makes the secret to paste into
this container's Gateway Secret field, and Test connection says Paired.
A shared user-defined network (address http://isputnik-games:4200) or br0 with
a fixed IP work too; the port mapping is then simply unused. Publishing the port
gives nothing away: without the secret every request is answered 401. How the
listing was made, for the next companion container: docs/publishing-checklist.md.
| Variable | Default | What it does |
|---|---|---|
GATEWAY_SECRET |
unset | The secret the home gateway signs forwarded requests with. Required in the image, at least 32 characters (openssl rand -hex 32); without one, with a short one, or with the compose example's placeholder the server refuses to start. |
PORT |
4200 |
The port to listen on. |
HOST |
0.0.0.0 in the image, 127.0.0.1 from source |
The address to listen on. |
STATIC_PATH |
/app/web in the image |
The built web app, served under /games/. |
DB_PATH |
/config/games.sqlite in the image, data/games.sqlite from source |
The SQLite file with the online matches. Mount /config as a volume. |
PUID / PGID |
1000 / 1000 |
The user the server runs as; the entrypoint takes ownership of /config for it (Unraid: usually 99 / 100). |
DEV_USER |
dev:Developer:admin:en:minimalist |
Source checkouts only, with no secret set: who the server pretends is signed in (id:name:role:lang:theme). |
LOG_LEVEL |
info |
trace … silent. At info every request is a line, including each poll for the other side's move; warn keeps only problems. |
Logs. The container logs to stdout as usual (docker logs isputnik-games),
and the home app shows the same from Control panel → Settings → Games: the
newest lines of the server log, and a table of events — who was refused at the
gateway check, who invited whom, how a match ended, which move was thrown out,
what broke — kept for 90 days in the games database. Every log line names the
member and the browser's address the home server forwarded, and carries the
home server's request id, so the two containers' logs can be read side by side.
Developing
npm install
npm run dev # engine (tsc --watch) + server on :4200 + Vite on :5174
Open http://127.0.0.1:5174/games/. With no GATEWAY_SECRET the server treats
every request as the developer identity, so the app runs on its own, and the
invite dialog offers a made-up family (Mum, Dad, Kid). To play an online match
against yourself, set DEV_USER=dad:Dad:member on a second server (another
port) or simply accept the invitation through the API. To run it
behind a real home app instead, start the home app with GAMES_URL pointing at
http://127.0.0.1:4200 and a shared secret, and open /games/ on the home app's
address.
npm run typecheck— builds the engine, then typechecks the server and the web appnpm run lintnpm test— engine rules and AI, server identity, web pagesnpm run build— everything the image ships
Layout
packages/engine/ pure TypeScript game rules shared by server and web
src/game.ts the GameDefinition every game implements
src/registry.ts the list of games
src/dots/ rules, computer opponent
apps/server/ Fastify: identity from the gateway, /games/api, static web
apps/web/ React + Vite with base /games/: lobby + one page per game
Adding a game: a folder in packages/engine/src/<game>/ implementing
GameDefinition, a line in the registry, a page under apps/web/src/games/<game>/
and an entry in the lobby catalog.
Licence
AGPL-3.0-only, like isputnik.home.
Requirements
Categories
Download Statistics
Related apps
Explore more like this
Explore allDetails
ghcr.io/isputnikdotnet/isputnik.games:latestRuntime arguments
- Network
bridge- Shell
sh- Privileged
- false
- Extra Params
--stop-timeout=30
Template configuration
The port the isputnik container reaches the games on: enter http://[your Unraid IP]:[this port] as the Games address in isputnik.home (Control panel, Settings, Apps). Not for browsers: the games open inside isputnik.home. On br0 with a fixed IP, or on a user-defined network shared with the isputnik container, this mapping is not used and the address is the container's own IP or name with port 4200.
- Target
- 4200
- Default
- 4200
- Value
- 4200
Stores the online matches, scores and the games' own log of events (a small SQLite database). Keep it apart from the isputnik container's appdata. isputnik.home's backups include a copy of it.
- Target
- /config
- Default
- /mnt/user/appdata/isputnik-games
- Value
- /mnt/user/appdata/isputnik-games
The secret isputnik.home signs its requests with, so this server knows who is signed in. Make it first, in isputnik.home on Control panel, Settings, Apps, Games (Generate secret; it is shown once), and paste it here. Required: the server refuses to start without one, or with one shorter than 32 characters. Nothing else is set on this container; everything about the games is managed inside isputnik.home.
- Target
- GATEWAY_SECRET
User ID the server runs as. It runs unprivileged (not root); on first start it takes ownership of the Config & Data path as this user. 99 (nobody) matches the default owner of an Unraid appdata share - leave it unless your share is owned by a different user.
- Default
- 99
- Value
- 99
Group ID the server runs as. 100 (users) matches the default group of an Unraid appdata share - leave it unless your share uses a different group.
- Default
- 100
- Value
- 100
trace, debug, info, warn, error, fatal or silent. At info every request is logged, including each poll for the other side's move; warn keeps only problems. isputnik.home shows this log and the games' own event record under Control panel, Overview, Logs.
- Target
- LOG_LEVEL
- Default
- info
- Value
- info