Crescendo Lab Docs
English
Sign up

Deploy an app from a Dockerfile

Deploy a long-running service, such as a webhook, an API or a tool for agents, from source code with a Dockerfile.

Last updated

Before you begin#

  • A program that answers HTTP requests.
  • A Dockerfile at the top of the project.

1. Write the Dockerfile#

This Node.js example listens on $PORT, exposes exactly one port, and runs as a non-root user:

Dockerfile
FROM node:22-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
USER node
EXPOSE 8080
CMD ["node", "server.js"]
server.js
import { createServer } from "node:http";

const port = Number(process.env.PORT ?? 8080);

createServer((req, res) => {
  res.writeHead(200, { "content-type": "application/json" });
  res.end(JSON.stringify({ ok: true, path: req.url }));
}).listen(port);

The image must meet these rules. The container runtime contract has the full list.

  • A CMD or ENTRYPOINT starts the server.
  • The server answers HTTP on $PORT.
  • The image is built for linux/amd64.
  • The filesystem is read-only apart from /tmp.

2. Upload the source#

On the app's Deploy tab, drop the source folder or its .zip on the upload area, then select Upload and build. The Dockerfile must be at the top. If you make the zip yourself, leave out node_modules, .git and .env:

bash
zip -r ../app.zip . -x 'node_modules/*' '.git/*' '.env*'

The platform builds the image, scans it for vulnerabilities and secrets, and checks it against the runtime contract. Anything the platform adapted shows as a notice on the version page, for example "The image runs as root, so it runs as uid 10001."

Already have an image?

Push it to your organization's image registry, then choose An image under Deploy a new version from to make a version from it.

3. Go live and check the runtime#

An app's first version goes live on its own once it builds. Later versions go live when you select Go live on the Deploy tab.

The Runtime tab shows which version is serving and how many instances are ready.

The version never becomes ready

The usual cause is the port: the server isn't listening on the port the platform gave it. See Troubleshoot failed deployments.

4. Add secrets#

Enter API keys and other secret values in the app's Settings. Your code reads them as environment variables. Saved settings apply when you restart the service, and the old instances keep serving until the new ones are ready. See App settings.

Keep secrets out of your source

If the scan finds a key in the image, take it out of the source, set it as a secret of the app instead, and rotate the key.