fix: use runtime BACKEND_URL for proxying

Fixes #400
This commit is contained in:
Abhishek Kumar 2026-06-03 17:21:04 +05:30
parent acc2ef9e96
commit 559d397380
4 changed files with 104 additions and 7 deletions

View file

@ -9,11 +9,6 @@ const nextConfig: NextConfig = {
},
async rewrites() {
return [
// API proxy for backend calls (excluding Next.js API routes)
{
source: "/api/:path((?!config|auth).*)*",
destination: `${process.env.BACKEND_URL || 'http://localhost:8000'}/api/:path*`,
},
{
source: "/ingest/static/:path*",
destination: "https://us-assets.i.posthog.com/static/:path*",

View file

@ -0,0 +1,98 @@
import { NextRequest, NextResponse } from "next/server";
import { getServerBackendUrl } from "@/lib/apiClient";
export const dynamic = "force-dynamic";
export const runtime = "nodejs";
const HOP_BY_HOP_HEADERS = [
"connection",
"keep-alive",
"proxy-authenticate",
"proxy-authorization",
"te",
"trailer",
"transfer-encoding",
"upgrade",
];
function trimTrailingSlash(url: string) {
return url.endsWith("/") ? url.slice(0, -1) : url;
}
function buildBackendUrl(request: NextRequest) {
const backendUrl = trimTrailingSlash(getServerBackendUrl());
return `${backendUrl}${request.nextUrl.pathname}${request.nextUrl.search}`;
}
function createRequestHeaders(request: NextRequest) {
const headers = new Headers(request.headers);
for (const header of HOP_BY_HOP_HEADERS) {
headers.delete(header);
}
headers.delete("accept-encoding");
headers.delete("content-length");
headers.delete("host");
return headers;
}
function createResponseHeaders(response: Response) {
const headers = new Headers(response.headers);
for (const header of HOP_BY_HOP_HEADERS) {
headers.delete(header);
}
headers.delete("content-encoding");
headers.delete("content-length");
return headers;
}
async function getRequestBody(request: NextRequest) {
if (request.method === "GET" || request.method === "HEAD") {
return undefined;
}
return request.arrayBuffer();
}
async function proxyRequest(request: NextRequest) {
const backendUrl = buildBackendUrl(request);
try {
const response = await fetch(backendUrl, {
method: request.method,
headers: createRequestHeaders(request),
body: await getRequestBody(request),
cache: "no-store",
});
return new Response(request.method === "HEAD" ? null : response.body, {
status: response.status,
statusText: response.statusText,
headers: createResponseHeaders(response),
});
} catch (error) {
const message =
error instanceof Error ? error.message : "Unknown backend proxy error";
return NextResponse.json(
{
detail: `Backend request failed while proxying to ${backendUrl}: ${message}`,
},
{ status: 502 },
);
}
}
export const GET = proxyRequest;
export const POST = proxyRequest;
export const PUT = proxyRequest;
export const PATCH = proxyRequest;
export const DELETE = proxyRequest;
export const OPTIONS = proxyRequest;
export const HEAD = proxyRequest;

View file

@ -1,5 +1,7 @@
import "server-only";
import { getServerBackendUrl } from "@/lib/apiClient";
let cachedAuthProvider: string | null = null;
/**
@ -12,7 +14,7 @@ export async function getAuthProvider(): Promise<string> {
}
try {
const backendUrl = process.env.BACKEND_URL || "http://localhost:8000";
const backendUrl = getServerBackendUrl();
const res = await fetch(`${backendUrl}/api/v1/health`, {
next: { revalidate: 300 },
});

View file

@ -1,6 +1,8 @@
import type { NextRequest } from 'next/server';
import { NextResponse } from 'next/server';
import { getServerBackendUrl } from '@/lib/apiClient';
const OSS_TOKEN_COOKIE = 'dograh_auth_token';
// Paths that don't require authentication in OSS mode
@ -14,7 +16,7 @@ async function fetchAuthProvider(): Promise<string> {
}
try {
const backendUrl = process.env.BACKEND_URL || 'http://localhost:8000';
const backendUrl = getServerBackendUrl();
const res = await fetch(`${backendUrl}/api/v1/health`);
if (res.ok) {
const data = await res.json();