# Gyro Pipeline: automatic build and deploy on git push

https://www.gyrohosting.com/en/knowledgebase/article/gyro-containers-pipeline

- **What you will learn**: How to connect your repository to a Gyro Containers environment so that every `git push` builds the code from its Dockerfile and rolls it out to your services without downtime, how to follow the build log live and how to go back to an earlier version.
- **Time**: 10 minutes

## 1. How it works

```
git push ─▶ webhook ─▶ build (isolated environment, Dockerfile) ─▶ your private registry ─▶ services switch to the new version ─▶ health check
                                                                                                       └─ fails: back to the previous version
```

- **Source:** GitHub, GitLab, Gitea / Forgejo, Bitbucket or any git server — over https (read-only token for private repositories) **or SSH (a deploy key of the pipeline)**. Without a repository you can upload your code as a **.tar.gz / .zip archive** and build it (section 4b).
- **Build:** Every run builds your Dockerfile in its own isolated build environment. The build can reach the internet (package downloads) but not Gyro's internal networks.
- **Image:** Stored in your **Image Registry** as `registry.ist.gyrohosting.com/<environment-code>/<image>:<short-commit>` and `:latest`.
- **Deploy:** The services you choose switch to that image instance by instance, so your site stays up. If the new version fails its health check the service returns to the previous version automatically.

## 2. Create a pipeline

1. Open the **Pipeline (CI/CD)** tab of your service and click **New pipeline**.
2. Enter a **Name** and choose the **Source**: *Git repository (https)*, *Git repository (SSH, deploy key)* or *Archive upload*.
3. For https: the **Provider** and the **Repository URL** (`https://github.com/org/app`); for a private repository an **Access token** (GitHub: fine-grained token with "Contents: Read" only; GitLab: `read_repository`). It is stored encrypted and never shown in any screen or log. For SSH the address looks like `git@github.com:org/app.git`; key steps are in section 3b.
4. Set the **Branches that trigger** (e.g. `main`, `release/*`) and optionally **Tags that trigger** (e.g. `v*`).
5. Enter the **Image name** (e.g. `web`), the **Dockerfile path** and, if needed, the **Build folder**.
6. Pick one or more **Services to deploy**. Leave it empty to only build the image.
7. Click **Save**. The **webhook URL** and the **secret** are shown.

## 3. Add the webhook to your repository

**GitHub:** Repository → *Settings* → *Webhooks* → *Add webhook*: *Payload URL* = webhook URL, *Content type* = `application/json`, *Secret* = secret, **Just the push event** (tags arrive as pushes too). GitHub sends a ping at once; you should see a green tick.

**GitLab:** Project → *Settings* → *Webhooks*: *URL* = webhook URL, *Secret token* = secret, *Push events* (+ *Tag push events* to build tags).

**Gitea / Forgejo:** Repository → *Settings* → *Webhooks* → *Gitea*: target URL, `POST`, `application/json`, *Secret*, trigger *Push*.

**Your own system / other git servers:** `POST <webhook URL>` with body `{"ref":"refs/heads/main","sha":"<40 character commit>"}` and headers `X-Gyro-Timestamp: <unix seconds>`, `X-Gyro-Signature: sha256=HMAC_SHA256(secret, timestamp + "." + body)`.

**Webhook** → **Show** displays the secret again, **Rotate** replaces it (update the repository afterwards).

## 3b. Private repository: SSH deploy key

To give the pipeline a read-only **deploy key** instead of a token:

1. Choose **Git repository (SSH, deploy key)** and enter the address: `git@github.com:org/app.git` or `ssh://git@git.example.com:2222/team/app.git` (port 22, 443 or above 1024).
2. After saving, the **SSH access** box opens. Click **Create deploy key**. Gyro creates an **ed25519** key pair for this pipeline; only the **public key** and its fingerprint are shown. The private key is stored encrypted and never appears in any screen, API answer or log.
3. Add the public key to your repository as a **read-only** deploy key:
  - **GitHub:** Repository → *Settings* → *Deploy keys* → *Add deploy key* (*Allow write access* off)
  - **GitLab:** Project → *Settings* → *Repository* → *Deploy keys*
  - **Bitbucket:** *Repository settings* → *Access keys*
  - **Gitea / Forgejo:** Repository → *Settings* → *Deploy Keys*
4. **Server key (host key):** the published keys of GitHub, GitLab and Bitbucket are pinned, no confirmation needed. For your own git server click **Fetch the server key**, compare the `SHA256:` fingerprint with your administrator's record and **Confirm**. If the key changes later the build stops and warns you (man-in-the-middle protection).
5. When **Test connection** lists your branches you are ready. The webhook is set up as for https (section 3).

**Rotate** replaces the key (the old one stops working at once; replace it in the repository too), **Delete** removes it.

> For **private** repositories reached over SSH `gyro-pipeline.yml` cannot be read (the file is read from the provider's https address); use the panel settings or add a read token as well.

## 4. First run and live log

- Push a commit, or click **Run now** on the pipeline card and choose a branch or tag (`main`, `tag:v1.2.0`).
- In **Runs** the state goes *Queued → Building (fetching code / running commands / building the image) → Deploying → Health check → Succeeded*.
- The terminal icon opens the live log with separate **Fetch code**, **Build commands** and **Image build** sections. Tokens and secrets appear as `****`.
- A build server is always kept ready, so a build usually starts within seconds. When many builds run at once a second server starts in a few minutes; meanwhile you may see "waiting for a build server".

## 4b. Build from an archive (.tar.gz / .zip)

If your code is not in a git repository, or you want to build a one-off version:

1. Choose **Archive upload** as the source of a new pipeline (or use **Build from an archive** on an existing pipeline).
2. **Choose an archive** (`.tar.gz`, `.tgz` or `.zip`, at most **200 MB**) and click **Upload and build**. The file goes straight to object storage (with a progress bar), then the build starts.
3. The Dockerfile must be at the root of the archive. A single top folder (e.g. `app-main/` downloaded from GitHub) is used as the root.

Safety rules: links (symlinks / hardlinks), device files, paths starting with `/` or containing `../` and encrypted zips are refused; at most 20,000 files and 2 GB unpacked. Such an archive stops with **"The archive is unsafe or damaged"** and the reason. Uploaded archives are deleted at the latest **24 hours** later. `gyro-pipeline.yml` is not read for archive builds; the panel settings apply. The image tag is `arc-<upload-id>`.

With the API: `POST /cloud/containers/{id}/pipelines/{pipeline}/uploads {"size": <bytes>}` → `curl -T app.tar.gz "<url>"` with the returned `url` → `POST .../runs {"upload_id": "..."}`.

## 5. Build commands and gyro-pipeline.yml

To run tests or preparation steps before the Dockerfile, set **Image for build commands** (e.g. `node:22-alpine`) and one command per line under **Advanced settings**. They run in the repository root; a failing command stops the build.

- **Build variables** (`KEY=value`) and **Build secrets** are environment variables of the commands. Secrets are stored encrypted and cannot be read back.
- **Dockerfile build args** arrive as `ARG`; they are visible in the image history, so no secrets there.
- `GYRO_COMMIT` (commit) and `GYRO_REF` (branch/tag) are available to the commands.

To keep the settings next to your code, add `gyro-pipeline.yml` to the repository root (GitHub, GitLab, Gitea). When present it overrides the panel settings:

```
image: web
dockerfile: Dockerfile
context: .
build:
  image: node:22-alpine
  commands:
    - npm ci
    - npm test
  env:
    NODE_ENV: production
  args:
    APP_VERSION: "1.0"
deploy:
  services: [web, worker]
  approval: false
  rollback: true
```

## 6. Approval, stopping and rollback

- With **Ask for approval before deploying** a finished build waits in *Waiting for approval*: **Approve and deploy** or **Reject** (expires after 24 hours).
- **Stop** cancels a running run.
- **Return to this version** (back arrow) deploys the image of an earlier successful run to the target services again.
- Service rollback works too: every pipeline deployment appears as `pipeline #N` in the service's **Revisions**.

## 7. Notifications, limits and pricing

- The pipeline's **Notify** boxes (Failed, Rolled back, Waiting for approval, Succeeded) use the channels on your **Alerts** page (e-mail, SMS, Telegram, signed webhook).
- Default build resources 2 vCPU / 4 GB, time limit 20 minutes; one build at a time per environment (others queue).
- **300 build minutes per environment per month are free.** This month's use is shown at the top of the tab. Open a ticket for more minutes or parallel builds.
- Build time counts from the start of the build on the build server to its end; failures on our side are not counted.

## 8. Frequently asked questions

**Do commands that need root work?**

Yes in the build environment (isolated). Your running services start as a non-root user; make sure the image listens on a port above 1024.

**Can I use my own key as the SSH deploy key?**

No; the key is created in Gyro and its private part is never shown anywhere, so it cannot be reused elsewhere. Use **Rotate** to get a new one.

**I get "The SSH server presents a different key than the confirmed one".** Your git server's key changed or something sits in the middle. Verify the new fingerprint with your administrator, then **SSH access** → **Remove confirmation** → **Fetch the server key** → **Confirm**.

**My archive upload stopped halfway.** An upload URL is valid for 15 minutes; start again with **Build from an archive**. Incomplete uploads are never built and are deleted within 24 hours.

**Can I manage it with the API, CLI or Terraform?**

Yes: `/cloud/containers/{id}/pipelines` (archives: `.../uploads`; SSH: `.../deploy-key` and `.../host-key`), `gyro container pipeline ...` and the `gyro_container_pipeline` resource (`deploy_key = true`, `ssh_host_fingerprint`). See *Gyro Containers: API, CLI and Terraform* in the Knowledge Base.

**Is there a sample project?**

Fork `https://github.com/Gyro-Hosting/gyro-pipeline-ornek` and connect it to a `web` service on port 8080.

**The build stops with "Repository access denied".** The repository is private and there is no token or it lacks read access. Enter a new token under the pipeline's **Settings** and try **Test connection**.

**I pushed but no run started.** The branch may not match **Branches that trigger**, or **Build automatically on webhook** is off. Check the response code under *Recent Deliveries* in GitHub (202 = received, `ignored: rule` = rule did not match).

**The build succeeded but the state is "Rolled back".** The new version failed its health check (e.g. the container exits at once). The service keeps running the previous version; see the error under **Logs** → **Previous instance**.
