Panel: warn before changing the game/panel port (needs a full program restart, Docker port mapping, how to undo) so nobody locks themselves out
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
1ff37065d0
commit
ad2dac21ba
+9
-2
@@ -24,7 +24,9 @@ public static class ConfigEditor
|
|||||||
panelBasePath = config.PanelBasePath,
|
panelBasePath = config.PanelBasePath,
|
||||||
licenseKeySet = !string.IsNullOrWhiteSpace(config.LicenseKey),
|
licenseKeySet = !string.IsNullOrWhiteSpace(config.LicenseKey),
|
||||||
steamWebApiKeySet = !string.IsNullOrWhiteSpace(config.SteamWebApiKey),
|
steamWebApiKeySet = !string.IsNullOrWhiteSpace(config.SteamWebApiKey),
|
||||||
environmentOverrides = config.EnvironmentOverrides
|
environmentOverrides = config.EnvironmentOverrides,
|
||||||
|
// In Docker muss ein anderer Port zusätzlich in docker-compose.yml freigegeben werden (Warnung im Panel)
|
||||||
|
inDocker = Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") == "true"
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>Einstellungen ändern. Schlüssel (Lizenz, Steam Web API) nur als Owner; leer = unverändert.</summary>
|
/// <summary>Einstellungen ändern. Schlüssel (Lizenz, Steam Web API) nur als Owner; leer = unverändert.</summary>
|
||||||
@@ -69,6 +71,7 @@ public static class ConfigEditor
|
|||||||
config.AutosaveSeconds = Number("autosaveSeconds", config.AutosaveSeconds, 10, 3600);
|
config.AutosaveSeconds = Number("autosaveSeconds", config.AutosaveSeconds, 10, 3600);
|
||||||
|
|
||||||
int before = changed.Count;
|
int before = changed.Count;
|
||||||
|
int oldPort = config.Port, oldPanelPort = config.PanelPort;
|
||||||
config.Port = Number("port", config.Port, 1, 65535);
|
config.Port = Number("port", config.Port, 1, 65535);
|
||||||
config.PanelEnabled = Flag("panelEnabled", config.PanelEnabled);
|
config.PanelEnabled = Flag("panelEnabled", config.PanelEnabled);
|
||||||
config.PanelPort = Number("panelPort", config.PanelPort, 0, 65535);
|
config.PanelPort = Number("panelPort", config.PanelPort, 0, 65535);
|
||||||
@@ -76,6 +79,8 @@ public static class ConfigEditor
|
|||||||
config.PanelTrustProxy = Flag("panelTrustProxy", config.PanelTrustProxy);
|
config.PanelTrustProxy = Flag("panelTrustProxy", config.PanelTrustProxy);
|
||||||
config.PanelBasePath = Text("panelBasePath", config.PanelBasePath, 60);
|
config.PanelBasePath = Text("panelBasePath", config.PanelBasePath, 60);
|
||||||
if (changed.Count > before) restartNeeded = true;
|
if (changed.Count > before) restartNeeded = true;
|
||||||
|
// Ports gehören dem Programm, nicht dem Gameserver: "Restart" im Panel reicht dafür nicht
|
||||||
|
bool portChanged = config.Port != oldPort || config.PanelPort != oldPanelPort;
|
||||||
|
|
||||||
foreach (string secret in new[] { "licenseKey", "steamWebApiKey" })
|
foreach (string secret in new[] { "licenseKey", "steamWebApiKey" })
|
||||||
{
|
{
|
||||||
@@ -93,7 +98,9 @@ public static class ConfigEditor
|
|||||||
catch (Exception e) { return "Could not save server.json: " + e.Message; }
|
catch (Exception e) { return "Could not save server.json: " + e.Message; }
|
||||||
GameServer.Log($"Settings changed by {by}: {string.Join(", ", changed)}");
|
GameServer.Log($"Settings changed by {by}: {string.Join(", ", changed)}");
|
||||||
var overridden = changed.Where(c => config.EnvironmentOverrides.Any(e => e.Replace("_", "").Contains(c.ToUpperInvariant().Replace("ISPUBLIC", "PUBLIC")))).ToList();
|
var overridden = changed.Where(c => config.EnvironmentOverrides.Any(e => e.Replace("_", "").Contains(c.ToUpperInvariant().Replace("ISPUBLIC", "PUBLIC")))).ToList();
|
||||||
return "Settings saved" + (restartNeeded ? " - some changes need a restart" : "") +
|
return "Settings saved" +
|
||||||
|
(portChanged ? " - the new port only applies after the whole program restarts (docker compose restart); in Docker publish it in docker-compose.yml first"
|
||||||
|
: restartNeeded ? " - some changes need a restart" : "") +
|
||||||
(overridden.Count > 0 ? " (note: " + string.Join(", ", overridden) + " is also set by an environment variable, which wins on restart)" : "");
|
(overridden.Count > 0 ? " (note: " + string.Join(", ", overridden) + " is also set by an environment variable, which wins on restart)" : "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+37
-1
@@ -356,6 +356,9 @@ function renderSettings(page) {
|
|||||||
if (typeof v === "number" && isNaN(v)) continue;
|
if (typeof v === "number" && isNaN(v)) continue;
|
||||||
body[k] = v;
|
body[k] = v;
|
||||||
}
|
}
|
||||||
|
// Port geändert? Vorher warnen - sonst sperrt man sich aus (vor allem in Docker, wo der Port nicht freigegeben ist)
|
||||||
|
const warning = portChangeWarning(c, body);
|
||||||
|
if (warning && !(await modal({ title: warning.title, text: warning.text, confirm: warning.confirm }))) return;
|
||||||
if (await act(api("POST", "config", body))) load();
|
if (await act(api("POST", "config", body))) load();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -378,7 +381,8 @@ function renderSettings(page) {
|
|||||||
h("div", { class: "section-head" }, h("h2", {}, "Network & panel"), h("span", { class: "muted" }, "needs a restart")),
|
h("div", { class: "section-head" }, h("h2", {}, "Network & panel"), h("span", { class: "muted" }, "needs a restart")),
|
||||||
h("div", { class: "section-body form-grid wide" },
|
h("div", { class: "section-body form-grid wide" },
|
||||||
number("port", "Game port", c.port, { min: 1, max: 65535, restart: true }),
|
number("port", "Game port", c.port, { min: 1, max: 65535, restart: true }),
|
||||||
number("panelPort", "Panel port", c.panelPort, { min: 0, max: 65535, restart: true, hint: "0 = same port as the game (recommended)" }),
|
number("panelPort", "Panel port", c.panelPort, { min: 0, max: 65535, restart: true,
|
||||||
|
hint: c.inDocker ? "0 = same port as the game (recommended). Docker: another port must also be published in docker-compose.yml" : "0 = same port as the game (recommended)" }),
|
||||||
text("panelBindAddress", "Panel bind address", c.panelBindAddress, { max: 60, restart: true, hint: "only with an own panel port - 127.0.0.1 = only via a local reverse proxy" }),
|
text("panelBindAddress", "Panel bind address", c.panelBindAddress, { max: 60, restart: true, hint: "only with an own panel port - 127.0.0.1 = only via a local reverse proxy" }),
|
||||||
text("panelBasePath", "Panel sub path", c.panelBasePath, { max: 60, restart: true, placeholder: "/", hint: "e.g. /panel when the proxy serves it there" }),
|
text("panelBasePath", "Panel sub path", c.panelBasePath, { max: 60, restart: true, placeholder: "/", hint: "e.g. /panel when the proxy serves it there" }),
|
||||||
toggle("panelTrustProxy", "Behind a reverse proxy", c.panelTrustProxy, "Trust X-Forwarded-For / -Proto / -Prefix", true),
|
toggle("panelTrustProxy", "Behind a reverse proxy", c.panelTrustProxy, "Trust X-Forwarded-For / -Proto / -Prefix", true),
|
||||||
@@ -396,6 +400,38 @@ function renderSettings(page) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Warnung, wenn Spiel- oder Panel-Port geändert werden: Ports übernimmt erst ein Neustart des ganzen Programms
|
||||||
|
* (der Restart-Knopf startet nur den Gameserver neu), danach ist das Panel nur noch am neuen Port - in Docker nur,
|
||||||
|
* wenn der Port in docker-compose.yml freigegeben ist. Text direkt in beiden Sprachen (enthält Zahlen).
|
||||||
|
*/
|
||||||
|
function portChangeWarning(c, body) {
|
||||||
|
const panelAt = (port, panelPort) => (panelPort > 0 ? panelPort : port);
|
||||||
|
const port = body.port ?? c.port, panelPort = body.panelPort ?? c.panelPort;
|
||||||
|
const oldPanel = panelAt(c.port, c.panelPort), newPanel = panelAt(port, panelPort);
|
||||||
|
if (port === c.port && newPanel === oldPanel) return null;
|
||||||
|
const de = window.MSCO_LANG === "de";
|
||||||
|
const lines = [];
|
||||||
|
if (newPanel !== oldPanel)
|
||||||
|
lines.push(de
|
||||||
|
? `Das Panel ist danach nur noch unter Port ${newPanel} erreichbar (http://<server>:${newPanel}/), nicht mehr unter ${oldPanel}.`
|
||||||
|
: `Afterwards the panel is only reachable on port ${newPanel} (http://<server>:${newPanel}/), no longer on ${oldPanel}.`);
|
||||||
|
if (port !== c.port)
|
||||||
|
lines.push(de ? `Spieler verbinden sich dann über Port ${port}.` : `Players then connect on port ${port}.`);
|
||||||
|
lines.push(de
|
||||||
|
? "Das gilt erst nach einem Neustart des ganzen Programms (docker compose restart) - der Neustart-Knopf startet nur den Gameserver neu."
|
||||||
|
: "This only applies after the whole program restarts (docker compose restart) - the Restart button only restarts the game server.");
|
||||||
|
const ports = [...new Set([port, newPanel])].map((p) => `"${p}:${p}/tcp"`).join(", ");
|
||||||
|
lines.push(c.inDocker
|
||||||
|
? (de ? `Docker: trag vorher unter ports in docker-compose.yml ${ports} ein, sonst sperrst du dich aus.`
|
||||||
|
: `Docker: first add ${ports} under ports in docker-compose.yml, otherwise you lock yourself out.`)
|
||||||
|
: (de ? "Gib den Port in der Firewall frei." : "Open the port in your firewall."));
|
||||||
|
lines.push(de
|
||||||
|
? 'Rückgängig: in data/server.json "PanelPort": 0 setzen und neu starten.'
|
||||||
|
: 'To undo: set "PanelPort": 0 in data/server.json and restart.');
|
||||||
|
return { title: de ? "Port ändern?" : "Change the port?", text: lines.join(" "), confirm: de ? "Trotzdem speichern" : "Save anyway" };
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------ Spieler
|
// ------------------------------------------------------------------ Spieler
|
||||||
|
|
||||||
function renderPlayers(page) {
|
function renderPlayers(page) {
|
||||||
|
|||||||
+6
-1
@@ -193,6 +193,8 @@
|
|||||||
"Game port": "Spiel-Port",
|
"Game port": "Spiel-Port",
|
||||||
"Panel port": "Panel-Port",
|
"Panel port": "Panel-Port",
|
||||||
"0 = same port as the game (recommended)": "0 = derselbe Port wie das Spiel (empfohlen)",
|
"0 = same port as the game (recommended)": "0 = derselbe Port wie das Spiel (empfohlen)",
|
||||||
|
"0 = same port as the game (recommended). Docker: another port must also be published in docker-compose.yml":
|
||||||
|
"0 = derselbe Port wie das Spiel (empfohlen). Docker: ein anderer Port muss zusätzlich in docker-compose.yml freigegeben werden",
|
||||||
"Panel bind address": "Panel-Bind-Adresse",
|
"Panel bind address": "Panel-Bind-Adresse",
|
||||||
"only with an own panel port - 127.0.0.1 = only via a local reverse proxy": "nur mit eigenem Panel-Port - 127.0.0.1 = nur über einen lokalen Reverse-Proxy",
|
"only with an own panel port - 127.0.0.1 = only via a local reverse proxy": "nur mit eigenem Panel-Port - 127.0.0.1 = nur über einen lokalen Reverse-Proxy",
|
||||||
"Panel sub path": "Panel-Unterpfad",
|
"Panel sub path": "Panel-Unterpfad",
|
||||||
@@ -317,7 +319,10 @@
|
|||||||
[/^Restored (.+?)( - start the server to use it)?$/, (m, n, s) => n + " wiederhergestellt" + (s ? " - starte den Server, um ihn zu benutzen" : "")],
|
[/^Restored (.+?)( - start the server to use it)?$/, (m, n, s) => n + " wiederhergestellt" + (s ? " - starte den Server, um ihn zu benutzen" : "")],
|
||||||
[/^Save game uploaded \((\d+) files\) - everyone reconnects$/, "Spielstand hochgeladen ($1 Dateien) - alle verbinden sich neu"],
|
[/^Save game uploaded \((\d+) files\) - everyone reconnects$/, "Spielstand hochgeladen ($1 Dateien) - alle verbinden sich neu"],
|
||||||
[/^Save game uploaded \((\d+) files\) - start the server to use it$/, "Spielstand hochgeladen ($1 Dateien) - starte den Server, um ihn zu benutzen"],
|
[/^Save game uploaded \((\d+) files\) - start the server to use it$/, "Spielstand hochgeladen ($1 Dateien) - starte den Server, um ihn zu benutzen"],
|
||||||
[/^Settings saved(.*)$/, (m, rest) => "Einstellungen gespeichert" + rest.replace(" - some changes need a restart", " - manche Änderungen brauchen einen Neustart")],
|
[/^Settings saved(.*)$/, (m, rest) => "Einstellungen gespeichert" + rest
|
||||||
|
.replace(" - some changes need a restart", " - manche Änderungen brauchen einen Neustart")
|
||||||
|
.replace(" - the new port only applies after the whole program restarts (docker compose restart); in Docker publish it in docker-compose.yml first",
|
||||||
|
" - der neue Port gilt erst nach einem Neustart des ganzen Programms (docker compose restart); in Docker vorher in docker-compose.yml freigeben")],
|
||||||
[/^The server is already (\w+)$/, (m, s) => "Der Server " + (s === "running" ? "läuft schon" : "startet schon")],
|
[/^The server is already (\w+)$/, (m, s) => "Der Server " + (s === "running" ? "läuft schon" : "startet schon")],
|
||||||
[/^No save game yet - upload one as ZIP in the panel \(World & Backups\) or copy it to data\/save$/,
|
[/^No save game yet - upload one as ZIP in the panel \(World & Backups\) or copy it to data\/save$/,
|
||||||
"Noch kein Spielstand - lade einen als ZIP/RAR im Panel hoch (Welt & Backups) oder kopiere ihn nach data/save"],
|
"Noch kein Spielstand - lade einen als ZIP/RAR im Panel hoch (Welt & Backups) oder kopiere ihn nach data/save"],
|
||||||
|
|||||||
@@ -178,6 +178,12 @@ Den Proxy einfach auf `http://<server>:7777` zeigen lassen und in `server.json`
|
|||||||
`docker-compose.yml` freigeben); mit `"PanelBindAddress": "127.0.0.1"` ist das Panel dann nur über den lokalen Proxy
|
`docker-compose.yml` freigeben); mit `"PanelBindAddress": "127.0.0.1"` ist das Panel dann nur über den lokalen Proxy
|
||||||
erreichbar. Ganz aus: `"PanelEnabled": false`.
|
erreichbar. Ganz aus: `"PanelEnabled": false`.
|
||||||
|
|
||||||
|
> **Eigener Panel-Port – nicht aussperren:** Der Port gilt erst nach einem Neustart des ganzen Programms
|
||||||
|
> (`docker compose restart`; der Neustart-Knopf im Panel startet nur den Gameserver neu). Danach ist das Panel **nur
|
||||||
|
> noch** unter dem neuen Port erreichbar, in Docker nur, wenn er in `docker-compose.yml` unter `ports` steht
|
||||||
|
> (`- "40120:40120/tcp"`). Schon ausgesperrt? `"PanelPort": 0` in `data/server.json` setzen und
|
||||||
|
> `docker compose restart` – dann ist das Panel wieder auf dem Spiel-Port.
|
||||||
|
|
||||||
## Konsolenbefehle
|
## Konsolenbefehle
|
||||||
|
|
||||||
| Befehl | Beschreibung |
|
| Befehl | Beschreibung |
|
||||||
|
|||||||
Reference in New Issue
Block a user