feat: frontend docker to use nextjs production build

- Damn this made things fast af.
This commit is contained in:
DESKTOP-RTLN3BA\$punk 2025-10-23 20:37:01 -07:00
parent 420e2b62eb
commit d5ccced6b9
7 changed files with 103 additions and 41 deletions

View file

@ -6,7 +6,9 @@ FLOWER_PORT=5555
# Frontend Configuration
FRONTEND_PORT=3000
NEXT_PUBLIC_API_URL=http://backend:8000
NEXT_PUBLIC_FASTAPI_BACKEND_URL=http://localhost:8000 (Default: http://localhost:8000)
NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE=LOCAL or GOOGLE (Default: LOCAL)
NEXT_PUBLIC_ETL_SERVICE=UNSTRUCTURED or LLAMACLOUD or DOCLING (Default: DOCLING)
# Backend Configuration
BACKEND_PORT=8000

View file

@ -38,7 +38,8 @@ services:
ports:
- "${BACKEND_PORT:-8000}:8000"
volumes:
- ./surfsense_backend:/app
- ./surfsense_backend/app:/app/app
- ./surfsense_backend/scripts:/app/scripts:ro
- shared_temp:/tmp
env_file:
- ./surfsense_backend/.env
@ -111,17 +112,17 @@ services:
# - celery_worker
frontend:
# build: ./surfsense_web
image: ghcr.io/modsetter/surfsense_ui:latest
build:
context: ./surfsense_web
# image: ghcr.io/modsetter/surfsense_ui:latest
args:
NEXT_PUBLIC_FASTAPI_BACKEND_URL: ${NEXT_PUBLIC_FASTAPI_BACKEND_URL:-http://localhost:8000}
NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE: ${NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE:-LOCAL}
NEXT_PUBLIC_ETL_SERVICE: ${NEXT_PUBLIC_ETL_SERVICE:-DOCLING}
ports:
- "${FRONTEND_PORT:-3000}:3000"
volumes:
- ./surfsense_web:/app
- /app/node_modules
env_file:
- ./surfsense_web/.env
environment:
- NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL:-http://backend:8000}
depends_on:
- backend

View file

@ -11,17 +11,23 @@ cleanup() {
trap cleanup SIGTERM SIGINT
echo "Starting Celery Beat..."
celery -A app.celery_app beat --loglevel=info &
celery_beat_pid=$!
echo "Starting FastAPI Backend..."
python main.py &
backend_pid=$!
# Wait a bit for backend to initialize
sleep 5
echo "Starting Celery Worker..."
celery -A app.celery_app worker --loglevel=info --concurrency=1 --pool=solo &
celery_worker_pid=$!
echo "Starting FastAPI Backend..."
python main.py --reload &
backend_pid=$!
# Wait a bit for worker to initialize
sleep 3
echo "Starting Celery Beat..."
celery -A app.celery_app beat --loglevel=info &
celery_beat_pid=$!
echo "All services started. PIDs: Backend=$backend_pid, Worker=$celery_worker_pid, Beat=$celery_beat_pid"

View file

@ -8,8 +8,7 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
Dockerfile
.dockerignore
node_modules
README.md

View file

@ -1,32 +1,79 @@
FROM node:20-alpine
# syntax=docker.io/docker/dockerfile:1
FROM node:20-alpine AS base
# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Install pnpm
RUN npm install -g pnpm
RUN corepack enable pnpm
# Copy package files
COPY package.json pnpm-lock.yaml ./
COPY package.json pnpm-lock.yaml* .npmrc* ./
# First copy the config file to avoid fumadocs-mdx postinstall error
# First copy the config file and content to avoid fumadocs-mdx postinstall error
COPY source.config.ts ./
COPY content ./content
# Install dependencies with --ignore-scripts to skip postinstall
RUN pnpm install --ignore-scripts
# Install dependencies with frozen lockfile
RUN pnpm i --frozen-lockfile
# Now run the postinstall script manually
RUN pnpm fumadocs-mdx
# Copy source code
# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
# Enable pnpm
RUN corepack enable pnpm
# Accept build arguments for Next.js public env vars
ARG NEXT_PUBLIC_FASTAPI_BACKEND_URL
ARG NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE
ARG NEXT_PUBLIC_ETL_SERVICE
# Set them as environment variables for the build
ENV NEXT_PUBLIC_FASTAPI_BACKEND_URL=$NEXT_PUBLIC_FASTAPI_BACKEND_URL
ENV NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE=$NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE
ENV NEXT_PUBLIC_ETL_SERVICE=$NEXT_PUBLIC_ETL_SERVICE
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Build app for production
# For development, we'll mount the source code as a volume
# so the build step will be skipped in development mode
# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
# ENV NEXT_TELEMETRY_DISABLED=1
RUN pnpm run build
# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
# Uncomment the following line in case you want to disable telemetry during runtime.
# ENV NEXT_TELEMETRY_DISABLED=1
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
# Start Next.js in development mode by default
# This will be faster for development since we're mounting the code as a volume
CMD ["pnpm", "dev"]
ENV PORT=3000
# server.js is created by next build from the standalone output
# https://nextjs.org/docs/pages/api-reference/config/next-config-js/output
ENV HOSTNAME="0.0.0.0"
CMD ["node", "server.js"]

View file

@ -71,7 +71,11 @@ Before you begin, ensure you have:
| POSTGRES_DB | PostgreSQL database name | surfsense |
| PGADMIN_DEFAULT_EMAIL | Email for pgAdmin login | admin@surfsense.com |
| PGADMIN_DEFAULT_PASSWORD | Password for pgAdmin login | surfsense |
| NEXT_PUBLIC_API_URL | URL of the backend API (used by frontend) | http://backend:8000 |
| NEXT_PUBLIC_FASTAPI_BACKEND_URL | URL of the backend API (used by frontend during build and runtime) | http://localhost:8000 |
| NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE | Authentication method for frontend: `LOCAL` or `GOOGLE` | LOCAL |
| NEXT_PUBLIC_ETL_SERVICE | Document parsing service for frontend UI: `UNSTRUCTURED`, `LLAMACLOUD`, or `DOCLING` | DOCLING |
**Note:** Frontend environment variables with the `NEXT_PUBLIC_` prefix are embedded into the Next.js production build at build time. Since the frontend now runs as a production build in Docker, these variables must be set in the root `.env` file (Docker-specific configuration) and will be passed as build arguments during the Docker build process.
**Backend Environment Variables:**
@ -148,11 +152,13 @@ For more details, see the [Uvicorn documentation](https://www.uvicorn.org/#comma
### Frontend Environment Variables
| ENV VARIABLE | DESCRIPTION |
| ------------------------------- | ---------------------------------------------------------- |
| NEXT_PUBLIC_FASTAPI_BACKEND_URL | URL of the backend service (e.g., `http://localhost:8000`) |
| NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE | Same value as set in backend AUTH_TYPE i.e `GOOGLE` for OAuth with Google, `LOCAL` for email/password authentication |
| NEXT_PUBLIC_ETL_SERVICE | Document parsing service (should match backend ETL_SERVICE): `UNSTRUCTURED`, `LLAMACLOUD`, or `DOCLING` - affects supported file formats in upload interface |
**Important:** Frontend environment variables are now configured in the **Docker-Specific Environment Variables** section above since the Next.js application runs as a production build in Docker. The following `NEXT_PUBLIC_*` variables should be set in your root `.env` file:
- `NEXT_PUBLIC_FASTAPI_BACKEND_URL` - URL of the backend service
- `NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE` - Authentication method (`LOCAL` or `GOOGLE`)
- `NEXT_PUBLIC_ETL_SERVICE` - Document parsing service (should match backend `ETL_SERVICE`)
These variables are embedded into the application during the Docker build process and affect the frontend's behavior and available features.
2. **Build and Start Containers**

View file

@ -2,6 +2,7 @@ import { createMDX } from "fumadocs-mdx/next";
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
output: "standalone",
typescript: {
ignoreBuildErrors: true,
},