Framework guides

Static sites and SPAs

Frameworks such as Vite, Create React App, Vue, Angular, and Astro (static mode) produce a folder of HTML, CSS, and JavaScript files. On Zenifra, a lightweight HTTP server delivers that folder.

Which path to choose

PathAdvantageBest for
GitHub + Node.js with serveNo Dockerfile, deploys on every pushMost sites and SPAs
OCI Image with NGINXFull control over caching, headers, and redirectsTeams already using NGINX or needing advanced rules

Option 1: GitHub with the Node.js runtime

Add serve as a dependency:

npm install serve

Check the folder your framework builds into:

FrameworkFolder
Vite (React, Vue, Svelte)dist
Create React Appbuild
Angular 17+dist/<project-name>/browser
Astro (static)dist

Fill in the project in the console:

FieldValue
RuntimeNode.js
Port3000
buildnpm run build
startnpx serve -s dist -l tcp://0.0.0.0:3000

Replace dist with the folder from the previous table.

The -s option makes serve answer unknown routes with index.html, which SPAs using React Router, Vue Router, or Angular Router need. For multi-page sites such as Astro, drop -s.

Environment variables in static sites

Variables such as VITE_API_URL are embedded in the JavaScript at build time. On Zenifra, project variables exist during the build, so they work normally. After changing one, deploy again to produce a new bundle. Never put secrets in these variables: they are visible in the browser.

Option 2: OCI Image with NGINX

Use the official NGINX image, which listens on port 80:

Dockerfile
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
ARG VITE_API_URL
ENV VITE_API_URL=$VITE_API_URL
RUN npm run build

FROM nginx:alpine
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
nginx.conf
server {
  listen 80;
  root /usr/share/nginx/html;

  location /assets/ {
    expires 1y;
    add_header Cache-Control "public, immutable";
  }

  location / {
    try_files $uri $uri/ /index.html;
  }
}

Build, push to your registry, and create an OCI Image project with Port 80. See Ready-made Dockerfiles for build and push commands and Deploy via OCI image for the console fields.

Domain and HTTPS

The project gets a *.clients.zenifra.com URL with HTTPS. To use your own domain, follow Custom domain.

Common problems

SymptomFix
Blank page and 404s for .js filesWrong folder in start or incorrect base in vite.config
A route such as /login returns 404 on reloadUse serve -s or try_files ... /index.html
VITE_* variable is emptyAdd it before the build and deploy again
serve: not foundserve is not in dependencies

Next steps

Last updated on

On this page