# Vite Dockerfile Generator

URL: /dockerizer/vite

Generate a production Dockerfile for a Vite single-page app — built on Node, served by unprivileged nginx with a proper SPA fallback.

## Default configuration

- `appName` (App name): vite — Used for the image tag, the compose service and the OCI labels.

- `port` (Port): 8080 — 8080 rather than 80 so the server never needs root to bind it. Publish it as 80 with `-p 80:8080`.

- `buildCommand` (Build script): build — The package.json script that produces your production build.

- `outputDir` (Build output directory): dist — Where your build tool writes the production bundle.

- `webServer` (Web server): nginx — Both are configured with a single-page-app fallback so deep links survive a refresh.

- `nodeVersion` (Node version): 24 — Node 24 is the active LTS line. Node 20 goes end-of-life in April 2026.

- `packageManager` (Package manager): npm — pnpm and Yarn are installed through Corepack, which reads the `packageManager` field in your package.json.

- `baseVariant` (Base image): alpine — Alpine is the smallest. Debian slim is safest if you compile native modules such as sharp, canvas or bcrypt.

- `cacheMounts` (BuildKit cache mounts): true — Persists the package manager store between builds. Repeat builds skip the download entirely.

- `multiArch` (Multi-architecture build): false — Adds BUILDPLATFORM/TARGETARCH so `docker buildx build --platform linux/amd64,linux/arm64` cross-compiles natively.

- `healthcheck` (Healthcheck): true — Adds a HEALTHCHECK so orchestrators can restart an unresponsive container.

- `tini` (tini init): false — Runs the app under tini so signals and zombie processes are handled properly.

- `ociLabels` (OCI labels): false — Adds org.opencontainers.image.* metadata to the final image.

- `buildSecret` (Build secret mount): false — Reads a private registry token via --mount=type=secret so it never lands in an image layer.

## Generated files

### Dockerfile

Multi-stage build: dependencies, compilation and the runtime image are separate, so only what the app needs at runtime ships.

```docker
# syntax=docker/dockerfile:1
# Generated by Easypanel Dockerizer — https://easypanel.io/dockerizer

# --- Build --------------------------------------------
FROM node:24-alpine AS deps
WORKDIR /app

# Manifests first: source changes must not bust the dependency cache
COPY package.json package-lock.json* ./
RUN --mount=type=cache,id=npm-store,target=/root/.npm,sharing=locked \
    npm ci --include=dev

FROM deps AS build
COPY . .
ENV NODE_ENV=production
RUN npm run build

# --- Runtime ------------------------------------------

# nginx-unprivileged runs as UID 101 and binds a high port, so no root is involved at any point
FROM nginxinc/nginx-unprivileged:stable-alpine AS runtime
COPY --from=build /app/dist/ /usr/share/nginx/html/
COPY nginx.conf /etc/nginx/conf.d/default.conf
USER nginx
EXPOSE 8080
STOPSIGNAL SIGTERM

# Lets Docker, Compose and Easypanel see when the app is wedged
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD ["wget", "-q", "--spider", "http://127.0.0.1:8080/"]
CMD ["nginx", "-g", "daemon off;"]

```

### .dockerignore

Keeps the build context small and stops secrets and local dependencies from reaching an image layer.

```bash
# Version control
.git
.gitignore
.github

# Secrets — never bake these into an image layer
.env
.env.*
!.env.example
*.pem
*.key

# Editor and OS noise
.vscode
.idea
.DS_Store
Thumbs.db

# Docs and local tooling
README.md
LICENSE
docs
.editorconfig
docker-compose*.yml
Dockerfile*
.dockerignore

# Dependencies — reinstalled inside the image from the lockfile
node_modules
**/node_modules
.pnpm-store
.yarn/cache
.yarn/unplugged
npm-debug.log*
yarn-error.log*
pnpm-debug.log*

# Test and coverage output
coverage
.nyc_output
**/*.test.ts
**/*.spec.ts

```

### nginx.conf

Serves the built assets with a single-page-app fallback, long-lived asset caching and a never-cached index.html.

```nginx
server {
    listen 8080;
    listen [::]:8080;
    server_name _;

    root /usr/share/nginx/html;
    index index.html;

    # Single-page app fallback: unknown paths render index.html so client-side
    # routes survive a refresh or a direct link.
    location / {
        try_files $uri $uri/ /index.html;
    }

    # Fingerprinted build assets are safe to cache forever.
    location ~* \.(?:js|css|woff2?|ttf|otf|eot|svg|png|jpe?g|gif|webp|avif|ico)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
        try_files $uri =404;
    }

    # index.html must never be cached or users get stuck on a stale bundle.
    location = /index.html {
        add_header Cache-Control "no-cache, no-store, must-revalidate";
    }

    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types text/plain text/css text/javascript application/javascript application/json image/svg+xml;

    # Baseline hardening
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    server_tokens off;
}

```

### docker-compose.yml

Runs the image locally with its backing services, wired together and health-gated.

```yaml
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    restart: unless-stopped
    ports:
      - "8080:8080"

```

## Frequently asked questions

### Why does my app 404 when I refresh a nested route?

Because the server looked for a file at that path and did not find one. The generated config adds `try_files $uri $uri/ /index.html`, which hands unknown paths to your client-side router instead.

### How do I inject environment variables?

Vite inlines `VITE_*` variables at build time, so they must be present during `docker build` — pass them with `--build-arg` and an `ARG`/`ENV` pair. Anything set at `docker run` time is invisible to the bundle.

### My build output goes to build/, not dist/. What do I change?

Just the output directory field above. Create React App and some older setups use `build/`; Vite defaults to `dist/`.

## Related generators

- [React](/dockerizer/react)

- [Vue](/dockerizer/vue)

- [Svelte](/dockerizer/svelte)

- [Static Site](/dockerizer/static)