2026-09-26 15:21:26 +00:00

MSCO Dedicated Server

Dedizierter Server für MSCO – My Summer Car Online. Er hält einen gemeinsamen Spielstand, speichert alles, was die Spieler verändern, und gibt es an später Beitretende weiter. .NET 10, läuft unter Linux (Docker oder systemd) und Windows.

Voraussetzungen

  • Ein Lizenzschlüssel von https://msco.mbm.wtf/keys (Login mit Steam). Der Server prüft ihn beim Start und meldet sich danach regelmäßig beim Master für die Serverliste.
  • Ein My-Summer-Car-Spielstand als Startwelt.
  • Port 7777/TCP im Router/Firewall freigegeben (sonst wird der Server nicht gelistet).
  • Server und Mod müssen dieselbe Version haben (sonst bekommen Spieler eine Warnung).

Mit Docker (empfohlen)

git clone https://git.mbm.wtf/MrMaho/MSCO-Dedicated-Server.git
cd MSCO-Dedicated-Server
docker compose up -d --build     # erster Start legt data/server.json an und beendet sich
  1. In data/server.json mindestens LicenseKey eintragen.
  2. Die Spielstand-Dateien nach data/save/ kopieren (siehe unten).
  3. docker compose up -d
Aktion Befehl
Konsole docker attach msco-server – verlassen mit Strg+P, dann Strg+Q (Strg+C beendet den Server)
Einzelner Befehl docker exec msco-server msco <befehl>, z.B. msco players
Logs docker logs -f msco-server
Stoppen docker compose stop – speichert vorher den Weltzustand und meldet den Server ab
Update git pull && docker compose up -d --build

Anderer Port: in data/server.json und in docker-compose.yml ändern.

Linux: „Permission denied“ in data/

Der Container läuft als Benutzer-ID 1000 (der erste Linux-Benutzer), damit dir die Dateien in data/ gehören. Hat dein Benutzer eine andere ID (id -u / id -g), trag sie in eine .env neben der docker-compose.yml ein:

echo "MSCO_UID=$(id -u)" > .env
echo "MSCO_GID=$(id -g)" >> .env

Wurden Dateien schon von einer älteren Version als root angelegt (typisch: „Permission denied“ beim Hochladen per SFTP oder bei mkdir in data/), einmal zurückholen:

docker compose down
sudo chown -R $(id -u):$(id -g) data
docker compose up -d --build

Ohne Docker

Linux (systemd): .NET 10 Runtime installieren (sudo apt install dotnet-runtime-10.0), dann dotnet publish -c Release -o /opt/msco-server und deploy/msco-server.service einrichten (Anleitung oben in der Datei). Daten liegen in /var/lib/msco-server. Für eine Konsole den Server stattdessen in screen/tmux starten.

Windows: dotnet publish -c Release -o publish, dann publish\MSCO.Server.exe starten.

Startparameter:

  • --data <ordner> – Datenordner (Standard: Programmordner; Docker: /data)
  • --import-save [pfad] – Spielstand übernehmen (ohne Pfad: der eigene Spielstand dieses PCs, auch Proton)
  • --cmd <befehl> – Befehl an einen laufenden Server im selben Datenordner schicken

Spielstand

In data/save/ gehören diese Dateien aus dem My-Summer-Car-Spielstand: defaultES2File.txt, items.txt, meshsave.txt, graveyard.txt (und notepad.txt, falls vorhanden).

  • Windows: %USERPROFILE%\AppData\LocalLow\Amistech\My Summer Car
  • Linux (Proton): ~/.steam/steam/steamapps/compatdata/516750/pfx/drive_c/users/steamuser/AppData/LocalLow/Amistech/My Summer Car

Spielstand hochladen (SFTP, z.B. WinSCP / FileZilla)

Die Dateien einfach nach data/save/ im Server-Ordner hochladen, z.B. /home/<benutzer>/MSCO-Dedicated-Server/data/save/. Das geht auch, während der Server läuft. Kommt dabei „Permission denied“, gehört der Ordner noch root (siehe Abschnitt „Linux: Permission denied“ oben) – einmal sudo chown -R $(id -u):$(id -g) data ausführen. Meldet der Server nach dem Hochladen Cannot read the save game … Permission denied, gehören die neuen Dateien einem anderen Benutzer (z.B. mit einem anderen SFTP-Konto oder als root hochgeladen) oder deine Benutzer-ID ist nicht 1000. Der Server nennt im Log seine Benutzer-ID und den passenden chown-Befehl.

Neuen Spielstand übernehmen

Nach dem Hochladen eines anderen Spielstands die alten Änderungen verwerfen und die Dateien neu einlesen – sonst passt der gespeicherte Weltzustand nicht zum neuen Spielstand:

docker exec msco-server msco reset-world
docker exec msco-server msco reload-save

Ohne Docker: die beiden Befehle in der Server-Konsole eingeben, oder den Server stoppen, data/world.json löschen und neu starten.

Einstellungen (data/server.json)

Einstellung Bedeutung
LicenseKey Schlüssel von der Keymaster-Seite (Pflicht)
Name, Description Anzeige im Server-Browser
MaxPlayers, Port Spieler-Limit (max. 3 sinnvoll), Port
Public false = nicht in der Liste, nur Direct Connect
RequireSteam true = nur Spieler mit Steam; false = Non-Steam-Server (Spieler werden über den Namen erkannt)
PublicAddress öffentliche IP/Domain für die Liste (nur hinter NAT/Proxy nötig)
AutosaveSeconds wie oft der Weltzustand gespeichert wird
SaveSyncMinutes wie oft (Minuten) sich der Server von einem Spieler im Spiel den aktuellen Spielstand hochladen lässt (Standard 5, zusätzlich bei jedem Beitritt; 0 = nur beim Beitritt)
SteamWebApiKey Steam-Anmeldetickets der Spieler bei Steam prüfen – nötig für Admins (kostenlos: https://steamcommunity.com/dev/apikey)
BannedSteamIds gesperrte Spieler
Admins SteamID64s, die im Spiel mit /admin kicken/bannen dürfen (nur mit SteamWebApiKey, siehe Sicherheit)

Fehlende Einstellungen ergänzt der Server beim Start automatisch. Umgebungsvariablen (MSCO_LICENSE_KEY, MSCO_NAME, MSCO_PORT, MSCO_MAX_PLAYERS, MSCO_PUBLIC, MSCO_REQUIRE_STEAM, MSCO_PUBLIC_ADDRESS, MSCO_STEAM_WEB_API_KEY) überschreiben server.json.

Web-Panel (wie txAdmin)

Der Server bringt ein Web-Panel mit – auf demselben Port wie das Spiel (Standard 7777). Einfach im Browser http://<server-ip>:7777/ öffnen; der Server erkennt selbst, ob ein Browser oder das Spiel verbindet. Es muss also kein weiterer Port freigegeben werden.

Erstes Anmelden: Beim Start ohne Panel-Konto steht im Log ein Einrichtungs-Code:

docker logs msco-server | grep -A2 "WEB PANEL SETUP"

Mit diesem Code legst du im Browser das Owner-Konto an (erneut anzeigen: msco panel).

Bereich Was geht
Dashboard Spieler, Laufzeit, Weltzustand, Backups – Start / Stop / Restart des Gameservers, Grund wenn er nicht läuft
Players Liste mit ID, Name, SteamID, IP · Kick, Ban, Admin geben/nehmen · Nachricht an alle
Console Live-Log (Chat, Beitritte, Admin-Aktionen) und Befehle eingeben (mit Verlauf ↑/↓)
Bans Gebannte ansehen, entbannen, SteamID auch offline bannen
World & Backups Welt zurücksetzen, Backup, Reset-Punkt, Backups wiederherstellen, Spielstand als ZIP hoch-/herunterladen
Settings server.json bearbeiten (Name, Spielerzahl, Sichtbarkeit, Ports, Panel, Schlüssel …)
Panel Users weitere Benutzer anlegen: Moderator (Spieler/Chat), Admin (alles am Server), Owner (+ Benutzer)
  • Das Panel ist unabhängig vom Gameserver: Es läuft auch, wenn der Server gestoppt ist, abgestürzt ist oder gar nicht starten kann (z.B. kein Lizenzschlüssel, kein Spielstand). Das Dashboard zeigt dann den Grund – Schlüssel unter Settings eintragen bzw. Spielstand als ZIP unter World & Backups hochladen und Start drücken.
  • Stop fährt den Gameserver herunter (Spieler bekommen den Grund, niemand kann beitreten), Start startet ihn wieder, Restart lädt Einstellungen, Lizenz und Spielstand neu. Nach einem Absturz startet er automatisch neu.
  • Erster Start ganz ohne Einrichtung: docker compose up -d, Panel öffnen, Einrichtungs-Code aus dem Log eingeben, Lizenzschlüssel und Spielstand im Panel hinterlegen, Start.
  • Passwörter werden nur als PBKDF2-Hash in data/panel_users.json gespeichert, Login mit Sperre nach Fehlversuchen, Sitzungs-Cookie (HttpOnly, SameSite=Strict), Schutz gegen CSRF.

Hinter einem Reverse-Proxy (nginx, Traefik, Caddy, Nginx Proxy Manager …)

Den Proxy einfach auf http://<server>:7777 zeigen lassen und in server.json setzen:

"PanelTrustProxy": true,
"PanelBasePath": ""

PanelTrustProxy übernimmt die echte Besucher-IP und HTTPS (X-Forwarded-For / -Proto), PanelBasePath (z.B. "/panel") bzw. X-Forwarded-Prefix für einen Unterpfad. Lieber einen eigenen Port? "PanelPort": 40120 (und im docker-compose.yml freigeben); mit "PanelBindAddress": "127.0.0.1" ist das Panel dann nur über den lokalen Proxy erreichbar. Ganz aus: "PanelEnabled": false.

Konsolenbefehle

Befehl Beschreibung
status, players Übersicht, Spielerliste mit IDs
kick <id> [grund], ban <id> [grund] Spieler entfernen / sperren
bans, unban <SteamID64 oder name:spieler> Gesperrte anzeigen / Sperre aufheben
say <text> Chatnachricht an alle
admins, op <id oder SteamID64>, deop <...> Admins anzeigen / geben / nehmen
save Weltzustand jetzt speichern
reload-save Spielstand-Dateien neu einlesen – verbundene Spieler verbinden sich automatisch neu
backups, restore-save <nr> gesicherte Spielstände anzeigen / einen davon zurückholen (z.B. wenn der aktuelle kaputt ist) – alle verbinden sich neu
backup aktuellen Spielstand jetzt sichern
reset-world ganze Welt zurück auf den Reset-Punkt (den Spielstand, wie er dem Server gegeben wurde: Start, --import-save, reload-save) – alle verbinden neu
set-reset-point aktuellen Spielstand als neuen Reset-Punkt nehmen
stop / start Gameserver stoppen (das Web-Panel läuft weiter) / wieder starten
restart Server neu starten (Einstellungen, Lizenz, Spielstand neu laden)
exit ganzes Programm beenden (auch das Panel) – mit Docker startet es danach wieder, dauerhaft aus: docker compose stop
panel Adresse des Web-Panels und ggf. den Einrichtungs-Code anzeigen
stop speichern und beenden

Im Spiel öffnen Admins mit /admin (Chat, Taste T) oder admin (F7-Konsole) das Admin-Menü: Kick/Ban, GOTO/BRING (zu einem Spieler / Spieler zu sich teleportieren) und Cheats (Geld, Bedürfnisse auffüllen, Satsuma zu sich holen). Cheats werden allen im Chat angezeigt, Teleports stehen im Server-Log. Der Chat landet auch im Server-Log.

Was der Server speichert

Aktueller Spielstand statt Nachspielen: Tritt jemand bei (und alle SaveSyncMinutes), bittet der Server einen Spieler, der schon im Spiel ist, zu speichern und den Spielstand hochzuladen – genau wie das Spiel selbst speichert (Schrauben, angebaute Teile, alles). Neue Spieler bekommen diesen Stand; alte Aktionen werden dann nicht mehr nachgespielt. Der vorherige Spielstand liegt jeweils in data/save_backups/ (die letzten 5).

  • save/ – der Ausgangs-Spielstand, den jeder neue Spieler bekommt.
  • world.json – alles, was seitdem passiert ist: Positionen bewegter Objekte, Schraub-/Montage-Aktionen, Geld, Türen/Tore, Fahrzeugzustand (Tank, Öl, Schrauben, Verschleiß …) und die letzte Position jedes Spielers.

Beim Beitreten: Spielstand laden → Objekte erfassen → Weltzustand anwenden → an der letzten eigenen Position weiterspielen.

Betrieb in Produktion

Checkliste

  • LicenseKey gesetzt, Server startet ohne Fehler (docker logs msco-server)
  • Nur Port 7777/TCP nach außen offen; der Server braucht sonst nur ausgehend HTTPS zu msco.mbm.wtf
  • Log meldet keine Warnung „NOT reachable from the internet“ (sonst erscheint der Server nicht in der Liste)
  • Steam-Server (RequireSteam: true): SteamWebApiKey eintragen, damit Anmeldetickets wirklich bei Steam geprüft werden
  • Mindestens eine SteamID in Admins
  • Backups von data/ eingerichtet (siehe unten)

Neustarts: Docker startet den Server nach einem Absturz neu (restart: on-failure). Bei Konfigurationsfehlern (kein/ungültiger Schlüssel, kein Spielstand) beendet er sich mit Code 1 und wird nach 3 Versuchen nicht mehr gestartet – dann ins Log schauen. docker compose stop / systemctl stop speichern vorher den Weltzustand.

Logs: werden von Docker auf 3 × 10 MB begrenzt. Chat, Beitritte, Kicks/Bans und Admin-Aktionen stehen darin.

Backups: Alles Wichtige liegt in data/ (server.json, save/, world.json). Den Server dafür nicht anhalten – der Weltzustand wird atomar geschrieben. Beispiel (täglich per cron):

tar czf /backup/msco-$(date +%F).tar.gz -C /pfad/zu/MSCO-Dedicated-Server data

Updates: Server und Mod müssen dieselbe Version haben. Nach einem neuen Release:

git pull
docker compose up -d --build

Spieler mit einer anderen Mod-Version bekommen beim Verbinden eine Warnung.

Weltzustand zurücksetzen: msco reset-world (oder RESET WORLD im Admin-Menü) setzt die ganze Welt auf den Reset-Punkt zurück – den Spielstand, wie er dem Server gegeben wurde (liegt in data/save_original/). Einen neuen Spielstand übernehmen: Dateien nach data/save/ legen und msco reload-save ausführen – der wird dann auch der neue Reset-Punkt.

Sicherheit

  • Die Adresse des Masters (https://msco.mbm.wtf) ist fest eingebaut, damit niemand die Schlüsselprüfung mit einem eigenen Master umgehen kann. Sie lässt sich weder in server.json noch per Umgebungsvariable ändern.
  • data/ enthält Lizenzschlüssel und API-Keys – nicht veröffentlichen (steht in .gitignore).
  • Der Container läuft nicht als root. Spielerdaten (Nachrichten, Objektzustände) werden in der Größe begrenzt, unbekannte oder zu große Nachrichten verworfen.
  • Admins nur mit SteamWebApiKey: Ohne Key prüft der Server die Steam-Tickets nicht – jeder könnte dann eine fremde SteamID (z.B. die eines Admins) angeben. Deshalb gibt es ohne Key keine Admin-Rechte (das Log warnt beim Start), und eine unbestätigte SteamID kann keinen verbundenen Spieler verdrängen.
  • Gebannte Spieler werden über ihre (bei Steam geprüfte) SteamID erkannt. Auf Non-Steam-Servern gibt es keine verlässliche Identität – dort sind Bans nur über den Namen möglich.

Lizenz

GNU AGPL-3.0 – siehe LICENSE.

Made by MBM – mbm.wtf

S
Description
No description provided
Readme AGPL-3.0
2.7 MiB
Languages
C# 72.5%
JavaScript 22%
CSS 4.5%
HTML 0.7%
Dockerfile 0.3%