Framework guidesStatic routes & 404s

Static routes and 404s

A generated content site should serve each route’s HTML and return HTTP 404 for a missing page. New lizardpack builds for Astro static, Docusaurus, VitePress, Hugo, and SvelteKit adapter-static use that policy. React and Vue SPAs keep the index.html fallback needed by browser routers.

The custom configuration below is optional. Use it for a routing policy that the detected framework does not provide. Existing images keep their old rules until you rebuild them.

Choose the routing policy

App typeRoute behavior
React or Vue SPAA valid client route loads index.html, then the client router renders it.
Generated documentation or contentA route resolves to its generated HTML; an unknown path returns HTTP 404.
Server-rendered appThe application server resolves routes and returns the status.

An SPA catch-all view can show a missing-page message, but browser code cannot change the HTTP status of the HTML response already sent. If you need route-aware HTTP status for an SPA, use a server or prerendered route setup that knows which paths exist.

Configure nginx for generated pages

Create nginx.conf at the application root:

server {
  listen 80;
  server_name _;
  root /usr/share/nginx/html;
  index index.html;
 
  location / {
    try_files $uri $uri.html $uri/ =404;
  }
 
  error_page 404 /404.html;
  location = /404.html {
    internal;
  }
}

This supports both guide.html and guide/index.html output layouts. Include a generated 404.html if you want a custom error page. Otherwise omit the error_page and exact-location blocks to use nginx’s default error body. Keep one canonical URL style in the site’s links and sitemap; this lookup rule does not add canonical redirects.

Build the site with the config

Use this complete Dockerfile for an npm project with a committed lockfile. Change BUILD_SCRIPT and OUTPUT_DIR defaults to match the table below:

FROM node:22-slim AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
ARG BUILD_SCRIPT=build
RUN npm run "$BUILD_SCRIPT"
 
FROM nginx:alpine
ARG OUTPUT_DIR=dist
COPY --from=build /app/${OUTPUT_DIR}/ /usr/share/nginx/html/
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
SiteBUILD_SCRIPTOUTPUT_DIR
Astro staticbuilddist
Docusaurusbuildbuild
VitePress with a docs/ rootdocs:builddocs/.vitepress/dist
VitePress at the project rootdocs:build or your actual script.vitepress/dist
SvelteKit with adapter-staticbuildbuild
Next.js exportbuildout
Nuxt generatebuild with nuxt generate.output/public

Use the generated-pages policy only when the app has those route files. A SvelteKit SPA fallback, for example, needs its own routing policy. Next.js static export has a complete recipe with a trailing-slash layout.

Exclude dependencies, build output, .git, and .env* in .dockerignore. If the build needs public variables, declare their ARG values before the build command. Do not copy private secrets into the image or browser output.

After CLI setup, create a service with lizard add --service web, then deploy this source with lizard up --service web --port 80. Skip the add step when the service already exists. On an existing service, check build decision order: command overrides can take precedence over the Dockerfile. A config file by itself does not replace the generated nginx configuration; the Dockerfile must copy it into the image.

Verify HTTP responses

Set SITE_URL to the actual local test URL or deployed origin, then replace /guide/ with a page that exists:

SITE_URL=https://YOUR_PUBLIC_HOST
curl -sS -o /dev/null -w '%{http_code}\n' "$SITE_URL/"
curl -sS -o /dev/null -w '%{http_code}\n' "$SITE_URL/guide/"
curl -sS -o /dev/null -w '%{http_code}\n' "$SITE_URL/this-page-does-not-exist"

Expect 200 for real pages and 404 for the missing path. If a valid route redirects to its canonical form, inspect the redirect and then verify the destination. Also test an actual asset and a made-up .js path: a missing script must not return the home page as HTML with status 200.

Finally, open the inner route directly in a browser and reload it. Correct client navigation alone can hide a server routing error. Check the framework’s canonical URL and sitemap settings alongside HTTP status before publishing an indexed site.

See tested versions and cloud results for the September 9, 2026 deployment checks and their limits.

Updated