A small HTTP service that runs next to a game server container and gives the Pegnia panel access to the server's files. It contains no game-specific code and does not talk to Kubernetes. (The console log and commands go through the controller's console gateway, which reads the game's container log from Kubernetes; nothing is logged to the volume.)
The Pegnia controller adds it to every game server pod when SIDECAR_IMAGE is set in the
controller's configuration. The sidecar shares the game's data volume and is reachable at
<server>-0.<server>.<namespace>.svc:9999 through the server's headless Service.
Readiness of the game itself is not the sidecar's job: the controller puts a Kubernetes readiness probe on the game container (a TCP check on the first TCP game port). Earlier versions of this project drove the Agones SDK lifecycle; that code has been removed.
All paths are relative to the data root. /, "" and . mean the root itself;
/mods and mods are the same directory. Paths that would leave the root (..,
/../etc, ../data-other, ...) are rejected, and every file operation goes through
Go's os.Root, so symlinks inside the data directory cannot lead outside it either.
| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Liveness check; never requires an API key |
/api/files?path= |
GET | List a directory (JSON) |
/api/files/download?path= |
GET | Download a file |
/api/files/upload?path=[&overwrite=true] |
POST | Upload a multipart file into a directory |
/api/files/delete |
POST | Delete a file or directory: {"path": "..."} |
/api/files/create-dir |
POST | Create a directory and its parents: {"path": "..."} |
Uploads are limited to 500 MB, and files with executable/script extensions
(.exe, .sh, .php, .js, ...) are refused. Uploading over an existing file needs
overwrite=true.
Every request except /health must carry SIDECAR_API_KEY in the X-API-Key header,
otherwise the sidecar answers 401. Without a key the sidecar refuses to start, unless
SIDECAR_INSECURE=true asks for an open API (local experiments only). In the cluster the
controller gives each server's sidecar its own key, and a NetworkPolicy lets only the
panel reach the sidecar port.
Each client IP (the first X-Forwarded-For entry if present, else the remote address) is
limited to SIDECAR_RATE_LIMIT requests per minute. /health is not limited.
| Environment variable | Description | Default |
|---|---|---|
SIDECAR_API_ADDR |
Listen address of the API | :9999 |
SIDECAR_DATA_ROOT |
Directory served by the API (the game's data volume); must exist | /data |
SIDECAR_API_KEY |
Required X-API-Key value (the controller sets a per-server key) |
(empty: refuses to start) |
SIDECAR_INSECURE |
true allows starting without an API key (local experiments only) |
(empty) |
SIDECAR_RATE_LIMIT |
Requests per minute per client IP | 60 |
curl -H "X-API-Key: change-me" http://localhost:9999/api/files?path=/
curl -o server.properties 'http://localhost:9999/api/files/download?path=server.properties'
curl -X POST -F "file=@my-mod.jar" 'http://localhost:9999/api/files/upload?path=mods'
curl -X POST -H 'Content-Type: application/json' -d '{"path":"mods/old"}' http://localhost:9999/api/files/create-dir
curl -X POST -H 'Content-Type: application/json' -d '{"path":"mods/old"}' http://localhost:9999/api/files/delete
curl -H "X-API-Key: $SIDECAR_API_KEY" http://localhost:9999/api/files # every request needs the keygo build ./... && go vet ./... && go test ./...
docker compose up --build # a Minecraft server with the sidecar on localhost:9999
make build # build the container image (see Makefile for the image name)Distributed under the MIT License. See LICENSE for more information.