Static Site Serving#
Dokploy serves static sites by generating an nginx:alpine-based Docker image at deploy time. Two build types produce this image via the same shared helper: Static (raw file drop or pre-built output) and Nixpacks (when a publishDirectory is set). Both paths converge on getStaticCommand in packages/server/src/utils/builders/static.ts.
How It Works#
Static Build Type#
getStaticCommand generates a shell script that:
- Optionally writes a custom
nginx.confinto the build directory (see SPA Routing below) - Writes a
.dockerignore(excluding.git,.env,Dockerfile,.dockerignore) - Generates a
Dockerfilethat bases onnginx:alpine, setsWORKDIR /usr/share/nginx/html/, copiespublishDirectory(defaults to.) into the webroot, and starts nginx withdaemon off - Invokes
getDockerCommandwithbuildType: "dockerfile"to build and deploy the image
File creation (nginx.conf, Dockerfile, .dockerignore) is handled by getCreateFileCommand, which base64-encodes content and writes it via shell.
Nixpacks Build Type#
When an application's publishDirectory is set and buildType is Nixpacks, getNixpacksCommand adds an artifact extraction step before handing off to getStaticCommand:
--no-error-without-startis passed to nixpacks (no start command needed since nginx will serve the output)- A temporary container is created from the nixpacks-built image
- Artifacts are copied out of the container at
/app/${publishDirectory}to the host filesystem - The container is removed, then
getStaticCommand(application)is called to produce the final nginx image
This approach shrinks the final image significantly — from ~600 MB (full nixpacks build image) to ~40 MB (nginx + static files) .
The publishDirectory feature was introduced in PR #297.
SPA Routing#
When application.isStaticSpa is true, a custom nginx.conf is injected that adds try_files $uri $uri/ /index.html . This prevents 404s on page refresh for client-side routers (React Router, Vue Router, etc.) by falling back all unresolved paths to index.html.
The isStaticSpa flag is a boolean on the application model , toggled from the dashboard under Build → Static settings. It was introduced in PR #1931.
Without isStaticSpa, nginx uses its default config (no try_files override), so direct URL access to deep routes returns 404.
Key Files#
| File | Role |
|---|---|
packages/server/src/utils/builders/static.ts | Core static builder: nginx.conf, Dockerfile generation, getStaticCommand |
packages/server/src/utils/builders/nixpacks.ts | Nixpacks builder; artifact extraction + calls getStaticCommand |
packages/server/src/utils/filesystem/directory.ts | getBuildAppDirectory — resolves the host build path per source type |
packages/server/src/utils/docker/utils.ts | getCreateFileCommand — shell command generator for writing files |
packages/server/src/db/schema/application.ts | Application schema: publishDirectory, isStaticSpa fields |