# Git Deploy

> Connect your server to a GitHub, GitLab, Gitea or Forgejo repository and deploy automatically on every push, release or tag, with protected paths, restarts, CI checks and one-click rollback.

The **Git Deploy** tab in the Portal connects your server to a Git repository on **GitHub**, **GitLab**, **Gitea** or **Forgejo**. Its files are copied to your server automatically — on every push, when you publish a release, when you push a tag, or at the click of a button. If you like, your server is stopped cleanly before the deploy and started again afterwards.

In short: push your code, and a few seconds later it runs on your server. No more uploading via SFTP, no unpacking ZIP files in the file manager, no forgotten restarts.

## What you'll learn

- How to connect a repository, with the Daki Git Deploy GitHub app or with an access token
- When a deploy runs and how to trigger one yourself
- How to keep worlds, databases and `.env` files safe with protected paths
- How restarts, the deploy history, rollbacks and the status in your repository work
- How to give your team the right permissions

---

## Who It's For

- **Developers of Discord bots and Node.js, Python or Java apps** whose code already lives on GitHub or GitLab.
- **Minecraft networks and game server teams** who keep plugins, configs or datapacks in a repository and want changes to roll out in a traceable way.
- **Teams:** several people work in the repository, the server is always up to date, and sub-user permissions decide exactly who can deploy.
- **Release-based projects:** only published versions (for example a finished `.jar` from a release) end up on the server, not every work in progress.

---

## Before You Start

- A server in the Portal that shows the **Git Deploy** tab. It sits in the server navigation under **Essentials**, right after **Files** by default.
- A repository on GitHub (github.com), GitLab (gitlab.com or your own instance, subgroups such as `group/subgroup/project` included), Gitea or Forgejo (for example Codeberg or your own instance). Public and private repositories both work.

> **Note:** Daki decides per server type (egg) whether the tab is shown. If you don't see **Git Deploy**, it isn't enabled for your server's type.

> **Info:** This guide uses the English labels of the Git Deploy tab. The tab is available in 19 languages and follows the language you've chosen in the Portal — the buttons are in the same place in every language.

---

## Quick Start with GitHub (Recommended)

The quickest way: connect through **Daki Git Deploy**, the official GitHub app of Daki Hosting. You sign in on GitHub and choose your repositories — **no token and no webhook** needed.

**Step 1: Open the Git Deploy tab**

In the Portal, open your server and go to the **Git Deploy** tab. Under **Git service**, choose **GitHub**.

**Step 2: Connect with GitHub**

In the **GitHub access** box, click **Connect with GitHub**. Sign in on GitHub and authorize the app.

The first time, GitHub then takes you straight on to choosing which repositories the app may access (**All repositories** or only selected ones) — one pass instead of two. Afterwards you land back in the Portal, and the **GitHub access** box shows **Connected via Daki Git Deploy as** your GitHub name. The **Webhook** box confirms that there's nothing to set up: pushes and releases arrive through the app by themselves.

**Step 3: Choose your repository and branch**

Click **Choose from my repositories** and pick your repository — or paste the web or clone URL, or type the path. Click **Load branches** and choose the branch to deploy. Leave the branch empty to use the repository's default branch.

**Step 4: Choose when and how to deploy**

Under **When to deploy**, choose a mode (for example **Every push**). Then set the target folder, your [protected paths](#protected-paths) and the [restart behavior](#restart-behavior).

**Step 5: Save**

Click **Save settings** in the bar at the bottom. That's it: the header of the tab shows **Automatic deploys on**, and your next push is deployed automatically. To deploy right away, click **Deploy now** at the top right.

- **Allow another repository:** **Choose repositories on GitHub** opens the repository selection on GitHub again, where you choose which repositories Daki Git Deploy may access.
- **Remove the connection:** click **Disconnect**. The server then no longer deploys from private repositories.

> **Tip:** You never have to renew anything. For every deploy, the Portal fetches a fresh, short-lived key from GitHub (valid for 1 hour) that only reaches your server's one repository. This happens in the background.

---

## Quick Start with an Access Token

For **GitLab**, **Gitea** and **Forgejo** — and for GitHub if you prefer — you save a personal access token. Public repositories work without any token at all.

**Step 1: Choose the Git service**

Open your server → **Git Deploy** and choose the **Git service**. For your own GitLab instance, Gitea or Forgejo, enter the server URL (for example `https://codeberg.org` or `https://git.example.com`). For gitlab.com, leave it empty.

**Step 2: Enter the repository**

Enter the repository as a path (`owner/name`) or simply paste its web or clone URL. For a **public** repository, that's all you need — without a token, the access box shows **No token – public repositories only**.

**Step 3: Save a token for private repositories**

With GitHub, first click **Use an own access token instead** in the **GitHub access** box. Then create a token on your Git provider — the **Create a token on …** link in the Portal takes you straight to the right page — and save it under **Personal access token**. The Portal checks the token immediately. See [Token Permissions](#token-permissions) for the rights it needs.

**Step 4: Choose your settings and save**

Choose when to deploy, the target folder, protected paths and the restart behavior, then click **Save settings**.

**Step 5: Add the webhook**

The **Webhook** box shows the **Payload URL** and the **Secret**, each with a copy button. Add them to your repository as described in [Set Up the Webhook](#set-up-the-webhook). Below the box, **Last delivery** then shows whether the webhook arrives.

**Step 6: Turn on automatic deploys**

Switch on **Automatic deploys active**.

### Token Permissions

| Provider | Token type | Rights for deploys | Also needed for the status in your repository |
| :--- | :--- | :--- | :--- |
| GitHub | Fine-grained token, only for this repository | *Contents: Read-only* (for **Wait for CI checks** also *Actions: Read-only*) | *Commit statuses* and *Deployments*: *Read and write* |
| GitLab | Personal, project or group access token | `read_api` + `read_repository` | `api` instead of `read_api`, role Developer |
| Gitea / Forgejo | Settings → Applications | `repository: Read`, `user: Read` | `repository: Read and Write` |

If only the write permission for the status is missing, your server is still deployed — the deploy log shows a note.

### Set Up the Webhook

**GitHub**

In your repository, go to **Settings → Webhooks → Add webhook**:

1. Paste the **Payload URL** and the **Secret** from the Portal.
2. Set the content type to `application/json`.
3. Under events, choose **Just the push event**. In release mode, choose **Releases** instead.

**GitLab**

In your project, go to **Settings → Webhooks**:

1. Paste the **Payload URL** as the URL and the **Secret** under **Secret token**.
2. Under triggers, select **Push events**. In tag mode, select **Tag push events**; in release mode, **Releases events**.

**Gitea / Forgejo**

In your repository, go to **Settings → Webhooks → Add webhook** and choose Gitea or Forgejo:

1. Paste the **Payload URL**, set the content type to `application/json` and enter the **Secret**.
2. Choose **Push events**, or in release mode **Custom events → Release**.

> **Tip:** Your Git provider can't reach the Portal, for example because your Gitea instance runs in your home network? Choose an interval under **Also check … for updates** instead (for example **Also check Gitea for updates**). The first check deploys the current state once.

---

## When a Deploy Runs

Under **When to deploy**, choose one of four modes:

| Mode | What gets deployed |
| :--- | :--- |
| **Manual** | Only when someone clicks **Deploy now**. |
| **Every push** | Every push to the chosen branch. |
| **Releases** | Only when a release is published. Deploy either the release's **source code** or a **release file** (for example `*.jar`) — optionally saved under a fixed name (for example `server.jar`) and optionally extracted if it's a `.zip`. Pre-releases can be included or left out. |
| **Tags** | When a tag is pushed that matches a pattern, for example `v*`. |

### Triggers

- **Webhook:** your Git provider reports changes immediately, and the deploy starts within seconds. With the GitHub app this happens automatically, without a webhook of your own.
- **Update checks (polling):** optional, for cases where your Git provider can't reach the Portal. Intervals from 5 minutes to 1 day.
- **Deploy now:** at any time, at the click of a button. In release mode you can pick a specific release.
- **Skip a push:** put `[skip deploy]` in the commit message and that push isn't deployed. `[deploy skip]` and `[no deploy]` work too.

### Wait for CI Checks

With **Wait for CI checks** turned on (only in **Every push** mode), a commit is deployed only once its CI is green — GitHub Actions, GitLab CI and Gitea/Forgejo Actions are supported. If the CI fails, the deploy is skipped.

---

## All Settings Explained

| Section | Setting | What it does |
| :--- | :--- | :--- |
| Repository | **Git service** | GitHub, GitLab, Gitea or Forgejo |
| Repository | **Server URL** | Only for self-hosted instances; must be reachable from the internet |
| Repository | **Repository** | `owner/name` or a URL; **Choose from my repositories** shows a list |
| Repository | **Branch** | Empty = default branch; **Load branches** shows a list |
| When to deploy | **Manual** / **Every push** / **Releases** / **Tags** | See [When a Deploy Runs](#when-a-deploy-runs) |
| When to deploy | **Wait for CI checks** | Only with **Every push** |
| When to deploy | **Include pre-releases**, **What to deploy** (**Source code** / **Release file**), **Save as**, **Extract .zip files instead of uploading them** | Only with **Releases** |
| When to deploy | **Tag pattern** | Only with **Tags**, for example `v*`; empty = every tag |
| When to deploy | **Also check … for updates** (named after your Git service, e.g. **Also check GitHub for updates**) | Polling: **Never (webhook only)**, 5/10/15/30 min, 1/3/6/12/24 h |
| When to deploy | **Automatic deploys active** | Off pauses webhook and polling; **Deploy now** keeps working |
| When to deploy | **Show deploys in the repository** | Status on the commit, see [Status in Your Repository](#status-in-your-repository) |
| Files | **Folder in the repository** | Only deploy a subfolder, for example `dist`; empty = everything |
| Files | **Target folder on the server** | Where the files go; `/` = your server's main folder |
| Files | **Protected paths** | One rule per line, see [Protected Paths](#protected-paths) |
| Files | **Remove files that were deleted from the repository** | Optional clean-up, see below |
| Restart | **Restart if running** / **Always start** / **Do not restart** | See [Restart Behavior](#restart-behavior) |
| Restart | **If the server does not stop** | Kill immediately, or after 5 s, 10 s (default: **Kill after 10 seconds**), 15 s, 30 s, 1 min, 2 min or 5 min |

Changes only take effect once you click **Save settings**. While something is unsaved, a bar at the bottom shows **Discard** and **Save settings**, and **Deploy now** is locked.

**Remove files that were deleted from the repository** only removes files that an earlier deploy wrote itself — never protected paths and never files you created yourself. Empty folders stay in place.

---

## Protected Paths

Files and folders under **Protected paths** are **never overwritten or deleted** by a deploy. If they don't exist yet, they're created once. Perfect for game worlds, databases and passwords.

Write one rule per line, relative to the target folder. Empty lines and lines starting with `#` are ignored. `*` never matches across a `/`.

| Rule | Protects |
| :--- | :--- |
| `world/` | Every folder named `world`, at any depth |
| `/world/` | Only `world` directly in the target folder |
| `*.db` | Every file ending in `.db`, anywhere |
| `.env` | Every file named `.env`, anywhere |
| `/config.yml` | Only `config.yml` directly in the target folder |
| `plugins/*/config.yml` | `config.yml` in every direct subfolder of `plugins` |

Typical examples:

**Minecraft**

```

world/

world_nether/

world_the_end/

plugins/*/config.yml

whitelist.json

ops.json

banned-*.json

```

**Discord bot / Node.js**

```

.env

*.db

*.sqlite

node_modules/

data/

```

**Python**

```

.env

*.db

venv/

```

---

## Restart Behavior

| Option | What happens |
| :--- | :--- |
| **Restart if running** | The server is stopped before the files are written and started again afterwards. A server that's off stays off. |
| **Always start** | Like above, and a server that's off is started after the deploy. |
| **Do not restart** | Files are replaced while the server keeps running. |

**If the server does not stop:** some programs, Node.js apps in particular, ignore the stop signal. The server is then killed after the time you choose (immediately, 5 seconds up to 5 minutes; **Kill after 10 seconds** by default) so the deploy doesn't hang. Killing at once is fastest, but gives the server no time to save.

> **Note:** Two safety nets: if the server doesn't go off at all, **no files are changed**. If the deploy fails after the server was stopped, the server is **started again**.

---

## What Happens During a Deploy

1. A trigger (push, release, tag, update check or button) creates a deploy.
2. If **Wait for CI checks** is on, it waits for green CI checks (**Waiting**).
3. The **Portal** downloads the archive from your Git provider. Your credentials never leave the Portal and never end up on your server.
4. The archive is prepared: only the chosen folder, protected paths filtered out, unsafe content such as symbolic links discarded.
5. Depending on your settings, the server is stopped (and killed after the chosen time if needed).
6. The files are written to the target folder; optionally, deleted files are removed.
7. Depending on your settings, the server is started again.
8. The result and the full log appear in the history — and, if enabled, as a status on the commit.

A deploy typically takes **10–40 seconds**, plus the time your server needs to stop.

---

## History, Logs and Rollback

The **Deployments** list at the bottom of the tab shows every deploy with its status, branch and commit (for example `main @ 75cd0a1`), number, trigger, the person who started it, the time and the commit message. The header of the tab shows when the server was last deployed.

| Status | Meaning |
| :--- | :--- |
| **Waiting** | Waiting for CI checks |
| **Scheduled** | Queued, starts shortly |
| **Running** | The deploy is in progress |
| **Deployed** | Finished successfully |
| **Failed** | Something went wrong — the log shows what |
| **Skipped** | Not deployed, for example because the CI failed or the commit says `[skip deploy]` |
| **Cancelled** | Cancelled before it started |

- **Log:** every deploy has a live log that updates while the deploy runs. **Hide log** closes it again.
- **Rollback in one click:** click **Deploy again** on an earlier deploy to roll out that state once more.
- **Cancel:** waiting or scheduled deploys can be cancelled.

Several servers can deploy at the same time, but each server runs only one deploy at a time. A new trigger replaces an older deploy that is still waiting.

---

## Status in Your Repository

With **Show deploys in the repository** turned on, your commit shows a status **Daki Hosting / *your server name***: yellow while the deploy runs, then a green check or a red cross, with a link to the Git Deploy tab.

- On GitHub, a deploy also appears under **Deployments**, with your server name as the environment.
- With the GitHub app, the status is written by **Daki Git Deploy** and shows its logo — nothing else to set up. With a token, it shows the picture of the token's account, and the token needs write permissions (see [Token Permissions](#token-permissions)).
- You can turn it off per server. Only the status and the link are public — no logs and no error details.

---

## Teams and Sub-User Permissions

[Sub-users](https://daki.cc/wiki/guides/subusers) get their own permission group **Git Deploy**:

| Permission | Allows |
| :--- | :--- |
| **view** (`github.read`) | See the settings, the webhook address and the history with logs |
| **deploy** (`github.deploy`) | **Deploy now**, **Deploy again** and cancelling deploys |
| **change settings** (`github.update`) | Repository, access, webhook and all settings |

Sub-users have **no** Git Deploy access by default — you decide who gets which permission. The server owner can always do everything.

---

## Security

- Tokens and secrets are stored **encrypted** and are **never sent to your browser**.
- With the GitHub app, there's no long-lived token of yours for deploys at all: every deploy uses a short-lived key (1 hour) that reaches **only your server's repository**.
- Your own GitHub access decides which repositories you can connect. Nobody can pull someone else's repositories onto their server.
- Webhooks are **signed** with a secret of their own for each server. Deliveries with a wrong secret or for a different repository are rejected.
- Only the person who saved the token can change the repository, so sub-users can't use the owner's token to load other private repositories.
- If you change the Git service or the server URL, the saved token is deleted automatically when you save.
- Protected paths are never overwritten, and **Remove files that were deleted from the repository** only deletes what Git Deploy wrote itself.
- The public status in your repository contains no logs and no error details.

---

## Known Limits

- One repository and one access per server.
- Each server runs only one deploy at a time.
- The status in your repository only appears once the deploy actually starts, not while it waits for CI.
- Release files are only extracted if they're `.zip` files; a `.tar.gz` is uploaded as a file.
- Empty folders stay in place after **Remove files that were deleted from the repository**.
- Symbolic links in the repository are not deployed.
- GitLab has no pre-releases; a release with a date in the future counts as a pre-release.
- GitLab: release files uploaded to the project (`/uploads/…`) can't be downloaded with a token from private projects; links to the package registry work.
- **Connect with GitHub** is only available for GitHub; GitLab, Gitea and Forgejo use a token.

---

## FAQ and Troubleshooting

**Do I need to renew my token regularly?**

Not with the GitHub app: the Portal fetches a fresh key for every deploy automatically. A token of your own is valid for as long as you set when creating it on your Git provider; when it expires, simply save a new one.

**My repository isn't in the list (GitHub app)**

Click **Choose repositories on GitHub** and allow the app to access the repository.

**The deploy stays on Scheduled**

Wait a moment. If it stays that way for more than a few minutes, please [contact support](https://daki.cc/wiki/guides/support).

**The webhook doesn't arrive, or GitHub shows error 401**

The secret doesn't match. Copy the secret in the Portal and enter it in the webhook again. **New secret** creates a new one — then change it on your Git provider as well.

**Why was my deploy skipped?**

Possible reasons: the CI checks failed, the commit message contains `[skip deploy]`, or a newer trigger replaced a deploy that was still waiting. The reason is shown in the deploy's row.

**I don't see a status on my commit**

**Show deploys in the repository** has to be turned on. With a token, the token also needs write permissions (see [Token Permissions](#token-permissions)) — the deploy log shows the reason.

**The deploy fails with “The node rejected the request”**

Your server's type doesn't allow certain files, or the disk is full. The log shows the details.

**The URL of my own Gitea instance is rejected**

Self-hosted instances must be reachable from the internet. Addresses from a home network such as `192.168.x.x` don't work.

**How do I roll back?**

In the history, click **Deploy again** on the earlier deploy you want to go back to.

**Will my game world or database be overwritten?**

Not if they're listed under **Protected paths** (for example `world/` or `*.db`).

**Who in my team can deploy?**

Only people with the **deploy** permission in the **Git Deploy** group of the server's sub-user settings. The server owner can always do everything.

---

## Next Steps

- [Subusers](https://daki.cc/wiki/guides/subusers) — Give your team access and decide who can deploy.
- [Environment Variables](https://daki.cc/wiki/guides/environment-variables) — Keep tokens and passwords out of your repository.
- [Startup Settings](https://daki.cc/wiki/guides/startup-settings) — Set the startup command your deployed code runs with.
- [Backups](https://daki.cc/wiki/guides/backups) — Save automatic backups of your server to Google Drive.

---
Source: https://daki.cc/wiki/guides/git-deploy
