Most apps deploy with no configuration: Nimbus Land works out how to build them (see Apps). When your language has no built-in support (Rust or .NET, for example) or you want full control over the image, put a Dockerfile at the root of your project. Nimbus Land builds it as written and runs the image like any other app.
How it is chosen#
A Dockerfile at the root of the app always wins over the automatic build for your language. A Dockerfile in a subdirectory (docker/, examples/) is ignored.
Nimbus Land still recognises the framework from your manifests, so framework defaults apply to the running app. A Rails app built from the Dockerfile that rails new writes still gets a generated SECRET_KEY_BASE and the storage volume suggestion (see Ruby).
To force the Dockerfile build, pass --builder dockerfile to nimbus deploy, set it in .nimbus.yml:
build:
builder: dockerfile
or send "builder": "dockerfile" to the build API. To publish the repository as a static site instead, see Static sites.
Checked before building#
The deploy plan reads your Dockerfile before anything is built:
- What runs is the final stage's
ENTRYPOINTandCMD. If the final stage declares anEXPOSEport other than the one your app receives traffic on, the plan notes it:Your Dockerfile declares port 8080, but the app receives traffic on port 3000. Make it listen on the PORT variable. - A
Procfileis not used. If you have one, the plan saysYour Procfile is not used when the Dockerfile builds the app. - Every
COPYandADDsource must exist in the repository. A source that matches nothing (typically build output such asdist/apiproduced by a step outside the Dockerfile) would fail the build, so a first deploy is refused before anything is created:Your Dockerfile copies dist/api, which is not in the repository. It is probably produced by a step this Dockerfile does not run.The build API returns the codecopy_source_missing. Globs are matched against your files,COPY --from=…is not checked, and.dockerignoreis not consulted for this check. Once the app has served a healthy release, this becomes a note instead of a refusal.
What your image needs#
- Listen on
PORT. Nimbus Land setsPORTand sends traffic only to it. An image that hard-codes another port builds and deploys, then never receives traffic. This is the most common Dockerfile problem.ENV PORT=3000in yourDockerfileis a fine default, because the platform's value overrides it. - Your
CMDandENTRYPOINTare used as-is. - App variables are available at run time only. They are not passed to the build as
--build-args. Give non-secret build inputsARGdefaults in theDockerfile, or move the step to run time. Never bake secrets into image layers. - There is no
.gitin the build. Builds receive your source without its.gitdirectory, soRUN git rev-parse HEADfails withnot a git repository. Pass a version through anARGdefault or compute it at run time. /bin/shis needed for commands. Release commands, one-off commands and scheduled tasks run through/bin/sh, so aFROM scratchor distroless image can't run them.
A .dockerignore at the project root is honoured.
Example: Rust#
Cargo.toml, src/main.rs and this Dockerfile are a complete app:
FROM rust:1.83-slim AS build
WORKDIR /app
COPY . .
RUN cargo build --release --locked
FROM debian:bookworm-slim
COPY --from=build /app/target/release/my-app /usr/local/bin/my-app
ENV PORT=3000
CMD ["my-app"]
Your server must read PORT. Then deploy from the project directory:
nimbus deploy
nimbus detect reports dockerfile for this project. A project with a Cargo.toml and no Dockerfile gets a note that Rust needs one.
Builds#
Each app keeps a build cache: a RUN step whose inputs haven't changed since a recent build is reused instead of run again (the build log shows Using caching version of cmd: …). Order your Dockerfile so dependency installs come before copying the rest of your source, and code-only commits rebuild quickly. If the cache can't be used, the build simply runs from scratch.
Builds run in a sandboxed environment with a fixed memory limit, and pull your base images during the build.
When a build fails, its failure reason quotes the last line of the failing step's output that reports an error, or names the step (… at step RUN mkdir /code/) when there is no such line. The full log is on the build page, which refreshes on its own while the build runs.
Troubleshooting#
The app never answers. The build succeeds and the app starts, but its address times out or returns an error, and the release never becomes healthy. The image listens on a fixed port instead of PORT. Read PORT at start-up (most servers accept a PORT variable or a flag) and deploy again.
The build ran out of memory. The failure reads The build ran out of memory (limit N GiB). with a hint for your stack, typically during next build, a large bundle or a native compile. For Node, set NODE_OPTIONS=--max-old-space-size=<MiB> in the build step (the hint suggests a value); otherwise split or trim the step that needs the memory.
A RUN step can't find a variable. App variables aren't passed to the build. Use ARG defaults, or do the work at run time.
not a git repository. There's no .git in the build. See What your image needs.
Also available as Markdown.