Skip to content
Deploying / Environments

Environments

A Kamal destination, and everything that hangs off one.

An environment is one Kamal destination of an app: production, staging, eu. It is the unit almost everything in KamalCloud hangs off, because it is the unit Kamal deploys.

Each environment has its own branch, machines, variables, secrets, domains, accessories, volumes, tasks and checkout on the runner.

Creating one

App → New environment. Name it and give it a branch. The name becomes the Kamal destination, so production means kamal deploy -d production and the files config/deploy.production.yml and .kamal/secrets.production.

Then place at least one host: a server pinned to a Kamal role.

The branch, and what deploys

  • branch — what gets checked out. main unless you say otherwise.
  • trigger — push deploys when that branch is pushed; tag deploys when any tag is pushed, and ships the tag rather than wherever the branch has moved on to.
  • auto-deploy — off by default. Nothing deploys from a push until you turn this on.
  • deploy paths — path patterns a push has to touch. Empty means any change counts. This is how one repository holding four apps deploys only the one that changed.

A deploy triggered by hand ships the branch head. Only a tag-triggered push deploys something other than the branch: it checks out the tag. See Deploying on push for skip markers and retries.

Submodules are off by default. Turn on Check out submodules on the app and the clone recurses into them; a submodule at another host has to accept the account’s deploy key.

Seeing the config

The app page’s deploy.yml button shows the repository’s config/deploy.yml as the git host has it, before anything is checked out. The environment’s edit page shows the file KamalCloud writes for it, so you can read what Kamal will get before you deploy.

What the page tells you

The environment page runs a check over everything it knows and sorts the result into three:

Blocked — a deploy would not work, so it is refused rather than attempted. Among them:

  • No runner, or a runner that is not ready
  • A role declared in your deploy.yml with no host placed against it – it would fall through to the repository’s own placeholder address
  • Nowhere to deploy at all
  • A secret the config names that the environment does not have
  • Hosts that disagree about the SSH user or port, which Kamal takes one of per destination
  • More than one host in the proxy role with no supplied certificate – kamal-proxy only gets its own certificate for a single host
  • The app renamed after deploying, which strands the volumes under the old service name
  • An accessory name already taken on that machine by another environment
  • A template app with no address set, where the image bakes its own URL into its data
  • No hostname on a shared machine – other apps deploy there too, and without one kamal-proxy would make this environment the default route for whatever the others did not claim

Attention — it would deploy, but you should know: the last deploy failed, the environment is in maintenance, a domain does not resolve to the right place, a supplied certificate is expiring or does not cover every hostname, a server is not running, or your deploy.yml ignores Kamal Handbook advice (see Kamal and KamalCloud).

Next — what is left to set up: KamalCloud has not deployed here yet, or there is no domain yet.

The generated domain

An environment created on a server with an IP address gets a domain straight away if you did not give one (an imported one keeps only what the proxy already answered for): a hostname under sslip.io that resolves to that IP, so the environment is reachable before you point DNS of your own at it. Add your own domain whenever you are ready.

The same rules refuse a deploy at staging time, so the page and the deploy never disagree.

Deploying

See Deployments for what each kind does. The buttons on the environment page:

  • Prepare installs Docker on the machines and writes the config and secrets, changing nothing that is running. It is what an app already deployed here by hand wants.
  • Set up and deploy does that and then deploys the branch. Once the environment is set up, the same button is Deploy.
  • Maintenance takes traffic away; Go live gives it back.
  • Reboot the app and Release the deploy lock are in the menu beside them.
  • Stop appears while a deployment is running.

Rolling back is on the Deployments list, against each earlier release.

The lock

Kamal keeps a lock file on the primary host so two deploys cannot run at once. A deploy killed partway can leave it behind. Release the deploy lock clears it. Do that only when you are sure nothing is actually deploying.

Maintenance mode

Maintenance asks for an optional message, then kamal-proxy answers every request with a 503 page carrying it. The containers keep running; the proxy simply stops sending traffic to them. Go live puts it back, and so does the next deploy.

Bare environments

An environment is bare when it has no Kamal destination. That happens when KamalCloud imports an app first deployed with a plain kamal deploy, with no -d: its containers and proxy routes carry no destination name, and adding one would strand them. A bare environment deploys with -c and one merged config file rather than with -d. See Kamal and KamalCloud.

Deleting one

Deleting an environment offers to have Kamal remove its containers first, or to leave them running. Removal is per destination, so an environment that also runs elsewhere keeps those containers.

Named Docker volumes go with it; bind mounts do not, because a directory somebody chose is often shared with things KamalCloud never deployed. As with apps, the first delete takes a farewell backup and refuses, and the second goes through.