mirror of
https://github.com/multica-ai/multica.git
synced 2026-06-17 03:38:32 +02:00
fix(selfhost): auto-derive WebSocket URL for LAN access (#896)
When NEXT_PUBLIC_WS_URL is not set, the WebSocket URL defaulted to ws://localhost:8080/ws. This broke real-time features (chat streaming, live updates, notifications) for self-hosted deployments accessed over LAN — the browser tried connecting to localhost on the client machine instead of the Docker host. Now the web app derives the WebSocket URL from window.location, routing through the existing Next.js /ws rewrite. This works for localhost, LAN, and custom domain setups without any extra configuration. Also adds NEXT_PUBLIC_WS_URL as a Docker build arg for explicit override, and documents LAN access configuration in SELF_HOSTING_ADVANCED.md. Closes #896
This commit is contained in:
@@ -37,8 +37,10 @@ RUN pnpm install --frozen-lockfile --offline
|
||||
# Set build-time env: tells Next.js rewrites to proxy API calls to the backend service
|
||||
ARG REMOTE_API_URL=http://backend:8080
|
||||
ARG NEXT_PUBLIC_GOOGLE_CLIENT_ID
|
||||
ARG NEXT_PUBLIC_WS_URL
|
||||
ENV REMOTE_API_URL=$REMOTE_API_URL
|
||||
ENV NEXT_PUBLIC_GOOGLE_CLIENT_ID=$NEXT_PUBLIC_GOOGLE_CLIENT_ID
|
||||
ENV NEXT_PUBLIC_WS_URL=$NEXT_PUBLIC_WS_URL
|
||||
ENV STANDALONE=true
|
||||
|
||||
# Build the web app (standalone output for minimal runtime)
|
||||
|
||||
@@ -218,6 +218,26 @@ NEXT_PUBLIC_API_URL=https://api.example.com
|
||||
NEXT_PUBLIC_WS_URL=wss://api.example.com/ws
|
||||
```
|
||||
|
||||
## LAN / Non-localhost Access
|
||||
|
||||
By default, Multica works on `localhost`. If you access it from another machine on the LAN (e.g. `http://192.168.1.100:3000`), you need to tell the backend to accept that origin:
|
||||
|
||||
```bash
|
||||
# .env — replace with your server's LAN IP
|
||||
FRONTEND_ORIGIN=http://192.168.1.100:3000
|
||||
CORS_ALLOWED_ORIGINS=http://192.168.1.100:3000
|
||||
```
|
||||
|
||||
Then rebuild:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.selfhost.yml up -d --build
|
||||
```
|
||||
|
||||
The frontend automatically derives the WebSocket URL from the page address, so real-time features (chat streaming, live issue updates, notifications) work over LAN without extra configuration.
|
||||
|
||||
> **Note:** If you need to override the WebSocket URL explicitly (e.g. when using a separate backend domain), set `NEXT_PUBLIC_WS_URL` in `.env` and rebuild the frontend image.
|
||||
|
||||
## Health Check
|
||||
|
||||
The backend exposes a health check endpoint:
|
||||
|
||||
@@ -22,12 +22,22 @@ function hasLegacyToken(): boolean {
|
||||
}
|
||||
}
|
||||
|
||||
// Derive WebSocket URL from the page origin so self-hosted / LAN deployments
|
||||
// work without explicit NEXT_PUBLIC_WS_URL. The Next.js rewrite rule
|
||||
// (/ws → backend) handles proxying.
|
||||
function deriveWsUrl(): string | undefined {
|
||||
if (process.env.NEXT_PUBLIC_WS_URL) return process.env.NEXT_PUBLIC_WS_URL;
|
||||
if (typeof window === "undefined") return undefined;
|
||||
const proto = window.location.protocol === "https:" ? "wss:" : "ws:";
|
||||
return `${proto}//${window.location.host}/ws`;
|
||||
}
|
||||
|
||||
export function WebProviders({ children }: { children: React.ReactNode }) {
|
||||
const cookieAuth = !hasLegacyToken();
|
||||
return (
|
||||
<CoreProvider
|
||||
apiBaseUrl={process.env.NEXT_PUBLIC_API_URL}
|
||||
wsUrl={process.env.NEXT_PUBLIC_WS_URL}
|
||||
wsUrl={deriveWsUrl()}
|
||||
cookieAuth={cookieAuth}
|
||||
onLogin={setLoggedInCookie}
|
||||
onLogout={clearLoggedInCookie}
|
||||
|
||||
@@ -62,6 +62,7 @@ services:
|
||||
args:
|
||||
REMOTE_API_URL: http://backend:8080
|
||||
NEXT_PUBLIC_GOOGLE_CLIENT_ID: ${NEXT_PUBLIC_GOOGLE_CLIENT_ID:-}
|
||||
NEXT_PUBLIC_WS_URL: ${NEXT_PUBLIC_WS_URL:-}
|
||||
depends_on:
|
||||
- backend
|
||||
ports:
|
||||
|
||||
Reference in New Issue
Block a user