mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
feat(proxy): add NO_PROXY support and use request URL for proxy agent selection
- Parse NO_PROXY / no_proxy in Probe Config into a trimmed list - Wire NO_PROXY into UI docs, Helm chart values, and probe Docker/compose examples - Add NO_PROXY env var to Helm probe template when provided - Pass target URL to ProxyConfig.getRequestProxyAgents / getHttpProxyAgent / getHttpsProxyAgent so proxy selection is per-request - Update probe calls (Alive, Metrics, FetchList, FetchMonitorTest, Register, Monitor ingest/reporting, Api/Website/Ssl monitors) to use local URL variables and supply them to proxy helpers - Minor refactors to avoid inline URL construction where reused
This commit is contained in:
@@ -41,6 +41,7 @@ docker run --name oneuptime-probe --network host \\
|
||||
-e ONEUPTIME_URL=${host.toString()} \\
|
||||
-e HTTP_PROXY_URL=http://proxy.example.com:8080 \\
|
||||
-e HTTPS_PROXY_URL=http://proxy.example.com:8080 \\
|
||||
-e NO_PROXY=localhost,.internal.example.com \
|
||||
-d oneuptime/probe:release
|
||||
|
||||
# With proxy authentication
|
||||
@@ -50,6 +51,7 @@ docker run --name oneuptime-probe --network host \\
|
||||
-e ONEUPTIME_URL=${host.toString()} \\
|
||||
-e HTTP_PROXY_URL=http://username:password@proxy.example.com:8080 \\
|
||||
-e HTTPS_PROXY_URL=http://username:password@proxy.example.com:8080 \\
|
||||
-e NO_PROXY=localhost,.internal.example.com \
|
||||
-d oneuptime/probe:release
|
||||
`}
|
||||
/>
|
||||
|
||||
@@ -27,6 +27,7 @@ docker run --name oneuptime-probe --network host \
|
||||
-e PROBE_ID=<probe-id> \
|
||||
-e ONEUPTIME_URL=https://oneuptime.com \
|
||||
-e HTTP_PROXY_URL=http://proxy.example.com:8080 \
|
||||
-e NO_PROXY=localhost,.internal.example.com \
|
||||
-d oneuptime/probe:release
|
||||
|
||||
# For HTTPS proxy
|
||||
@@ -35,6 +36,7 @@ docker run --name oneuptime-probe --network host \
|
||||
-e PROBE_ID=<probe-id> \
|
||||
-e ONEUPTIME_URL=https://oneuptime.com \
|
||||
-e HTTPS_PROXY_URL=http://proxy.example.com:8080 \
|
||||
-e NO_PROXY=localhost,.internal.example.com \
|
||||
-d oneuptime/probe:release
|
||||
|
||||
# With proxy authentication
|
||||
@@ -44,6 +46,7 @@ docker run --name oneuptime-probe --network host \
|
||||
-e ONEUPTIME_URL=https://oneuptime.com \
|
||||
-e HTTP_PROXY_URL=http://username:password@proxy.example.com:8080 \
|
||||
-e HTTPS_PROXY_URL=http://username:password@proxy.example.com:8080 \
|
||||
-e NO_PROXY=localhost,.internal.example.com \
|
||||
-d oneuptime/probe:release
|
||||
```
|
||||
|
||||
@@ -84,9 +87,11 @@ services:
|
||||
# Proxy configuration (optional)
|
||||
- HTTP_PROXY_URL=http://proxy.example.com:8080
|
||||
- HTTPS_PROXY_URL=http://proxy.example.com:8080
|
||||
- NO_PROXY=localhost,.internal.example.com
|
||||
# For proxy with authentication:
|
||||
# - HTTP_PROXY_URL=http://username:password@proxy.example.com:8080
|
||||
# - HTTPS_PROXY_URL=http://username:password@proxy.example.com:8080
|
||||
# - NO_PROXY=localhost,.internal.example.com
|
||||
network_mode: host
|
||||
restart: always
|
||||
```
|
||||
@@ -162,11 +167,15 @@ spec:
|
||||
value: "http://proxy.example.com:8080"
|
||||
- name: HTTPS_PROXY_URL
|
||||
value: "http://proxy.example.com:8080"
|
||||
- name: NO_PROXY
|
||||
value: "localhost,.internal.example.com"
|
||||
# For proxy with authentication, use:
|
||||
# - name: HTTP_PROXY_URL
|
||||
# value: "http://username:password@proxy.example.com:8080"
|
||||
# - name: HTTPS_PROXY_URL
|
||||
# value: "http://username:password@proxy.example.com:8080"
|
||||
# - name: NO_PROXY
|
||||
# value: "localhost,.internal.example.com"
|
||||
```
|
||||
|
||||
Then run the following command:
|
||||
@@ -189,6 +198,7 @@ The probe supports the following environment variables:
|
||||
#### Optional Variables
|
||||
- `HTTP_PROXY_URL` - HTTP proxy server URL for HTTP requests
|
||||
- `HTTPS_PROXY_URL` - HTTP proxy server URL for HTTPS requests
|
||||
- `NO_PROXY` - Comma-separated hosts or domains that should bypass the proxy
|
||||
- `PROBE_NAME` - Custom name for the probe
|
||||
- `PROBE_DESCRIPTION` - Description for the probe
|
||||
- `PROBE_MONITORING_WORKERS` - Number of monitoring workers (default: 1)
|
||||
@@ -199,7 +209,7 @@ The probe supports the following environment variables:
|
||||
|
||||
#### Proxy Configuration
|
||||
|
||||
The probe supports both HTTP and HTTPS proxy servers. When configured, the probe will route all monitoring traffic through the specified proxy servers.
|
||||
The probe supports both HTTP and HTTPS proxy servers. When configured, the probe will route all monitoring traffic through the specified proxy servers. You can also provide a comma-separated `NO_PROXY` list to bypass the proxy for internal hosts or networks.
|
||||
|
||||
**Proxy URL Format:**
|
||||
```
|
||||
@@ -214,9 +224,10 @@ http://[username:password@]proxy.server.com:port
|
||||
- HTTP and HTTPS proxy support
|
||||
- Proxy authentication (username/password)
|
||||
- Automatic fallback between HTTP and HTTPS proxies
|
||||
- Selective proxy bypass using `NO_PROXY`
|
||||
- Works with all monitor types (Website, API, SSL, Synthetic, etc.)
|
||||
|
||||
**Note:** Both standard environment variables (`HTTP_PROXY_URL`, `HTTPS_PROXY_URL`) and lowercase variants (`http_proxy`, `https_proxy`) are supported for compatibility.
|
||||
**Note:** Both standard environment variables (`HTTP_PROXY_URL`, `HTTPS_PROXY_URL`, `NO_PROXY`) and lowercase variants (`http_proxy`, `https_proxy`, `no_proxy`) are supported for compatibility.
|
||||
|
||||
### Verify
|
||||
|
||||
|
||||
@@ -105,6 +105,7 @@ The following table lists the configurable parameters of the OneUptime chart and
|
||||
| `probes.<key>.customCodeMonitorScriptTimeoutInMs` | Timeout for custom code monitor script | `60000` | |
|
||||
| `probes.<key>.proxy.httpProxyUrl` | HTTP proxy URL for HTTP requests made by the probe (optional) | `nil` | |
|
||||
| `probes.<key>.proxy.httpsProxyUrl` | HTTPS proxy URL for HTTPS requests made by the probe (optional) | `nil` | |
|
||||
| `probes.<key>.proxy.noProxy` | Comma-separated hosts that should bypass the proxy (optional) | `nil` | |
|
||||
| `probes.<key>.additionalContainers` | Additional containers to add to the probe pod | `nil` | |
|
||||
| `probes.<key>.resources` | Pod resources (limits, requests) | `nil` | |
|
||||
| `statusPage.cnameRecord` | CNAME record for the status page | `nil` | |
|
||||
|
||||
@@ -126,6 +126,10 @@ spec:
|
||||
- name: HTTPS_PROXY_URL
|
||||
value: {{ $val.proxy.httpsProxyUrl | squote }}
|
||||
{{- end }}
|
||||
{{- if and $val.proxy $val.proxy.noProxy }}
|
||||
- name: NO_PROXY
|
||||
value: {{ $val.proxy.noProxy | squote }}
|
||||
{{- end }}
|
||||
{{- include "oneuptime.env.oneuptimeSecret" $ | nindent 12 }}
|
||||
ports:
|
||||
- containerPort: {{ if and $val.ports $val.ports.http }}{{ $val.ports.http }}{{ else }}3874{{ end }}
|
||||
|
||||
@@ -302,6 +302,9 @@ probes:
|
||||
# Example: http://proxy.example.com:8080
|
||||
# Example with auth: http://username:password@proxy.example.com:8080
|
||||
httpsProxyUrl:
|
||||
# Comma-separated list of hosts that should bypass the proxy (optional)
|
||||
# Example: localhost,.internal.example.com,10.0.0.0/8
|
||||
noProxy:
|
||||
# KEDA autoscaling configuration based on monitor queue metrics
|
||||
keda:
|
||||
enabled: false
|
||||
@@ -337,6 +340,8 @@ probes:
|
||||
# httpProxyUrl:
|
||||
# # HTTPS proxy URL for HTTPS requests (optional)
|
||||
# httpsProxyUrl:
|
||||
# # Hosts that should bypass the proxy (optional)
|
||||
# noProxy:
|
||||
# resources:
|
||||
# additionalContainers:
|
||||
# KEDA autoscaling configuration based on monitor queue metrics
|
||||
|
||||
@@ -43,7 +43,7 @@ router.get(
|
||||
url: queueSizeUrl,
|
||||
data: requestBody,
|
||||
headers: {},
|
||||
options: { ...ProxyConfig.getRequestProxyAgents() },
|
||||
options: { ...ProxyConfig.getRequestProxyAgents(queueSizeUrl) },
|
||||
});
|
||||
|
||||
if (result instanceof HTTPErrorResponse) {
|
||||
|
||||
@@ -103,3 +103,28 @@ export const HTTP_PROXY_URL: string | null =
|
||||
*/
|
||||
export const HTTPS_PROXY_URL: string | null =
|
||||
process.env["HTTPS_PROXY_URL"] || process.env["https_proxy"] || null;
|
||||
|
||||
/*
|
||||
* NO_PROXY: Comma-separated list of hosts that should bypass the configured proxy.
|
||||
* Hosts can include optional ports (example.com:8080) or leading dots for subdomains (.example.com).
|
||||
*/
|
||||
const rawNoProxy: string | undefined =
|
||||
process.env["NO_PROXY"] || process.env["no_proxy"] || undefined;
|
||||
|
||||
export const NO_PROXY: Array<string> = rawNoProxy
|
||||
? rawNoProxy
|
||||
.split(",")
|
||||
.map((value: string) => value.trim())
|
||||
.reduce<Array<string>>((accumulator: Array<string>, current: string) => {
|
||||
if (!current) {
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
const parts: Array<string> = current
|
||||
.split(/\s+/)
|
||||
.map((item: string) => item.trim())
|
||||
.filter((item: string) => item.length > 0);
|
||||
|
||||
return accumulator.concat(parts);
|
||||
}, [])
|
||||
: [];
|
||||
|
||||
@@ -36,10 +36,14 @@ const InitJob: VoidFunction = (): void => {
|
||||
|
||||
logger.debug("Probe ID: " + probeId.toString());
|
||||
|
||||
const aliveUrl: URL = URL.fromString(PROBE_INGEST_URL.toString()).addRoute(
|
||||
"/alive",
|
||||
);
|
||||
|
||||
const result: HTTPResponse<JSONObject> = await API.post({
|
||||
url: URL.fromString(PROBE_INGEST_URL.toString()).addRoute("/alive"),
|
||||
url: aliveUrl,
|
||||
data: ProbeAPIRequest.getDefaultRequestBody(),
|
||||
options: { ...ProxyConfig.getRequestProxyAgents() },
|
||||
options: { ...ProxyConfig.getRequestProxyAgents(aliveUrl) },
|
||||
});
|
||||
|
||||
if (result.isSuccess()) {
|
||||
|
||||
@@ -101,7 +101,7 @@ class FetchListAndProbe {
|
||||
limit: PROBE_MONITOR_FETCH_LIMIT || 100,
|
||||
},
|
||||
headers: {},
|
||||
options: { ...ProxyConfig.getRequestProxyAgents() },
|
||||
options: { ...ProxyConfig.getRequestProxyAgents(monitorListUrl) },
|
||||
});
|
||||
|
||||
logger.debug("Fetched monitor list");
|
||||
|
||||
@@ -65,7 +65,7 @@ class FetchMonitorTestAndProbe {
|
||||
limit: 100,
|
||||
},
|
||||
headers: {},
|
||||
options: { ...ProxyConfig.getRequestProxyAgents() },
|
||||
options: { ...ProxyConfig.getRequestProxyAgents(monitorListUrl) },
|
||||
});
|
||||
|
||||
logger.debug("MONITOR TEST: Fetched monitor test list");
|
||||
|
||||
@@ -73,17 +73,19 @@ export default class Register {
|
||||
hostname: HOSTNAME,
|
||||
};
|
||||
|
||||
const statusReportUrl: URL = URL.fromString(
|
||||
PROBE_INGEST_URL.toString(),
|
||||
).addRoute("/probe/status-report/offline");
|
||||
|
||||
await API.fetch<JSONObject>({
|
||||
method: HTTPMethod.POST,
|
||||
url: URL.fromString(PROBE_INGEST_URL.toString()).addRoute(
|
||||
"/probe/status-report/offline",
|
||||
),
|
||||
url: statusReportUrl,
|
||||
data: {
|
||||
...ProbeAPIRequest.getDefaultRequestBody(),
|
||||
statusReport: stausReport as any,
|
||||
},
|
||||
headers: {},
|
||||
options: { ...ProxyConfig.getRequestProxyAgents() },
|
||||
options: { ...ProxyConfig.getRequestProxyAgents(statusReportUrl) },
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -131,7 +133,9 @@ export default class Register {
|
||||
probeDescription: PROBE_DESCRIPTION,
|
||||
clusterKey: ClusterKeyAuthorization.getClusterKey(),
|
||||
},
|
||||
options: { ...ProxyConfig.getRequestProxyAgents() },
|
||||
options: {
|
||||
...ProxyConfig.getRequestProxyAgents(probeRegistrationUrl),
|
||||
},
|
||||
});
|
||||
|
||||
if (result.isSuccess()) {
|
||||
@@ -149,13 +153,17 @@ export default class Register {
|
||||
return process.exit();
|
||||
}
|
||||
|
||||
const aliveUrl: URL = URL.fromString(PROBE_INGEST_URL.toString()).addRoute(
|
||||
"/alive",
|
||||
);
|
||||
|
||||
await API.post({
|
||||
url: URL.fromString(PROBE_INGEST_URL.toString()).addRoute("/alive"),
|
||||
url: aliveUrl,
|
||||
data: {
|
||||
probeKey: PROBE_KEY.toString(),
|
||||
probeId: PROBE_ID.toString(),
|
||||
},
|
||||
options: { ...ProxyConfig.getRequestProxyAgents() },
|
||||
options: { ...ProxyConfig.getRequestProxyAgents(aliveUrl) },
|
||||
});
|
||||
|
||||
LocalCache.setString("PROBE", "PROBE_ID", PROBE_ID.toString() as string);
|
||||
|
||||
@@ -63,18 +63,24 @@ export default class MonitorUtil {
|
||||
|
||||
if (result) {
|
||||
// report this back to Probe API.
|
||||
const monitorTestIngestUrl: URL = URL.fromString(
|
||||
PROBE_INGEST_URL.toString(),
|
||||
).addRoute(
|
||||
"/probe/response/monitor-test-ingest/" +
|
||||
monitorTest.id?.toString(),
|
||||
);
|
||||
|
||||
await API.fetch<JSONObject>({
|
||||
method: HTTPMethod.POST,
|
||||
url: URL.fromString(PROBE_INGEST_URL.toString()).addRoute(
|
||||
"/probe/response/monitor-test-ingest/" + monitorTest.id?.toString(),
|
||||
),
|
||||
url: monitorTestIngestUrl,
|
||||
data: {
|
||||
...ProbeAPIRequest.getDefaultRequestBody(),
|
||||
probeMonitorResponse: result as any,
|
||||
},
|
||||
headers: {},
|
||||
options: { ...ProxyConfig.getRequestProxyAgents() },
|
||||
options: {
|
||||
...ProxyConfig.getRequestProxyAgents(monitorTestIngestUrl),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -112,18 +118,21 @@ export default class MonitorUtil {
|
||||
|
||||
if (result) {
|
||||
// report this back to Probe API.
|
||||
const monitorIngestUrl: URL = URL.fromString(
|
||||
PROBE_INGEST_URL.toString(),
|
||||
).addRoute("/probe/response/ingest");
|
||||
|
||||
await API.fetch<JSONObject>({
|
||||
method: HTTPMethod.POST,
|
||||
url: URL.fromString(PROBE_INGEST_URL.toString()).addRoute(
|
||||
"/probe/response/ingest",
|
||||
),
|
||||
url: monitorIngestUrl,
|
||||
data: {
|
||||
...ProbeAPIRequest.getDefaultRequestBody(),
|
||||
probeMonitorResponse: result as any,
|
||||
},
|
||||
headers: {},
|
||||
options: { ...ProxyConfig.getRequestProxyAgents() },
|
||||
options: {
|
||||
...ProxyConfig.getRequestProxyAgents(monitorIngestUrl),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ export default class ApiMonitor {
|
||||
options: {
|
||||
timeout: options.timeout?.toNumber() || 5000,
|
||||
doNotFollowRedirects: options.doNotFollowRedirects || false,
|
||||
...ProxyConfig.getRequestProxyAgents(),
|
||||
...ProxyConfig.getRequestProxyAgents(url),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -91,7 +91,7 @@ export default class ApiMonitor {
|
||||
options: {
|
||||
timeout: options.timeout?.toNumber() || 5000,
|
||||
doNotFollowRedirects: options.doNotFollowRedirects || false,
|
||||
...ProxyConfig.getRequestProxyAgents(),
|
||||
...ProxyConfig.getRequestProxyAgents(url),
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -279,9 +279,9 @@ export default class SSLMonitor {
|
||||
// Use proxy agent if proxy is configured
|
||||
if (ProxyConfig.isProxyConfigured()) {
|
||||
const httpsProxyAgent: HttpsProxyAgent<string> | null =
|
||||
ProxyConfig.getHttpsProxyAgent();
|
||||
ProxyConfig.getHttpsProxyAgent(url);
|
||||
const httpProxyAgent: HttpProxyAgent<string> | null =
|
||||
ProxyConfig.getHttpProxyAgent();
|
||||
ProxyConfig.getHttpProxyAgent(url);
|
||||
|
||||
// Prefer HTTPS proxy agent, fall back to HTTP proxy agent
|
||||
const proxyAgent:
|
||||
|
||||
@@ -65,7 +65,7 @@ export default class WebsiteMonitor {
|
||||
isHeadRequest: options.isHeadRequest,
|
||||
timeout: options.timeout?.toNumber() || 5000,
|
||||
doNotFollowRedirects: options.doNotFollowRedirects || false,
|
||||
...ProxyConfig.getRequestProxyAgents(),
|
||||
...ProxyConfig.getRequestProxyAgents(url),
|
||||
});
|
||||
|
||||
if (
|
||||
@@ -78,7 +78,7 @@ export default class WebsiteMonitor {
|
||||
isHeadRequest: false,
|
||||
timeout: options.timeout?.toNumber() || 5000,
|
||||
doNotFollowRedirects: options.doNotFollowRedirects || false,
|
||||
...ProxyConfig.getRequestProxyAgents(),
|
||||
...ProxyConfig.getRequestProxyAgents(url),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user