CI deployments

This guide deploys stable environments from CI. The branch name is the environment name: pushing to production deploys the production environment, and pushing to staging deploys staging. Deployments run behind a GitHub environment, so production can require an approval and each environment can hold its own control node credentials.

If you want a throwaway environment per pull request instead, see Preview environments.

Prerequisites

  • A control node reachable from GitHub Actions, with a deploy node registered.
  • An up.yaml describing the services of the project.
  • Control node credentials. Set UP_NODE_URL and UP_NODE_TOKEN as repository secrets when every environment uses the same control node. Set them as environment secrets on staging and production instead when the two point at different control nodes.

The staging and production environments do not need to be created ahead of time. GitHub creates an environment automatically the first time a job references it, but it starts with no secrets and no protection rules. Only a repository administrator can configure it, so plan that step before the first deploy.

Secrets

Environment secrets override repository secrets with the same name, and a job can only read an environment’s secrets after that environment’s protection rules pass. The practical setup is:

  • Repository secrets UP_NODE_URL and UP_NODE_TOKEN when staging and production share a control node. Nothing else is needed.
  • Environment secrets on staging and production when they use different control nodes. Set the same two names, and the environment value wins.

Install the workflow

Copy templates/github/deploy.yml from the up repository to .github/workflows/deploy.yml in your repository, and set branches: to the branches you deploy from. The workflow:

  • triggers on pushes to those branches, and the branch name is the environment name, so pushing to production deploys the environment named production;
  • sets environment: on the job, which applies that environment’s protection rules and secrets;
  • sets deployment: false, which keeps the gate and secrets but leaves the deployment record to the action, so the action can attach a URL. This is incompatible with custom deployment protection rules; required reviewers, wait timers, and branch and tag policies still apply;
  • uses a per-environment concurrency group, so a second push waits for the first instead of deploying at the same time.

The job calls the composite action karabohq/up/.github/actions/deploy, which installs up, creates the environment if it is missing, applies the config, lists the services, and creates the GitHub deployment with a link to the first public service URL. The action requires only environment; preview, file, comment-title, version, and go-version all have defaults, with preview defaulting to false. Pin the action reference to a commit SHA or to a release tag before relying on it in production; the repository has no release tags yet, so @main is the only moving option until the first release.

Approval gates

Protection rules live on the GitHub environment, not in the workflow file. On the production environment, add required reviewers so a deploy waits for an approval before it runs. The workflow itself does not change.

Availability depends on the plan. Environment secrets need GitHub Pro or higher for private repositories; GitHub Free only gets them on public repositories. Required reviewers and wait timers are free on public repositories but need GitHub Enterprise for private ones. Private repositories on Pro or Team can still restrict an environment to protected branches and tags, which stops feature branches from requesting a production deploy.

Public URLs for staging and uat

Production services keep the domains declared in up.yaml. A stable non-production environment cannot use those same domains without colliding with production, and there is no built-in staging domain yet. Two approaches work:

  • Derived per-environment domains: declare a base domain per stable environment, so up apply with --env staging yields web.staging.example.com from the same up.yaml. This is not implemented yet.
  • A config file per environment: keep up.staging.yaml next to up.yaml with the staging domains, and set the deploy step’s file input to up.staging.yaml for staging. This works today, but the two files must be kept in sync by hand.

Until one of these is adopted, services in staging have no public URL: they are reachable inside the environment network, and the deployment record has no link.

Deploying by hand

The template has no manual trigger. To add one, add a workflow_dispatch input for the environment and use it in place of github.ref_name for the environment name. The same environment gate applies, so a manual production deploy still waits for approval when reviewers are configured.