Migrating production infrastructure? Get up to ₹10,000 in migration credits. Apply now
voroaDocs
Deploys

Deploy a Docker app from your Dockerfile in India

Build your service from your own Dockerfile on Voroa: choose the Docker runtime, set the Dockerfile path, and make the image listen on the port Voroa provides.

Voroa normally works out how to build your service by reading your repository. When that is not enough, you can bring your own Dockerfile and describe the build yourself. That is the right choice when your service needs a system package, a language or runtime version Voroa does not detect, or a build process that does not match any standard pattern. What every Docker service includes, and what each size costs, is on Docker hosting on Voroa.

The trade is that you now own the whole build: the base image and its security updates, the layer ordering that decides how long a rebuild takes, and making sure the final image starts a process listening on the port Voroa gives it.

Create a service that builds from a Dockerfile

  1. Select New and choose a Web Service.
  2. Connect the repository and branch as usual.
  3. Under Build & runtime, set Runtime to Docker (Dockerfile).
  4. A Dockerfile path field appears. Leave it as /Dockerfile if your Dockerfile is at the top of the repository, or enter its path — for example /docker/prod.Dockerfile. The path is relative to the root directory you set for the service.
  5. Select Create. Your first build starts immediately and you can watch it in Deploys.

The Dockerfile path is chosen when the service is created and cannot be changed afterwards from Settings. If you need a different Dockerfile, either change what that path points to in your repository, or create a new service.

The port contract

Voroa decides the port and passes it to your container as the PORT environment variable, which is always 3000. Your image must start a process that listens on it.

EXPOSE in your Dockerfile does not do this. EXPOSE is documentation — metadata recorded in the image — and it does not publish a port or change what your process binds to. A Dockerfile with EXPOSE 8080 and a server hard-coded to port 8080 will build successfully and then fail to serve.

Read the port from the environment:

dockerfile
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
CMD ["node", "server.js"]
js
// server.js
const port = process.env.PORT || 3000;
app.listen(port);

If your service shows Failed to start, check that it listens on the PORT environment variable — EXPOSE alone does not publish a port.

What starts your container

The image’s own ENTRYPOINT and CMD decide what runs. The Start command field on the service does not apply to a Docker runtime service — it is used only when Voroa builds your service automatically. To change what your container runs, change the CMD in your Dockerfile.

Your process does not run as process 1 inside the container. Voroa starts every service under a small init process that passes stop signals to your app and cleans up finished child processes, so they never pile up and use up the service’s process limit. If your app handles SIGTERM, it gets that signal when a new deploy replaces it. If it does not, it stops at that point. An image that must itself be process 1, such as an image built on s6-overlay’s /init, is not supported and fails its deploy with a clear reason. If your image already starts with tini or dumb-init, it keeps working. tini may print one warning line in your logs.

Health checks

With a Docker runtime, Voroa checks your Health check path only if your image has a tool it can use to send the request: node, python3, curl or wget. Before the new version starts, Voroa looks inside the built image once and uses the first of those it finds. What decides whether a new deploy is considered ready, in order:

Situation How readiness is decided
The service has a Health check path set, and the image has node, python3, curl or wget Voroa requests that path inside your container. Any status below 400 (2xx or a redirect) counts as healthy. A path that is still answering 4xx or 5xx, or not answering, when the Startup timeout ends fails the deploy. This replaces any HEALTHCHECK in your Dockerfile.
The service has a Health check path set, but the image has none of those tools The path cannot be checked. The build log says so, and readiness falls to the rows below. Minimal images such as distroless or scratch are in this group.
Your Dockerfile declares a HEALTHCHECK Your health check decides. Voroa waits for the container to report healthy, and a container that still reports unhealthy when the Startup timeout ends fails the deploy.
Your Dockerfile declares no HEALTHCHECK Voroa checks that something is accepting connections on the port. A container that exits or restarts repeatedly fails the deploy.

A health check is worth having. Without one, “a process is running” is the strongest signal available, and a service that has started but cannot serve requests looks the same as a healthy one. If your image is minimal and has none of the tools above, add a HEALTHCHECK to your Dockerfile instead. See Health checks for what a useful endpoint checks.

Build environment variables

Environment variables you mark as available at build time are passed to the build as build arguments. Use this only for values that are safe to publish: anything passed this way is recorded in the image and can be read back by anyone who can inspect it. This is not a Voroa limitation, it is how images work.

Do not pass a token, password or private key this way. See Secrets and Docker builds.

Things to know

  • Your base image decides your language version. A service that builds from a Dockerfile takes its runtime from the FROM line you wrote - Voroa does not choose one for you, and a .nvmrc or engines.node in the repository is not read on this one because it would not be used.
  • Submodules are not supported. Voroa clones your repository at the selected branch; git submodules are not fetched, so a build that expects their contents will fail.
  • Keep the build cacheable. Copy your dependency manifest and install dependencies before copying the rest of your source, so a code-only change does not reinstall everything.
  • Build resources depend on your plan. Builds run with a memory and CPU limit; a build that exceeds it is stopped. Very large images build slowly.
  • Builds have a time limit. A build that runs past it is stopped and the deploy is marked failed, with Build timed out in the build log.
Last updated November 14, 2026