I’m setting up a monorepo project that serves multiple Vite apps behind Nginx using reverse proxies. My goal is to support Hot Module Replacement (HMR) in development.
What I tried
I have two Vite apps:
One served from /
One served from /app/
When I reverse-proxy the first app to /, it works fine.
But when I try to reverse-proxy the second app to /app/, I always get a “Too Many Redirects” error in the browser.
To simplify debugging, I focused on a single Vite app and configured it to be accessible via http://localhost/app/ through Nginx. But I still get the redirect loop.
Vite config
//worko-ui-react/vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import compression from "vite-plugin-compression";
import path from "path";
// https://vite.dev/config/
export default defineConfig({
plugins: [react(), compression()],
envDir: "./environments", // Manually specify the directory where the environment files are located
envPrefix: "APP_", // Manually specify the prefix for the environment variables
resolve: {
alias: {
"@": path.resolve(__dirname, "src"), // Add alias for `src`
"@Assets": path.resolve(__dirname, "src/assets/assets.ts"),
"@Components": path.resolve(__dirname, "src/components"),
"@Context": path.resolve(__dirname, "src/context"),
"@Enums": path.resolve(__dirname, "src/types/enums"),
"@Hooks": path.resolve(__dirname, "src/hooks"),
"@Interfaces": path.resolve(__dirname, "src/types/interface"),
"@Layouts": path.resolve(__dirname, "src/layouts"),
"@Pages": path.resolve(__dirname, "src/pages"),
"@Styles": path.resolve(__dirname, "src/styles"),
"@Services": path.resolve(__dirname, "src/services"),
"@Utils": path.resolve(__dirname, "src/utils"),
"@Views": path.resolve(__dirname, "src/views"),
"@Routes": path.resolve(__dirname, "src/routes.ts"),
"lib-worko-ai": path.resolve(__dirname, "../../packages/lib-worko-ai/src"),
"@LibWorko": path.resolve(__dirname, "../../packages/lib-worko-ai/src"),
},
},
optimizeDeps: {
exclude: ["lib-worko-ai"],
},
server: {
fs: {
allow: [".."],
},
proxy: {
"/cognito": {
target: "https://cognito-idp.ap-south-1.amazonaws.com",
changeOrigin: true,
rewrite: (path) => path.replace(/^/cognito/, ""),
},
},
host: "0.0.0.0", // listen on all interfaces (for proxy)
port: 3001, // ensure it runs on the expected port
strictPort: true, // do not fallback to a different port,
open: true, // Manually open the browser window upon starting the server
},
base: "/app/",
});
Routes.tsx
const AppRoutes = createBrowserRouter([
{
path: "/",
// errorElement: <ErrorFallback />,
element: <MainLayout />,
children: [
{
path: "auth/*",
element: (
<Suspense fallback={<MainLoader />}>
<AuthRouter />
</Suspense>
),
},
// {path: 'dashboard/*', element: <DashboardRedirect />},
{ path: "*", element: <PageNotFound /> },
],
{
basename:"/app",
});
export default AppRoutes;
Nginx config
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
location /app/ {
proxy_pass http://127.0.0.1:3001/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
}
}
