From 7c0d7faa245a8ca6302b7862a32e90ac092357ad Mon Sep 17 00:00:00 2001 From: Hornwitser Date: Sun, 30 Aug 2026 18:42:37 +0200 Subject: [PATCH 1/2] Add config to set URL for static assets Add option in the controller config to set where static assets are loaded from in order to support deployments where the static assets are server via a CDN while the API is directly accessed. This is useful because some CDNs put low limits on how large requests bodies can be, which causes issues with uploading large mods and saves. --- docs/configuration.md | 11 ++++++++++ packages/controller/src/Controller.ts | 11 +++++----- packages/controller/src/routes.ts | 1 + packages/controller/web/index.html | 2 +- packages/lib/src/config/definitions.ts | 16 +++++++++++++++ packages/lib/src/plugin.ts | 5 +++++ packages/lib/src/plugin_loader.ts | 6 ++++++ test/lib/config/validators.test.js | 28 ++++++++++++++++++++++++++ test/lib/plugin_loader.js | 8 +++++++- 9 files changed, 81 insertions(+), 7 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 2285e319..39013cfc 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -60,6 +60,17 @@ This should be a full URL ending with a /. Defaults to null meaning assume localhost. +### controller.static_url + +Used to override where static assets such as the web bundle is loaded from. +This can be used if you want to put the static assets on a separate cdn url like `https://cdn.example.com/static/` while keeping the API hosted directly by clusterio. +Due to a limitation on how the webpack assets are built the pathname component of the url have to be `/static/`. + +See also the `clusteriocontroller copy-static` command for how to obtain the static asset files that need to be hosted. + +Defaults to null meaning use the internally hosted assets. + + ### controller.tls_certificate Path to TLS certificate to use for the HTTPS server when controller.https_port is configured. diff --git a/packages/controller/src/Controller.ts b/packages/controller/src/Controller.ts index cd63d9cf..bcbdd007 100644 --- a/packages/controller/src/Controller.ts +++ b/packages/controller/src/Controller.ts @@ -355,6 +355,8 @@ export default class Controller { this.onSystemMetricsIntervalChanged(); } else if (field === "controller.trusted_proxies") { this.trustedProxies = this.parseTrustedProxies(); + } else if (field === "controller.static_url") { + this.app.locals.staticRoot = this.config.get("controller.static_url"); } lib.invokeHook(this.plugins, "onControllerConfigFieldChanged", field, curr, prev); }); @@ -389,6 +391,7 @@ export default class Controller { } this.app.locals.mainBundle = manifest["main.js"] || "no_web_build"; } + this.app.locals.staticRoot = this.config.get("controller.static_url"); // Load plugins await this.loadPlugins(); @@ -866,7 +869,7 @@ export default class Controller { ); } - static addAppRoutes(app: Application, pluginInfos: any[]) { + static addAppRoutes(app: Application, pluginInfos: lib.PluginNodeEnvInfo[]) { app.use((req: Request, res: Response, next) => { const startNs = process.hrtime.bigint(); stream.finished(res, () => { @@ -915,9 +918,7 @@ export default class Controller { app.get(route, Controller.serveWeb(route)); } - let pluginPackagePath = require.resolve(path.posix.join(pluginInfo.requirePath, "package.json")); - let webPath = path.join(path.dirname(pluginPackagePath), "dist", "web", "static"); - app.use("/static", express.static(webPath, staticOptions)); + app.use("/static", express.static(pluginInfo.webStaticPath, staticOptions)); } } @@ -1231,7 +1232,7 @@ export default class Controller { return function(req: Request, res: Response, next: NextFunction) { let depth = routeDepth + Number(req.path.slice(-1) === "/"); let webRoot = "../".repeat(depth) || "./"; - let staticRoot = `${webRoot}static/`; + let staticRoot = res.app.locals.staticRoot ?? `${webRoot}static/`; let mainBundle: string = ""; if (res.app.locals.mainBundle) { mainBundle = res.app.locals.mainBundle; diff --git a/packages/controller/src/routes.ts b/packages/controller/src/routes.ts index bcd3eaaa..a4e1da70 100644 --- a/packages/controller/src/routes.ts +++ b/packages/controller/src/routes.ts @@ -22,6 +22,7 @@ declare global { export interface Locals { controller: Controller, mainBundle: string, + staticRoot: string | null, devPlugins: Map, streams: Map } diff --git a/packages/controller/web/index.html b/packages/controller/web/index.html index 5a5a8af0..4bf444cd 100644 --- a/packages/controller/web/index.html +++ b/packages/controller/web/index.html @@ -29,7 +29,7 @@