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_SITE_URL=https://backoffice.ghabilee.ir
|
||||||
NEXT_PUBLIC_API_URL=
|
NEXT_PUBLIC_API_URL=
|
||||||
NEXT_PUBLIC_FILE_SERVER_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=
|
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
|
* local HTTP). Rewriting local HTTP Next to production Nest can therefore
|
||||||
* emit a Secure `__Host-` cookie the browser may reject. Prefer local Nest
|
* emit a Secure `__Host-` cookie the browser may reject. Prefer local Nest
|
||||||
* when testing login/refresh. See docs/reference/environment-variables.md.
|
* 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. */
|
/** Path prefix for reverse-proxy deploys (e.g. `/ghabilee`). Empty = site root. */
|
||||||
const rawBasePath = (process.env.NEXT_PUBLIC_BASE_PATH || '').trim()
|
const rawBasePath = (process.env.NEXT_PUBLIC_BASE_PATH || '').trim()
|
||||||
|
|||||||
@ -25,6 +25,21 @@ env_or_empty() {
|
|||||||
printf '%s' "${!key-}"
|
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_ARGS=(
|
||||||
--build-arg "NEXT_PUBLIC_API_URL=$(env_or_empty NEXT_PUBLIC_API_URL)"
|
--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)"
|
--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_AUTH_TOKEN=$(env_or_empty SENTRY_AUTH_TOKEN)"
|
||||||
--build-arg "SENTRY_ORG=$(env_or_empty SENTRY_ORG)"
|
--build-arg "SENTRY_ORG=$(env_or_empty SENTRY_ORG)"
|
||||||
--build-arg "SENTRY_PROJECT=$(env_or_empty SENTRY_PROJECT)"
|
--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)"
|
echo "Building ${IMAGE_REPO}:${IMAGE_TAG} (build arguments redacted)"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user