fix(deploy): reject loopback API_PROXY_TARGET in production builds
Prevents baking self-proxy /api and /chat rewrites that pin a CPU core inside Docker.
This commit is contained in:
parent
5404974c32
commit
8d2e19ac7d
@ -1,4 +1,7 @@
|
||||
NEXT_PUBLIC_SITE_URL=https://backoffice.ghabilee.ir
|
||||
NEXT_PUBLIC_API_URL=
|
||||
NEXT_PUBLIC_FILE_SERVER_URL=
|
||||
# Dev-only same-origin proxy to Nest. Leave empty in Docker/production.
|
||||
# Never use http://127.0.0.1:3000 / localhost here in a container — that is this
|
||||
# Next process and bakes a self-proxy CPU loop into the image at build time.
|
||||
API_PROXY_TARGET=
|
||||
|
||||
@ -14,8 +14,36 @@ const isProduction = process.env.NODE_ENV === 'production'
|
||||
* local HTTP). Rewriting local HTTP Next to production Nest can therefore
|
||||
* emit a Secure `__Host-` cookie the browser may reject. Prefer local Nest
|
||||
* when testing login/refresh. See docs/reference/environment-variables.md.
|
||||
*
|
||||
* Never point API_PROXY_TARGET at loopback in Docker/production: inside the
|
||||
* container 127.0.0.1:3000 is this Next process, so /api and /chat rewrites
|
||||
* become a self-proxy CPU loop. Leave empty when the browser uses a public
|
||||
* NEXT_PUBLIC_API_URL, or use the backend service hostname on a shared network.
|
||||
*/
|
||||
const apiProxyTarget = (process.env.API_PROXY_TARGET || '').replace(/\/+$/, '')
|
||||
const resolveApiProxyTarget = (raw) => {
|
||||
const trimmed = (raw || '').trim().replace(/\/+$/, '')
|
||||
if (!trimmed) return ''
|
||||
|
||||
let hostname = ''
|
||||
try {
|
||||
hostname = new URL(trimmed).hostname
|
||||
} catch {
|
||||
console.warn(`[next.config] Ignoring invalid API_PROXY_TARGET=${JSON.stringify(raw)}`)
|
||||
return ''
|
||||
}
|
||||
|
||||
const isLoopback = hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1'
|
||||
if (isLoopback) {
|
||||
console.warn(
|
||||
`[next.config] Ignoring loopback API_PROXY_TARGET=${trimmed} (points at this Next process in Docker and causes a CPU loop)`
|
||||
)
|
||||
return ''
|
||||
}
|
||||
|
||||
return trimmed
|
||||
}
|
||||
|
||||
const apiProxyTarget = resolveApiProxyTarget(process.env.API_PROXY_TARGET)
|
||||
|
||||
/** Path prefix for reverse-proxy deploys (e.g. `/ghabilee`). Empty = site root. */
|
||||
const rawBasePath = (process.env.NEXT_PUBLIC_BASE_PATH || '').trim()
|
||||
|
||||
@ -25,6 +25,21 @@ env_or_empty() {
|
||||
printf '%s' "${!key-}"
|
||||
}
|
||||
|
||||
# Loopback targets bake self-proxy rewrites into the image and peg a CPU core in Docker.
|
||||
sanitize_api_proxy_target() {
|
||||
local target
|
||||
target="$(env_or_empty API_PROXY_TARGET)"
|
||||
case "$target" in
|
||||
*127.0.0.1*|*localhost*|*'::1'*)
|
||||
echo "Warning: refusing loopback API_PROXY_TARGET for production image build" >&2
|
||||
printf ''
|
||||
;;
|
||||
*)
|
||||
printf '%s' "$target"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
BUILD_ARGS=(
|
||||
--build-arg "NEXT_PUBLIC_API_URL=$(env_or_empty NEXT_PUBLIC_API_URL)"
|
||||
--build-arg "NEXT_PUBLIC_FILE_SERVER_URL=$(env_or_empty NEXT_PUBLIC_FILE_SERVER_URL)"
|
||||
@ -41,7 +56,7 @@ BUILD_ARGS=(
|
||||
--build-arg "SENTRY_AUTH_TOKEN=$(env_or_empty SENTRY_AUTH_TOKEN)"
|
||||
--build-arg "SENTRY_ORG=$(env_or_empty SENTRY_ORG)"
|
||||
--build-arg "SENTRY_PROJECT=$(env_or_empty SENTRY_PROJECT)"
|
||||
--build-arg "API_PROXY_TARGET=$(env_or_empty API_PROXY_TARGET)"
|
||||
--build-arg "API_PROXY_TARGET=$(sanitize_api_proxy_target)"
|
||||
)
|
||||
|
||||
echo "Building ${IMAGE_REPO}:${IMAGE_TAG} (build arguments redacted)"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user