The app reads its Base44 app id and backend URL from VITE_BASE44_APP_ID and VITE_BASE44_BACKEND_URL, but neither was set anywhere, so Vite compiled both defaults to undefined and app-params resolved them to null at runtime. On base44's own host these arrive as query params; on a custom domain they never do. A null serverUrl skipped the SDK's default (it only applies to undefined), making every API baseURL relative — requests hit our own nginx, which answered with index.html, and the app rendered against HTML and died. Deploys reported success while serving an empty page. appBaseUrl was never passed either, so login/logout redirects were relative too and bounced between /login and the SPA fallback. redirectToLogin also omits app_id, which base44.app/login 404s on when the request comes from our domain rather than a *.base44.app one, so login now goes through loginWithProvider. Set both vars as build args in the Dockerfile — they must be present at build time, since runtime env vars in Dokploy arrive after Vite has already inlined them. Guard the build against an empty app id and a missing dist/index.html. Surface failures instead of hiding them: an ErrorBoundary around the tree, and a diagnostic panel for auth errors that previously fell through to a crash. In nginx, serve a real 404 for missing /assets/ files. Falling through to the SPA rule returned index.html as text/html, which the browser refuses to run as a module — another silent blank page. Also add /health and stop the SPA fallback from being cached under the requested path. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
93 lines
3.0 KiB
Nginx Configuration File
93 lines
3.0 KiB
Nginx Configuration File
user nginx;
|
|
worker_processes auto;
|
|
|
|
error_log /dev/stderr warn;
|
|
pid /var/run/nginx.pid;
|
|
|
|
events {
|
|
worker_connections 1024;
|
|
}
|
|
|
|
http {
|
|
include /etc/nginx/mime.types;
|
|
default_type application/octet-stream;
|
|
|
|
access_log /dev/stdout;
|
|
|
|
sendfile on;
|
|
tcp_nopush on;
|
|
keepalive_timeout 65;
|
|
server_tokens off;
|
|
|
|
# Compression: takes the main JS bundle from ~1.9 MB down to ~530 kB on the wire
|
|
gzip on;
|
|
gzip_vary on;
|
|
gzip_proxied any;
|
|
gzip_comp_level 6;
|
|
gzip_min_length 1024;
|
|
gzip_types
|
|
text/plain
|
|
text/css
|
|
text/xml
|
|
text/javascript
|
|
application/javascript
|
|
application/json
|
|
application/xml
|
|
image/svg+xml
|
|
font/woff
|
|
font/woff2;
|
|
|
|
server {
|
|
# 80 is the conventional port; 3000 is what Dokploy targets by default in
|
|
# its domain config. Binding both means Traefik reaches the app whichever
|
|
# one the dashboard's Port field is set to, so a deploy can't 502 purely
|
|
# because those two numbers disagree.
|
|
listen 80;
|
|
listen 3000;
|
|
server_name _;
|
|
|
|
root /usr/share/nginx/html;
|
|
index index.html;
|
|
|
|
# Container liveness for Dokploy/Docker. Kept above the SPA fallback so it
|
|
# answers with a real status instead of 200-plus-index.html, which would
|
|
# make any health check pass even with the app completely broken.
|
|
location = /health {
|
|
access_log off;
|
|
add_header Content-Type text/plain;
|
|
return 200 "ok\n";
|
|
}
|
|
|
|
# Vite writes content-hashed filenames here, so they can be cached forever.
|
|
# Only add_header is used — combining it with `expires` emits two
|
|
# conflicting Cache-Control headers.
|
|
#
|
|
# try_files ending in =404 is deliberate: without it a stale index.html
|
|
# asking for an asset from a previous deploy would fall through to the
|
|
# SPA rule below and receive index.html with a 200 and a text/html type.
|
|
# The browser refuses to execute that as a module and the page renders
|
|
# empty with only a MIME error in the console — a real 404 is far easier
|
|
# to diagnose and lets a reload recover.
|
|
location /assets/ {
|
|
add_header Cache-Control "public, max-age=31536000, immutable";
|
|
access_log off;
|
|
try_files $uri =404;
|
|
}
|
|
|
|
# index.html must be revalidated every time or deploys won't take effect
|
|
location = /index.html {
|
|
add_header Cache-Control "no-cache";
|
|
}
|
|
|
|
location / {
|
|
# This line forces Nginx to pass routing back to React Router
|
|
try_files $uri $uri/ /index.html;
|
|
|
|
# The fallback is served under the requested path, so the `= /index.html`
|
|
# rule above never applies to it. Without this a proxy or browser can
|
|
# cache the old HTML and keep loading assets that no longer exist.
|
|
add_header Cache-Control "no-cache";
|
|
}
|
|
}
|
|
}
|