From a93af23275089f2c9526e483931a49aa68fa55fe Mon Sep 17 00:00:00 2001 From: sandro gianola Date: Tue, 2 Apr 2024 01:27:19 +0200 Subject: [PATCH 1/3] disable loading page feature --- config/config.yml.example | 1 + src/ConfigManager.ts | 5 +++++ src/ProxyHost.ts | 13 +++++++++++++ src/index.ts | 14 ++++++++++++-- 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/config/config.yml.example b/config/config.yml.example index 2a3ed75..1ca23ef 100644 --- a/config/config.yml.example +++ b/config/config.yml.example @@ -7,6 +7,7 @@ proxyHosts: proxyPort: 5800 timeoutSeconds: 15 stopOnTimeoutIfCpuUsageBelow: 50 + disableDefaultLoadingPage: false - domain: - wordpress.yourdomain.io - wordpress.otherdomain.io diff --git a/src/ConfigManager.ts b/src/ConfigManager.ts index 88432d5..b1cc47d 100644 --- a/src/ConfigManager.ts +++ b/src/ConfigManager.ts @@ -18,6 +18,7 @@ type ProxyHostConfig = { proxyUseCustomMethod: string timeoutSeconds: number stopOnTimeoutIfCpuUsageBelow?: number + disableDefaultLoadingPage?:boolean } type ApplicationConfig = { proxyListeningPort: number, @@ -141,6 +142,10 @@ export default class ConfigManager { proxyHost.stopOnTimeoutIfCpuUsageBelow = proxyHostConfig.stopOnTimeoutIfCpuUsageBelow as number; } + if (proxyHostConfig.disableDefaultLoadingPage) { + proxyHost.disableDefaultLoadingPage = proxyHostConfig.disableDefaultLoadingPage; + } + if (proxyHostConfig.domain instanceof Array) { proxyHostConfig.domain.forEach(domain => { this.proxyHosts.set( diff --git a/src/ProxyHost.ts b/src/ProxyHost.ts index 197ddfc..09c9696 100644 --- a/src/ProxyHost.ts +++ b/src/ProxyHost.ts @@ -16,6 +16,7 @@ export default class ProxyHost { public proxyUseCustomMethod: string | undefined; private timeoutSeconds: number; public stopOnTimeoutIfCpuUsageBelow = Infinity; + public disableDefaultLoadingPage = false private activeSockets: Set = new Set(); private containerEventEmitter: EventEmitter | null = null; @@ -137,6 +138,18 @@ export default class ProxyHost { this.startingHost = false; } + public async isContainerRunning():Promise { + let interval:NodeJS.Timer; + return new Promise((resolve) => { + interval = setInterval(async () => { + if (this.containerRunning) { + resolve(true); + clearInterval(interval); + } + }, 250); + }); + } + private checkContainerReady() { if (this.containerReadyChecking) return; diff --git a/src/index.ts b/src/index.ts index 07de849..bb92b3f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -120,8 +120,18 @@ placeholderServer.use((_, res, next) => { res.setHeader('x-powered-by', 'ContainerNursery'); next(); }); -placeholderServer.get('*', (req, res) => { - res.render('placeholder', { containerName: req.headers['x-container-nursery-container-name'] }); +placeholderServer.all('*', async (req, res) => { + const proxyHost = proxyHosts.get(req.headers.host as string); + if (proxyHost?.disableDefaultLoadingPage) { + await proxyHost?.isContainerRunning(); + proxyHost?.newConnection(); + proxy.web(req, res, { + target: proxyHost?.getTarget(), + headers: proxyHost?.getHeaders() + }); + } else { + res.render('placeholder', { containerName: req.headers['x-container-nursery-container-name'] }); + } }); placeholderServer.listen(placeholderServerListeningPort, placeholderServerListeningHost); logger.info({ port: placeholderServerListeningPort, host: placeholderServerListeningHost }, 'Proxy placeholder server listening'); From 75833a822561719826aee3bca9e0c936b72c1a1e Mon Sep 17 00:00:00 2001 From: sandro gianola Date: Thu, 18 Apr 2024 22:00:19 +0200 Subject: [PATCH 2/3] add global var to disable all default loading page | add customHttpStatusReadyChecking --- config/config.yml.example | 3 ++- src/ConfigManager.ts | 18 +++++++++++++++++- src/ProxyHost.ts | 7 ++++++- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/config/config.yml.example b/config/config.yml.example index 1ca23ef..a3aa688 100644 --- a/config/config.yml.example +++ b/config/config.yml.example @@ -1,4 +1,5 @@ proxyListeningPort: 80 +disableDefaultLoadingPage: true proxyHosts: - domain: handbrake.yourdomain.io containerName: handbrake @@ -7,7 +8,7 @@ proxyHosts: proxyPort: 5800 timeoutSeconds: 15 stopOnTimeoutIfCpuUsageBelow: 50 - disableDefaultLoadingPage: false + enableDefaultLoadingPage: true - domain: - wordpress.yourdomain.io - wordpress.otherdomain.io diff --git a/src/ConfigManager.ts b/src/ConfigManager.ts index b1cc47d..4185782 100644 --- a/src/ConfigManager.ts +++ b/src/ConfigManager.ts @@ -18,10 +18,13 @@ type ProxyHostConfig = { proxyUseCustomMethod: string timeoutSeconds: number stopOnTimeoutIfCpuUsageBelow?: number - disableDefaultLoadingPage?:boolean + disableDefaultLoadingPage?: boolean + enableDefaultLoadingPage?: boolean + customHttpStatusReadyChecking?: number } type ApplicationConfig = { proxyListeningPort: number, + disableDefaultLoadingPage: boolean, proxyHosts: ProxyHostConfig[] } @@ -29,11 +32,13 @@ export default class ConfigManager { private configFile = 'config/config.yml'; private proxyHosts: Map; private proxyListeningPort: number | null; + public disableDefaultLoadingPage: boolean | undefined; private eventEmitter: EventEmitter; constructor(proxyHosts: Map) { this.proxyHosts = proxyHosts; this.proxyListeningPort = null; + this.disableDefaultLoadingPage = false; this.eventEmitter = new EventEmitter(); this.createIfNotExist(); this.parseConfig(); @@ -97,6 +102,9 @@ export default class ConfigManager { if (!config || !config.proxyHosts) { logger.error({ invalidProperty: 'proxyHosts' }, 'Config is invalid, missing property'); } else { + if (config.disableDefaultLoadingPage) { + this.disableDefaultLoadingPage = config.disableDefaultLoadingPage; + } this.loadProxyHosts(config.proxyHosts); if (config.proxyListeningPort) { const prevPort = this.proxyListeningPort; @@ -142,10 +150,18 @@ export default class ConfigManager { proxyHost.stopOnTimeoutIfCpuUsageBelow = proxyHostConfig.stopOnTimeoutIfCpuUsageBelow as number; } + if (this.disableDefaultLoadingPage && !proxyHostConfig.enableDefaultLoadingPage) { + proxyHost.disableDefaultLoadingPage = this.disableDefaultLoadingPage; + } + if (proxyHostConfig.disableDefaultLoadingPage) { proxyHost.disableDefaultLoadingPage = proxyHostConfig.disableDefaultLoadingPage; } + if (proxyHostConfig.customHttpStatusReadyChecking) { + proxyHost.customHttpStatusReadyChecking = proxyHostConfig.customHttpStatusReadyChecking; + } + if (proxyHostConfig.domain instanceof Array) { proxyHostConfig.domain.forEach(domain => { this.proxyHosts.set( diff --git a/src/ProxyHost.ts b/src/ProxyHost.ts index 09c9696..2a86bb0 100644 --- a/src/ProxyHost.ts +++ b/src/ProxyHost.ts @@ -13,10 +13,12 @@ export default class ProxyHost { private proxyHost: string; private proxyPort: number; public proxyUseHttps = false; + public customHttpStatusReadyChecking: number | undefined public proxyUseCustomMethod: string | undefined; private timeoutSeconds: number; public stopOnTimeoutIfCpuUsageBelow = Infinity; public disableDefaultLoadingPage = false + public enableDefaultLoadingPage = false private activeSockets: Set = new Set(); private containerEventEmitter: EventEmitter | null = null; @@ -168,7 +170,10 @@ export default class ProxyHost { headers: res.headers }, 'Checked if target is ready'); - if (res.status === 200 || (res.status >= 300 && res.status <= 399)) { + if ( + res.status === 200 || (res.status >= 300 && res.status <= 399) + || (this.customHttpStatusReadyChecking && res.status === this.customHttpStatusReadyChecking) + ) { clearInterval(checkInterval); this.containerReadyChecking = false; this.containerRunning = true; From 069e6a178224fa485b4c7afa2a3e3c8c7a512e1d Mon Sep 17 00:00:00 2001 From: sandro gianola Date: Fri, 26 Apr 2024 12:28:03 +0200 Subject: [PATCH 3/3] update README --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 070ea5b..f6d47d1 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ The following top-level properties can be configured: Property | Meaning ---------|--------| `proxyListeningPort` | The port ContainerNursery should listen on for new http connections. Defaults to `80`. +`disableDefaultLoadingPage` | Boolean for disable the default loading page. By disabling the default loading page the request waits for the container and responds when the container is ready. Defaults to `false`. The virtual hosts the proxy should handle can be configured by adding an object to the `proxyHosts` key. @@ -68,6 +69,8 @@ The following properties are optional: | `proxyUseHttps` | Boolean indicating if the proxy should use HTTPS to connect to the container. Defaults to `false`. This should only be used if the container only accepts HTTPS requests. It provides no additional security. | | `stopOnTimeoutIfCpuUsageBelow` | If set, prevents the container from stopping when reaching the configured timeout if the averaged CPU usage (percentage between 0 and 100*core count) of the **main** container (first in the list of container names) is above this value. This is great for containers that should remain running while their doing intensive work even when nobody is doing any http requests, for example handbrake. | | `proxyUseCustomMethod` | Can be set to a HTTP method (`HEAD`,`GET`, ...) which should be used for the ready check. Some services only respond to certain HTTP methods correctly. | +| `enableDefaultLoadingPage` | Boolean for enable the default loading page when `disableDefaultLoadingPage` is set to `true`. | +| `customHttpStatusReadyChecking` | Custom Http status number use to check if the container is ready and running. | ### Example Configuration ```yaml