Cosmoner Docs
Guides

Deploy a Container Image

Run any Docker image as an app — from your Cosmoner registry, Docker Hub or the GitHub container registry — and redeploy it from CI when you push a new tag.

Overview

If you already build images, you can run one directly instead of having Cosmoner build from your repository. Any language, any base image, any build system: if it runs in a container and answers HTTP, it runs as an app.

An image app can pull from:

  • Your project registries — a Cosmoner container registry in the same project. No credentials needed, and pushes can redeploy the app automatically.
  • Docker Hub.
  • GitHub container registry (ghcr.io).

Images from other registries cannot be deployed yet.

1. Push your image

For a Cosmoner registry, the repository page in the control panel shows the exact docker login, docker tag and docker push commands for it. For Docker Hub and the GitHub container registry, push as you normally would.

Build the image for linux/amd64. On an Apple Silicon Mac, that means docker build --platform linux/amd64 … — an arm64 image will not start.

2. Create the app

In your project, go to Apps → New app, choose a domain, then select the Container Image tab.

  • From a project registry, pick it under Your registries, then the image and the Tag.
  • From Docker Hub or the GitHub container registry, choose it under Container registry and pick the image, or select Enter an image manually and type its name. For a public image, leave the credentials empty. For a private one, either connect the account, or enter a Username and a read-only Personal access token — not your account password.

Ports

Set Internal container port to the port your container listens on. That is where traffic is sent, and the container is also given it in the PORT environment variable. Both port fields default to 80, which suits images built on a web server such as nginx; an app server listening on 3000 or 8000 needs it changed.

Environment variables

Add, link and import variables the same way as for a git app — see Environment variables. They are set on the running container; nothing is rebuilt.

Then Continue, choose a plan and the number of instances, and Launch.

Deploying new versions

On push, from a project registry

An app running an image from your own registry can redeploy itself when you push. Under Deploy on push:

SettingWhat a push does
Same tagRedeploys when the tag the app runs is pushed again — e.g. you always push :latest or :production.
Newest imageDeploys every push to the repository and switches the app to its tag — e.g. you tag each build with its commit SHA.
OffNothing. You deploy from the API, the CLI or CI.

Change it later on the app's General tab, under Deploys.

From CI, with the CLI

The cosmoner CLI deploys a tag and waits until it is live, which makes it a natural last step of a pipeline:

npx @cosmoner/cli deploy web --tag "$GIT_SHA"

It exits non-zero if the rollout fails, so the pipeline fails with it. Give it an API key with apps:read and apps:write in COSMONER_API_KEY. --digest deploys one exact image instead of a tag, and with neither, the app's current tag is pulled again.

The CLI deploys images from Cosmoner registries. For Docker Hub and the GitHub container registry, redeploy through the Apps API.

Going back to an earlier version

Select Roll back on an earlier deployment in the Deployments section of the app's Overview tab. The app goes back to the exact image that deployment ran, pinned to its digest, so pushes to its tag no longer move it until you deploy a tag again. Rolling back needs the image to still be in the repository — deleting it from the registry removes that option.

From CI, deploying an earlier tag or digest does the same. Tagging images with something that identifies the build, such as the commit SHA, rather than only latest, keeps every version addressable.

Troubleshooting

The deploy never becomes healthy. Check Runtime logs. The usual cause is a port mismatch: Internal container port must be the port the process listens on. Also check the process listens on 0.0.0.0, not 127.0.0.1 — a server bound to localhost cannot be reached from outside its container.

exec format error in the logs. The image was built for another CPU architecture. Rebuild it with --platform linux/amd64.

The image cannot be read. For a private image, check the token has read access to that repository, and that the name and tag are spelled exactly as in the registry.

On this page