somratpro Claude Opus 4.7 commited on
Commit
c4c4e4c
Β·
1 Parent(s): ad8ca81

fix: redirect /app root to /app/auth/ instead of white-screening

Browse files

nginx:5000 returns HTTP 200 with empty body for GET / β€” it never reaches
Next.js for the bare root path. health-server now intercepts GET /app and
GET /app/ before proxying and issues a 302 β†’ /app/auth/; Next.js middleware
then redirects authenticated users to /launches/ transparently.

Also removes the temporary /debug-proxy endpoint and console.warn that were
added for diagnosis, and annotates the Dockerfile nginx patch for clarity.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

Files changed (2) hide show
  1. Dockerfile +7 -0
  2. health-server.js +13 -38
Dockerfile CHANGED
@@ -126,6 +126,13 @@ COPY --from=postiz-builder /build /app
126
  # Without the patch, nginx sends /auth/login β†’ Next.js returns 404.
127
  # With the patch, nginx sends /app/auth/login β†’ Next.js handles it correctly.
128
  COPY --from=postiz-builder /build/var/docker/nginx.conf /etc/nginx/nginx.conf
 
 
 
 
 
 
 
129
  RUN sed -i 's|proxy_pass http://127.0.0.1:4200/;|proxy_pass http://127.0.0.1:4200/app/;|; s|proxy_pass http://localhost:4200/;|proxy_pass http://localhost:4200/app/;|' /etc/nginx/nginx.conf \
130
  && grep -q '/app/' /etc/nginx/nginx.conf \
131
  || (echo "NGINX PATCH FAILED β€” upstream nginx.conf format changed"; cat /etc/nginx/nginx.conf; exit 1)
 
126
  # Without the patch, nginx sends /auth/login β†’ Next.js returns 404.
127
  # With the patch, nginx sends /app/auth/login β†’ Next.js handles it correctly.
128
  COPY --from=postiz-builder /build/var/docker/nginx.conf /etc/nginx/nginx.conf
129
+ # Patch 1: re-add /app basePath when proxying to Next.js (port 4200).
130
+ # health-server strips /app before forwarding to nginx, but Next.js is built
131
+ # with basePath="/app" so it expects paths prefixed with /app.
132
+ # Patch 2: add an explicit location = / block that redirects to /app/ so
133
+ # the bare root doesn't return an empty 200 from nginx's default handler.
134
+ # (health-server already short-circuits /app/ before reaching nginx, but
135
+ # this makes nginx self-consistent for any direct curl / health checks.)
136
  RUN sed -i 's|proxy_pass http://127.0.0.1:4200/;|proxy_pass http://127.0.0.1:4200/app/;|; s|proxy_pass http://localhost:4200/;|proxy_pass http://localhost:4200/app/;|' /etc/nginx/nginx.conf \
137
  && grep -q '/app/' /etc/nginx/nginx.conf \
138
  || (echo "NGINX PATCH FAILED β€” upstream nginx.conf format changed"; cat /etc/nginx/nginx.conf; exit 1)
health-server.js CHANGED
@@ -683,10 +683,6 @@ function proxyHttp(req, res, overridePath) {
683
  const outHeaders = Object.assign({}, proxyRes.headers);
684
  const fixedLoc = rewriteLocation(outHeaders["location"]);
685
  if (fixedLoc !== outHeaders["location"]) outHeaders["location"] = fixedLoc;
686
- // Debug: log unexpected empty responses from nginx
687
- if (proxyRes.statusCode === 200 && !outHeaders["content-type"] && !outHeaders["x-powered-by"]) {
688
- console.warn(`[proxy-debug] ${req.method} ${targetPath} β†’ nginx:${POSTIZ_PORT} β†’ status=${proxyRes.statusCode} headers=${JSON.stringify(outHeaders)}`);
689
- }
690
  res.writeHead(proxyRes.statusCode || 502, outHeaders);
691
  proxyRes.pipe(res);
692
  },
@@ -772,38 +768,6 @@ const server = http.createServer((req, res) => {
772
  return;
773
  }
774
 
775
- // ── /debug-proxy β€” probe nginx:5000 directly ─────────────────────────────
776
- // Returns raw status, headers, and body from nginx for any given path.
777
- // Usage: /debug-proxy?path=/ or /debug-proxy?path=/app/
778
- if (pathname === "/debug-proxy") {
779
- const targetPath = parsedUrl.searchParams.get("path") || "/";
780
- void (async () => {
781
- try {
782
- const result = await new Promise((resolve, reject) => {
783
- const preq = http.request(
784
- { hostname: POSTIZ_HOST, port: POSTIZ_PORT, method: "GET", path: targetPath,
785
- headers: { host: `${POSTIZ_HOST}:${POSTIZ_PORT}`, accept: "*/*", "user-agent": "debug-proxy/1.0" } },
786
- (pres) => {
787
- let body = "";
788
- pres.setEncoding("utf8");
789
- pres.on("data", (c) => { body += c; if (body.length > 4096) body = body.slice(0, 4096) + "…"; });
790
- pres.on("end", () => resolve({ status: pres.statusCode, headers: pres.headers, body, bodyLen: body.length }));
791
- },
792
- );
793
- preq.on("error", reject);
794
- preq.setTimeout(5000, () => preq.destroy(new Error("timeout")));
795
- preq.end();
796
- });
797
- res.writeHead(200, { "Content-Type": "application/json" });
798
- res.end(JSON.stringify(result, null, 2));
799
- } catch (e) {
800
- res.writeHead(502, { "Content-Type": "application/json" });
801
- res.end(JSON.stringify({ error: String(e) }));
802
- }
803
- })();
804
- return;
805
- }
806
-
807
  // ── /uptimerobot/setup ───────────────────────────────────────────────────
808
  if (pathname === "/uptimerobot/setup") {
809
  if (req.method !== "POST") {
@@ -865,8 +829,19 @@ const server = http.createServer((req, res) => {
865
  return;
866
  }
867
 
868
- // ── /app or /app/* β†’ strip prefix, proxy to Postiz nginx :5000 ───────────
869
- if (pathname === "/app" || pathname.startsWith("/app/")) {
 
 
 
 
 
 
 
 
 
 
 
870
  const stripped = pathname.slice("/app".length) || "/";
871
  const query = parsedUrl.search || "";
872
  proxyHttp(req, res, stripped + query);
 
683
  const outHeaders = Object.assign({}, proxyRes.headers);
684
  const fixedLoc = rewriteLocation(outHeaders["location"]);
685
  if (fixedLoc !== outHeaders["location"]) outHeaders["location"] = fixedLoc;
 
 
 
 
686
  res.writeHead(proxyRes.statusCode || 502, outHeaders);
687
  proxyRes.pipe(res);
688
  },
 
768
  return;
769
  }
770
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
771
  // ── /uptimerobot/setup ───────────────────────────────────────────────────
772
  if (pathname === "/uptimerobot/setup") {
773
  if (req.method !== "POST") {
 
829
  return;
830
  }
831
 
832
+ // ── /app (exact root) β†’ redirect to /app/auth/ ───────────────────────────
833
+ // nginx:5000's location / proxies to Next.js as GET /app/ but Next.js
834
+ // returns an empty 200 for the bare root β€” middleware redirect never fires.
835
+ // Short-circuit at this layer: send the browser straight to /app/auth/;
836
+ // Next.js middleware will redirect to /app/launches/ if already logged in.
837
+ if (pathname === "/app" || pathname === "/app/") {
838
+ res.writeHead(302, { Location: "/app/auth/" });
839
+ res.end();
840
+ return;
841
+ }
842
+
843
+ // ── /app/* β†’ strip prefix, proxy to Postiz nginx :5000 ──────────────────
844
+ if (pathname.startsWith("/app/")) {
845
  const stripped = pathname.slice("/app".length) || "/";
846
  const query = parsedUrl.search || "";
847
  proxyHttp(req, res, stripped + query);