Serve production frontend via Nginx static build
This commit is contained in:
@@ -39,7 +39,9 @@ PROVIDER_BASE_URL_ALLOWLIST=[]
|
|||||||
|
|
||||||
PUBLIC_BASE_URL=http://localhost:8000
|
PUBLIC_BASE_URL=http://localhost:8000
|
||||||
CORS_ORIGINS=["http://localhost:5173","http://localhost:3000"]
|
CORS_ORIGINS=["http://localhost:5173","http://localhost:3000"]
|
||||||
|
# Used at build time for production frontend image, and at runtime in development.
|
||||||
VITE_API_BASE=
|
VITE_API_BASE=
|
||||||
|
# Development-only Vite host allowlist override.
|
||||||
VITE_ALLOWED_HOSTS=
|
VITE_ALLOWED_HOSTS=
|
||||||
|
|
||||||
# Optional frontend build network and npm fetch tuning:
|
# Optional frontend build network and npm fetch tuning:
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ These create an extra non-admin account on first startup.
|
|||||||
|
|
||||||
- `APP_ENV=development`: Local mode (default).
|
- `APP_ENV=development`: Local mode (default).
|
||||||
- `APP_ENV=production`: Use when running as a real shared deployment with HTTPS and tighter security settings.
|
- `APP_ENV=production`: Use when running as a real shared deployment with HTTPS and tighter security settings.
|
||||||
|
- Frontend runtime switches to a static build served by Nginx in this mode.
|
||||||
|
|
||||||
## Daily Use Commands
|
## Daily Use Commands
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ Use `.env.example` as baseline. The table below documents user-managed settings
|
|||||||
| `APP_ENV` | `development` | `production` |
|
| `APP_ENV` | `development` | `production` |
|
||||||
| `HOST_BIND_IP` | `127.0.0.1` or local LAN bind if needed | `127.0.0.1` (publish behind proxy only) |
|
| `HOST_BIND_IP` | `127.0.0.1` or local LAN bind if needed | `127.0.0.1` (publish behind proxy only) |
|
||||||
| `PUBLIC_BASE_URL` | `http://localhost:8000` | `https://api.example.com` |
|
| `PUBLIC_BASE_URL` | `http://localhost:8000` | `https://api.example.com` |
|
||||||
| `VITE_API_BASE` | empty for host-derived `http://<frontend-host>:8000/api/v1`, or explicit local URL | `https://api.example.com/api/v1` |
|
| `VITE_API_BASE` | empty for host-derived `http://<frontend-host>:8000/api/v1`, or explicit local URL | `https://api.example.com/api/v1` (build-time value for production frontend image) |
|
||||||
| `VITE_ALLOWED_HOSTS` | optional comma-separated hostnames, for example `localhost,docs.lan` | optional comma-separated public frontend hostnames, for example `app.example.com` |
|
| `VITE_ALLOWED_HOSTS` | optional comma-separated hostnames, for example `localhost,docs.lan` | optional comma-separated public frontend hostnames, for example `app.example.com` |
|
||||||
| `CORS_ORIGINS` | `["http://localhost:5173","http://localhost:3000"]` | exact frontend origins only, for example `["https://app.example.com"]` |
|
| `CORS_ORIGINS` | `["http://localhost:5173","http://localhost:3000"]` | exact frontend origins only, for example `["https://app.example.com"]` |
|
||||||
| `REDIS_URL` | `redis://:<password>@redis:6379/0` in isolated local network | `rediss://:<password>@redis.internal:6379/0` |
|
| `REDIS_URL` | `redis://:<password>@redis:6379/0` in isolated local network | `rediss://:<password>@redis.internal:6379/0` |
|
||||||
@@ -139,13 +139,14 @@ Recommended LIVE pattern:
|
|||||||
## Frontend Runtime
|
## Frontend Runtime
|
||||||
|
|
||||||
- Frontend no longer consumes `VITE_API_TOKEN`.
|
- Frontend no longer consumes `VITE_API_TOKEN`.
|
||||||
- Frontend startup mode is environment-driven:
|
- Frontend image target is environment-driven:
|
||||||
- `APP_ENV=development` runs `vite dev`
|
- `APP_ENV=development` builds the `development` target and runs Vite dev server
|
||||||
- `APP_ENV=production` runs `vite build` then `vite preview`
|
- `APP_ENV=production` builds the `production` target and serves static assets through Nginx
|
||||||
|
- Frontend Docker targets are selected from `APP_ENV`, so use `development` or `production` values.
|
||||||
- Vite dev server host allowlist uses the union of:
|
- Vite dev server host allowlist uses the union of:
|
||||||
- hostnames extracted from `CORS_ORIGINS`
|
- hostnames extracted from `CORS_ORIGINS`
|
||||||
- optional explicit hostnames from `VITE_ALLOWED_HOSTS`
|
- optional explicit hostnames from `VITE_ALLOWED_HOSTS`
|
||||||
- The same host allowlist policy is applied to both Vite `server` and `preview`.
|
- `VITE_ALLOWED_HOSTS` only affects development mode where Vite is running.
|
||||||
- Session authentication is cookie-based; browser reloads and new tabs can reuse an active session until it expires or is revoked.
|
- Session authentication is cookie-based; browser reloads and new tabs can reuse an active session until it expires or is revoked.
|
||||||
- Protected media and file download flows still use authenticated fetch plus blob/object URL handling.
|
- Protected media and file download flows still use authenticated fetch plus blob/object URL handling.
|
||||||
|
|
||||||
|
|||||||
@@ -143,15 +143,16 @@ services:
|
|||||||
frontend:
|
frontend:
|
||||||
build:
|
build:
|
||||||
context: ./frontend
|
context: ./frontend
|
||||||
|
target: ${APP_ENV:-development}
|
||||||
network: ${DOCKER_BUILD_NETWORK:-default}
|
network: ${DOCKER_BUILD_NETWORK:-default}
|
||||||
args:
|
args:
|
||||||
|
VITE_API_BASE: ${VITE_API_BASE:-}
|
||||||
NPM_REGISTRY: ${NPM_REGISTRY:-https://registry.npmjs.org/}
|
NPM_REGISTRY: ${NPM_REGISTRY:-https://registry.npmjs.org/}
|
||||||
NPM_FETCH_RETRIES: ${NPM_FETCH_RETRIES:-5}
|
NPM_FETCH_RETRIES: ${NPM_FETCH_RETRIES:-5}
|
||||||
NPM_FETCH_RETRY_MINTIMEOUT: ${NPM_FETCH_RETRY_MINTIMEOUT:-20000}
|
NPM_FETCH_RETRY_MINTIMEOUT: ${NPM_FETCH_RETRY_MINTIMEOUT:-20000}
|
||||||
NPM_FETCH_RETRY_MAXTIMEOUT: ${NPM_FETCH_RETRY_MAXTIMEOUT:-120000}
|
NPM_FETCH_RETRY_MAXTIMEOUT: ${NPM_FETCH_RETRY_MAXTIMEOUT:-120000}
|
||||||
NPM_FETCH_TIMEOUT: ${NPM_FETCH_TIMEOUT:-300000}
|
NPM_FETCH_TIMEOUT: ${NPM_FETCH_TIMEOUT:-300000}
|
||||||
environment:
|
environment:
|
||||||
APP_ENV: ${APP_ENV:-development}
|
|
||||||
VITE_API_BASE: ${VITE_API_BASE:-}
|
VITE_API_BASE: ${VITE_API_BASE:-}
|
||||||
CORS_ORIGINS: '${CORS_ORIGINS:-["http://localhost:5173","http://localhost:3000"]}'
|
CORS_ORIGINS: '${CORS_ORIGINS:-["http://localhost:5173","http://localhost:3000"]}'
|
||||||
VITE_ALLOWED_HOSTS: ${VITE_ALLOWED_HOSTS:-}
|
VITE_ALLOWED_HOSTS: ${VITE_ALLOWED_HOSTS:-}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM node:22-slim
|
FROM node:22-slim AS base
|
||||||
|
|
||||||
ARG NPM_REGISTRY=https://registry.npmjs.org/
|
ARG NPM_REGISTRY=https://registry.npmjs.org/
|
||||||
ARG NPM_FETCH_RETRIES=5
|
ARG NPM_FETCH_RETRIES=5
|
||||||
@@ -15,19 +15,35 @@ RUN npm config set registry "${NPM_REGISTRY}" \
|
|||||||
&& npm config set fetch-retry-mintimeout "${NPM_FETCH_RETRY_MINTIMEOUT}" \
|
&& npm config set fetch-retry-mintimeout "${NPM_FETCH_RETRY_MINTIMEOUT}" \
|
||||||
&& npm config set fetch-retry-maxtimeout "${NPM_FETCH_RETRY_MAXTIMEOUT}" \
|
&& npm config set fetch-retry-maxtimeout "${NPM_FETCH_RETRY_MAXTIMEOUT}" \
|
||||||
&& npm config set fetch-timeout "${NPM_FETCH_TIMEOUT}" \
|
&& npm config set fetch-timeout "${NPM_FETCH_TIMEOUT}" \
|
||||||
&& NODE_OPTIONS=--dns-result-order=ipv4first npm ci --no-audit
|
&& NODE_OPTIONS=--dns-result-order=ipv4first npm ci --no-audit \
|
||||||
RUN chown -R node:node /app
|
&& chown -R node:node /app
|
||||||
|
|
||||||
COPY --chown=node:node tsconfig.json /app/tsconfig.json
|
COPY --chown=node:node tsconfig.json /app/tsconfig.json
|
||||||
COPY --chown=node:node tsconfig.node.json /app/tsconfig.node.json
|
COPY --chown=node:node tsconfig.node.json /app/tsconfig.node.json
|
||||||
COPY --chown=node:node vite.config.ts /app/vite.config.ts
|
COPY --chown=node:node vite.config.ts /app/vite.config.ts
|
||||||
COPY --chown=node:node index.html /app/index.html
|
COPY --chown=node:node index.html /app/index.html
|
||||||
COPY --chown=node:node src /app/src
|
COPY --chown=node:node src /app/src
|
||||||
COPY --chown=node:node docker-entrypoint.sh /app/docker-entrypoint.sh
|
|
||||||
RUN chmod +x /app/docker-entrypoint.sh
|
FROM base AS development
|
||||||
|
|
||||||
EXPOSE 5173
|
EXPOSE 5173
|
||||||
|
|
||||||
USER node
|
USER node
|
||||||
|
|
||||||
CMD ["/app/docker-entrypoint.sh"]
|
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0", "--port", "5173"]
|
||||||
|
|
||||||
|
FROM base AS build
|
||||||
|
|
||||||
|
ARG VITE_API_BASE=
|
||||||
|
ENV VITE_API_BASE=${VITE_API_BASE}
|
||||||
|
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
FROM nginx:1.27-alpine AS production
|
||||||
|
|
||||||
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
COPY --from=build /app/dist /usr/share/nginx/html
|
||||||
|
|
||||||
|
EXPOSE 5173
|
||||||
|
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# Frontend runtime entrypoint.
|
|
||||||
# Uses APP_ENV to select development or production Vite startup mode.
|
|
||||||
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
APP_ENV_VALUE="${APP_ENV:-development}"
|
|
||||||
HOST_VALUE="${FRONTEND_HOST:-0.0.0.0}"
|
|
||||||
PORT_VALUE="${FRONTEND_PORT:-5173}"
|
|
||||||
|
|
||||||
if [ "$APP_ENV_VALUE" = "production" ]; then
|
|
||||||
npm run build
|
|
||||||
exec npm run preview -- --host "$HOST_VALUE" --port "$PORT_VALUE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec npm run dev -- --host "$HOST_VALUE" --port "$PORT_VALUE"
|
|
||||||
12
frontend/nginx.conf
Normal file
12
frontend/nginx.conf
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
server {
|
||||||
|
listen 5173;
|
||||||
|
listen [::]:5173;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -81,10 +81,5 @@ export default defineConfig(({ mode }) => {
|
|||||||
port: 5173,
|
port: 5173,
|
||||||
...(allowedHosts ? { allowedHosts } : {}),
|
...(allowedHosts ? { allowedHosts } : {}),
|
||||||
},
|
},
|
||||||
preview: {
|
|
||||||
host: '0.0.0.0',
|
|
||||||
port: 5173,
|
|
||||||
...(allowedHosts ? { allowedHosts } : {}),
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user