Framework guide

How to deploy any app with a Dockerfile

To deploy an app with a Dockerfile on Codara Cloud, put a file named exactly Dockerfile at the root of the repository (or point the app at its path), make the container listen on the PORT variable, and create an app from the GitHub repository. Codara builds that Dockerfile as written in the EU, with no buildpack in between. You can also deploy a prebuilt image from any registry.

By Codara Solutions · Reviewed

When does Codara use your Dockerfile?

When a file named exactly Dockerfile sits at the root of the build context, or when you set a Dockerfile path on the app. It takes priority over every other build strategy. Detection is case-sensitive: a lowercase dockerfile, or one in a subdirectory, is not picked up automatically and the build falls through to Railpack.

In a monorepo, set a root directory so each app builds from its own folder, and watch paths so a push only rebuilds the apps it touched. Dockerfile detection and the build context are resolved relative to the root directory.

Terminal
# A Dockerfile somewhere other than the root
codaracloud apps update api --client my-workspace --project shop \
  --dockerfile docker/api.Dockerfile

# One app per folder of a monorepo
codaracloud apps update web --client my-workspace --project shop \
  --root-directory apps/web --watch-path "apps/web/**" --watch-path "packages/**"

What should the Dockerfile do?

Build the app, then start one long-running process in the foreground that listens on 0.0.0.0 and on the PORT variable. Codara sends traffic to port 8080 by default and sets PORT to match; set another port on the app if your image cannot read PORT. A multi-stage build keeps the final image small and the build tools out of it.

Dockerfile · a Node.js API
FROM node:22-slim AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:22-slim
WORKDIR /app
ENV NODE_ENV=production
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY --from=build /app/dist ./dist
USER node
CMD ["node", "dist/server.js"]

The same pattern works for Go, Rust, Java, PHP, Ruby or anything else that runs in a Linux container. Add a .dockerignore so node_modules, .git and local .env files never enter the build context.

Build arguments or environment variables?

Build arguments reach your Dockerfile’s ARG instructions during the build (only a Dockerfile you wrote: Railpack, Nixpacks and static builds do not receive them) and are baked into image layers, so they are only for public values such as a public API URL compiled into a frontend. Up to 32 values, 1,024 characters in total. Secrets go in runtime environment variables, which the build cannot see and the container reads at start.

Terminal
# Public, build-time value (read with ARG PUBLIC_API_URL in the Dockerfile)
codaracloud apps update web --client my-workspace --project shop \
  --build-arg PUBLIC_API_URL=https://api.example.com

# Secrets, at runtime only
codaracloud env set web SESSION_SECRET=... PAYMENT_API_KEY=...

How do you create and release the app?

In the console, open Apps → New app, choose the project and environment, select GitHub repository and the branch, and submit; the wizard shows that it will build your Dockerfile before you confirm. Every push to the branch then builds and releases. Set a health check path so a release only goes live once the new container answers; if it never does, the previous release keeps serving.

Terminal · the same from the CLI
codaracloud apps create api --client my-workspace --project shop \
  --repo acme/shop-api --branch main --port 8080
codaracloud deploy api --client my-workspace --project shop --source

# Roll back to an earlier release without rebuilding
codaracloud deploys list api --client my-workspace --project shop
codaracloud rollback api --client my-workspace --project shop --to-deploy <deploy-id>

Can you deploy an image you built elsewhere?

Yes. An app can point at a container image instead of a repository, which suits images from your own CI or third-party software. Passing the same reference again pulls it again, which refreshes a moving tag such as latest. For a private registry, set credentials first; the password is read from stdin only.

Terminal
echo "$REGISTRY_TOKEN" | codaracloud apps registry set my-app \
  --username acme-ci --password-stdin
codaracloud apps image my-app ghcr.io/acme/my-app:v1.4.2

What limits should you know about?

A build may run for 30 minutes, and each build start counts toward your plan’s monthly allowance, failed builds included. Build logs are kept for 24 hours. Codara builds one image per app and does not run docker-compose.yml files: create each Compose service as its own app, and use a managed database instead of a database container. An app with a persistent volume restarts with a short gap on each release, because the disk can be mounted by one container at a time.

Questions

Do I need EXPOSE in the Dockerfile?
No. Codara sends traffic to the port configured on the app, 8080 by default, and passes it to the container as PORT. EXPOSE is documentation only.
Where are my images built and stored?
Codara builds them in its own cluster with BuildKit and stores them in its container registry in the EU. You do not need a GitHub package permission or your own registry.
Can I use Docker Compose?
Not directly. Codara deploys one image per app. Split a Compose file into separate apps in the same environment, and use Codara’s managed Postgres, MySQL, MariaDB, Redis or MongoDB for the database containers.

Keep going