Ein Image mit Webseite, Backend, SQLite und Docker-Client; startet Match-Container über /var/run/docker.sock auf demselben Host. Tests laufen beim Bauen mit. Auf amp-cluster gebaut (301 MB) und geprüft. Dazu: Testbefehl für Node 22 angepasst, beim Beenden werden ausstehende Live-Updates verworfen und laufende Server-Aktionen abgewartet, damit nach dem Schließen der Datenbank nichts mehr darauf zugreift.
5.3 KiB
CS2 Mapveto als Container betreiben
CS2 Mapveto läuft als ein Container: Webseite, Backend, Datenbank (SQLite) und ein Docker-Client.
Er steht auf demselben Docker-Host wie die CS2-Server und startet pro Match über /var/run/docker.sock
einen eigenen CS2-Container (Docker-Adapter). Ein PC mit Node.js oder SSH wird dafür nicht mehr gebraucht.
Docker-Host (z. B. amp-cluster, 192.168.178.111)
├── cs2-mapveto ← dieser Container, Port 3000
├── cs2mv-<match> ← CS2-Server pro Match, Ports ab 27100 (startet/entfernt CS2 Mapveto)
├── Volume cs2-mapveto-gamefiles CS2-Spieldateien (~73 GB, einmal befüllt)
└── Volume cs2-mapveto-data Datenbank von CS2 Mapveto
Nur eine Instanz pro Docker-Host. Läuft CS2 Mapveto zusätzlich auf einem PC mit
SERVER_ADAPTER=dockerund demselben Docker-Host, vergeben beide unabhängig voneinander Ports und Containernamen. Die PC-Instanz also beenden oder auf einen anderen Adapter stellen, bevor der Container läuft.
1. Image bauen
Das Image wird auf dem Docker-Host gebaut, beim Bauen laufen auch alle Tests. Am einfachsten vom PC aus, im Projektordner, über den SSH-Zugang zum Host:
docker -H ssh://cs2docker build -t cs2-mapveto:latest .
Ergebnis: Image cs2-mapveto:latest (~300 MB) auf dem Host. Alternativ direkt auf dem Host nach einem
git clone des Repositorys: docker build -t cs2-mapveto:latest .
Meldet Docker unter Windows
docker-credential-desktop: executable file not found, kommt das von einer Docker-Desktop-Einstellung. Abhilfe für den einen Befehl:$env:DOCKER_CONFIG = "$env:TEMP\dockercfg"(Ordner mit einer Dateiconfig.json, Inhalt{}).
2. Stack in Portainer anlegen
Portainer → Stacks → + Add stack → Name cs2-mapveto → Web editor:
services:
cs2-mapveto:
image: cs2-mapveto:latest
container_name: cs2-mapveto
restart: unless-stopped
ports:
- "3000:3000"
environment:
- PUBLIC_URL=http://192.168.178.111:3000
- LOG_RECEIVER_URL=http://192.168.178.111:3000
- SERVER_ADAPTER=docker
- CS2_PUBLIC_HOST=192.168.178.111
- CS2_RCON_HOST=192.168.178.111
- CS2_GSLT=
- CS2_DOCKER_VOLUME=cs2-mapveto-gamefiles
- CS2_DOCKER_IMAGE=joedwards32/cs2:latest
- CS2_PORT_RANGE_START=27100
- CS2_PORT_RANGE_END=27139
- CREATE_MATCH_PASSWORD=
- STREAM_KEY=
- SERIES_AUTO_ADVANCE_SECONDS=30
- SERVER_IDLE_TIMEOUT_MINUTES=30
volumes:
- cs2-mapveto-data:/data
- /var/run/docker.sock:/var/run/docker.sock
volumes:
cs2-mapveto-data:
name: cs2-mapveto-data
Deploy the stack. Danach ist CS2 Mapveto unter http://192.168.178.111:3000 erreichbar, die Stream-Übersicht
unter /stream.
Dieselbe Datei liegt als compose.yml im Repository (dort zusätzlich mit build: ., für
docker compose up -d --build direkt auf dem Host).
Einstellungen
Alle Umgebungsvariablen aus .env.example funktionieren auch hier. Die wichtigsten:
| Variable | Bedeutung |
|---|---|
PUBLIC_URL |
Adresse der Webseite für Einladungslinks |
LOG_RECEIVER_URL |
Adresse, an die die CS2-Container ihre Logs schicken (Live-Ergebnisse) |
CS2_PUBLIC_HOST / CS2_RCON_HOST |
IP des Docker-Hosts – Spieler verbinden sich dorthin, CS2 Mapveto steuert die Server darüber |
CS2_GSLT |
leer = LAN-Modus; mit Token öffentlich erreichbar (ein Token pro gleichzeitigem Match) |
CS2_PORT_RANGE_START/END |
Ports für Match-Container, zwei pro Match, in der Firewall freigeben |
CREATE_MATCH_PASSWORD |
Passwort zum Anlegen von Matches |
STREAM_KEY |
Schlüssel für /stream?key=… |
Passwörter und Schlüssel nur aus Buchstaben und Ziffern wählen.
3. Updaten
- Neues Image bauen (Schritt 1, gleicher Befehl).
- Portainer → Stack
cs2-mapveto→ Update the stack (bzw. Container → Recreate).
Die Datenbank liegt im Volume cs2-mapveto-data und bleibt erhalten. Laufende Match-Container übernimmt
CS2 Mapveto nach dem Neustart wieder; ein Serverstart, der gerade lief, wird als unterbrochen markiert und
lässt sich mit „Server neu starten“ wiederholen.
4. Sicherheit
Der Container hat über /var/run/docker.sock volle Kontrolle über Docker auf dem Host – das ist nötig, um
Match-Container zu starten, entspricht aber Root-Rechten auf dem Host. Deshalb:
- Port 3000 nur im LAN anbieten, nicht ins Internet weiterleiten.
CREATE_MATCH_PASSWORDsetzen, wenn nicht jeder im LAN Matches anlegen soll.- RCON-Ports (TCP 27100–27139) möglichst nur vom Host bzw. LAN erreichbar lassen.
5. Fehlersuche
| Symptom | Ursache / Lösung |
|---|---|
| „Server wird angefordert“ bleibt stehen | Container-Log prüfen (Portainer → cs2-mapveto → Logs); Docker-Socket eingebunden? |
permission denied … docker.sock im Log |
Socket nicht eingebunden oder Docker mit Rootless-Modus – Pfad zum Socket anpassen |
| Match-Container startet, „Server startet“ endet in Fehler | Ports 27100+ von CS2_RCON_HOST aus erreichbar? Firewall des Hosts |
| Keine Live-Ergebnisse | LOG_RECEIVER_URL muss die Host-IP mit Port 3000 sein, nicht localhost |
| Port bereits belegt | Eine zweite CS2-Mapveto-Instanz nutzt denselben Host (siehe Hinweis oben) |