Spaces:
Runtime error
Runtime error
| # ────────────────────────────────────────────────────────────────────────────── | |
| # Exocore Docs — production Docker image | |
| # | |
| # Two-stage build: | |
| # 1. Node 20 builds the Vite + React SPA into ./dist | |
| # 2. nginx-alpine serves the static bundle (no Node runtime in the | |
| # final image — keeps it tiny: ~25 MB compressed) | |
| # | |
| # Build: | |
| # docker build -t exocore-docs:latest -f exocore-docs/Dockerfile exocore-docs | |
| # | |
| # Run (host port 8080 → container port 80): | |
| # docker run --rm -p 8080:80 exocore-docs:latest | |
| # | |
| # Hugging Face Spaces: this image works as-is on a "Docker" Space — HF | |
| # expects something on port 7860, so override at run-time: | |
| # docker run -p 7860:7860 -e PORT=7860 exocore-docs:latest | |
| # ────────────────────────────────────────────────────────────────────────────── | |
| # ───── Stage 1: build the SPA ───── | |
| FROM node:20-bookworm-slim AS builder | |
| WORKDIR /build | |
| # Cache npm install on the lockfile. | |
| COPY package*.json ./ | |
| RUN npm install --legacy-peer-deps | |
| # Pull in the rest of the project. | |
| COPY tsconfig.json vite.config.ts index.html ./ | |
| COPY public ./public | |
| COPY docs ./docs | |
| COPY src ./src | |
| RUN npm run build | |
| # ───── Stage 2: static serve via nginx ───── | |
| FROM nginx:1.27-alpine AS runtime | |
| # Drop the default nginx site and replace it with one that listens on | |
| # $PORT (defaults to 80) and serves the SPA with hash-routing fallback. | |
| RUN rm /etc/nginx/conf.d/default.conf | |
| # Create the templates directory before writing to it | |
| RUN mkdir -p /etc/nginx/templates | |
| # Inline nginx config — kept here so the image is reproducible without | |
| # any extra files outside the Docker build context. | |
| RUN printf '%s\n' \ | |
| 'server {' \ | |
| ' listen ${NGINX_PORT};' \ | |
| ' server_name _;' \ | |
| ' root /usr/share/nginx/html;' \ | |
| ' index index.html;' \ | |
| '' \ | |
| ' # Long cache on hashed assets, short cache on the entry HTML.' \ | |
| ' location /assets/ {' \ | |
| ' add_header Cache-Control "public, max-age=31536000, immutable";' \ | |
| ' try_files $uri =404;' \ | |
| ' }' \ | |
| ' location /screenshots/ {' \ | |
| ' add_header Cache-Control "public, max-age=86400";' \ | |
| ' try_files $uri =404;' \ | |
| ' }' \ | |
| '' \ | |
| ' # Hash-router SPA fallback — every unknown path returns index.html.' \ | |
| ' location / {' \ | |
| ' add_header Cache-Control "no-cache";' \ | |
| ' try_files $uri $uri/ /index.html;' \ | |
| ' }' \ | |
| '' \ | |
| ' gzip on;' \ | |
| ' gzip_types text/plain text/css application/javascript application/json image/svg+xml;' \ | |
| ' gzip_min_length 1024;' \ | |
| '}' \ | |
| > /etc/nginx/templates/default.conf.template | |
| COPY --from=builder /build/dist /usr/share/nginx/html | |
| # Default to Hugging Face's required port | |
| ENV PORT=7860 | |
| ENV NGINX_PORT=7860 | |
| # Expose the exact port Hugging Face looks for | |
| EXPOSE 7860 | |
| CMD ["sh", "-c", "export NGINX_PORT=${PORT:-7860}; exec nginx -g 'daemon off;'"] |