Container runtime contract
The rules a container app's image must follow. Where the platform can adapt an image, it does, and leaves a notice on the version page.
Rules#
| Item | Requirement | If not met |
|---|---|---|
| Start command | A CMD or ENTRYPOINT. | The version is refused. |
| Port | Serve HTTP on $PORT. | Chosen from setting → EXPOSE → 8080; see App settings. |
| Platform | linux/amd64. | A push for another platform is refused. |
| User | A non-root USER is recommended. | Root or no USER runs as uid 10001, group 0. A USER the image doesn't have is refused. |
| Filesystem | Read-only apart from /tmp. | Writes elsewhere fail. |
| Cloud credentials | None are provided. | Use the app's secrets to reach outside services. |
When an image runs as uid 10001, the files it reads must be readable by group 0.
Notices#
What the platform adapted shows as notices on the version page and the image's Check tab. AI tools read the same codes from the deploy status.
| Code | Meaning | What to do |
|---|---|---|
imageUserForced | The image runs as root, so it runs as uid 10001. | Nothing. To clear the notice, set a non-root USER in the Dockerfile. |
imagePortFromExpose | The app listens on the one port the image exposes. | Nothing. |
imagePortsAmbiguous | The image exposes several ports and none is 8080, so it runs on 8080, which is probably not where the server listens. | Choose the right port in Settings › Runtime settings › Port and restart the service, or EXPOSE only that port in the Dockerfile. |
Images that write files at start-up#
Some images write outside /tmp when they start. nginx:alpine, for example, writes to /var/cache/nginx and fails on a read-only filesystem. Use an image that doesn't need to write, or move its writes to /tmp:
FROM nginxinc/nginx-unprivileged:alpine
COPY dist/ /usr/share/nginx/html/Only serving static files?
Deploy a static site instead. You don't need to run nginx yourself.