Upgrading to Gitea 28: five breaking changes you need to fix before restarting

Gitea 28.0.0, released on September 30, 2026, brings five breaking changes that can break an existing installation on first startup. They affect five areas:

  • egress rules for mirrors and migrations;
  • deletion of Actions runs after 400 days;
  • Git 2.25 as minimum version;
  • user registration and use of DOMAIN;
  • stricter evaluation of workflows.

Reviewing each one takes a minute. Undoing them after updating costs much more.

Security Note: this version includes security fixes. At the time of publishing this note (October 1, 2026), the Gitea team had not yet published the details. They announced they will add them to the version post in approximately one week. This is a reason to update soon, but after doing the checks below.

What is Gitea and why is it used as an alternative to GitHub?

Gitea is a self-hosted Git forge with MIT license. It brings together repositories, pull requests, issues, a package registry, and its own CI system, Gitea Actions, in a single binary or container. It’s the option teams turn to when they want GitHub-style workflows in their own infrastructure. If you’re already deploying on your own server, it fits naturally with tools like Openship.

Why is it 28.0.0 and not 1.28?

Gitea removed the historical 1. prefix from its version numbers, so what would have been 1.28.0 is now 28.0.0. It follows directly from the 1.27.x series and there’s nothing else special about the numbering. Still, check any tool that interprets 1.x versions or that has fixed download URLs. I explain what changed in downloads below.

What breaks when updating to Gitea 28?

These are the five breaking changes listed by the Gitea team, ordered by likelihood of affecting you.

1. Are your mirrors and migrations still reaching the hosts they need?

Now migrations, mirrors, and other Git network operations go through an internal proxy that applies your egress rules to direct connections (#39426). In most installations with the default lax mode, nothing changes. Act before updating if any of these cases apply to your instance:

  • You were using the external preset. It was removed. If you want a deny-by-default policy, define EGRESS_MODE = strict and list the allowed hosts. [migrations] EGRESS_MODE covers migrations and mirrors, and [security] EGRESS_MODE covers webhooks and OAuth2.
  • You were using [security] ALLOWED_HOST_LIST as an exclusive whitelist. In lax mode it no longer restricts public hosts. Define [security] EGRESS_MODE = strict to preserve the previous behavior. If the list is defined without an explicit EGRESS_MODE, Gitea logs a warning on startup.
  • Your host lists use wildcards in IPs, a lone *, or example.*. None of those formats are valid now. Domain entries follow curl syntax: example.com matches the domain and its subdomains, and *.example.com only matches the subdomains.
  • Your [migrations] BLOCKED_HOST_LIST has any invalid entries. Gitea will refuse to start.

In strict mode, entries without a port only allow 80 and 443. [migrations] ALLOWED_DOMAINS, BLOCKED_DOMAINS, and ALLOW_LOCALNETWORKS are deprecated in favor of ALLOWED_HOST_LIST and BLOCKED_HOST_LIST.

2. Will Gitea delete your old Actions runs?

Yes, by default. Actions runs completed more than 400 days ago are now deleted along with their jobs, logs, and artifacts (#38855). They are deleted by a new cron task, cleanup_action_runs, which by default runs at midnight. To keep everything, define this before updating:

[actions]
RUN_RETENTION_DAYS = 0

Now 0 means “keep forever” in RUN_RETENTION_DAYS, LOG_RETENTION_DAYS, and ARTIFACT_RETENTION_DAYS. Logs and artifacts are always deleted along with their run.

3. Is your Git version new enough?

Gitea no longer starts with a Git version older than 2.25.0 (#39131). If you install Git on your own instead of using the official container, run git --version on the host before upgrading.

4. Why did sign-up stop working and why are clone URLs broken?

There are two changes coming together in #39400:

  • Self-registration is disabled by default. If your instance allows people to sign up, it will only stay open if you explicitly set [service] DISABLE_REGISTRATION = false.
  • [server] DOMAIN is ignored. The instance domain, including the default SSH domain, now comes from ROOT_URL. If you set DOMAIN but never ROOT_URL, fix that first. Otherwise, clone URLs that your users copy may end up wrong.

5. Will your workflows still run the same way?

Not necessarily. Actions workflows are evaluated more strictly (#39358):

  • The job-level if: is evaluated before expanding the matrix. Also, it can only use the github, gitea, needs, vars, and inputs contexts. Move conditions about matrix to strategy.matrix.include/exclude or to a step-level if:.
  • fail-fast now applies to the matrix. A job that fails can cancel the rest of the combinations. Set strategy.fail-fast: false if you need all of them to finish.
  • Public repositories can no longer call reusable workflows from private repositories. Also, nested workflows can no longer exceed the permissions of the caller’s token.

What else should you review before restarting?

There are three changes that aren’t on the official breaking changes list but can also catch you:

  • Reverse proxy and WebSockets. Live notifications now use a WebSocket at /-/ws, instead of server-sent events at /user/events. Your proxy has to forward WebSocket upgrade headers. If it doesn’t, notification counters fall back to polling. Deployments with multiple Gitea processes need [websocket] PUBSUB_TYPE = redis. The [ui.notification] EVENT_SOURCE_UPDATE_TIME setting was removed.
  • Download scripts. File names no longer carry the OS version suffix, for example gitea-28.0.0-windows-amd64.exe.
  • Removed builds. Binaries no longer include builds for 32-bit x86 or gogit, and the Snap is no longer built for armhf. Installations on those platforms don’t have an official artifact for 28.0.0.

How do you update Gitea with Docker or from the binary?

Gitea automatically migrates the database on first startup, and you can’t run an older version on an already-migrated database. The official documentation recommends always backing up before a database migration:

  1. Stop the Gitea instance.
  2. Back up the database, Gitea configuration, and data in APP_DATA_PATH. If you use external storage like S3 or MinIO, include that too. A volume snapshot is a convenient alternative.
  3. Apply the configuration changes from above.
  4. Replace the binary, or docker pull the new version and bring the container back up with docker or docker-compose.
  5. Start Gitea. The first startup takes longer while migrations run.

The documentation also points to contrib/upgrade.sh in the Gitea source code, which automates the steps with binary on Linux. Before updating, resolve any obsolete configuration warnings that appear above the Site Administration panel, because if they’re not resolved, the next version may refuse to start. If you use custom templates, check them against the new version as well.

Gitea or Forgejo?

Forgejo is a fork of Gitea and, since early 2024, a hard fork with diverging code. According to the Forgejo project itself, it was born in October 2022, after Gitea’s domains and brand went to a for-profit company. Today it operates under the umbrella of Codeberg e.V., a non-profit association. It’s distributed under the GPL v3+ license since version 9.0, while Gitea remains MIT.

For this article, the practical difference is that Forgejo has its own version numbers and its own release notes. None of the above applies directly to a Forgejo instance. If you’re considering moving from Gitea to Forgejo, Forgejo’s upgrade guide documents the process.

What do you gain by upgrading to Gitea 28?

The release is substantial:

  • Audit log. Gitea records security-relevant events, which can be filtered and exported by administrators in JSONL format. It comes disabled by default; enable it with [audit] RECORD_OUTPUT = database. Events are kept for 30 days unless you change [audit] RETENTION_DAYS.
  • Bot accounts. These are accounts for automation that only authenticate with access tokens and don’t receive notifications or emails.
  • User impersonation for administrators. An administrator can view the instance as a specific user to reproduce access issues. A banner marks the session, and with audit logging enabled, events record both accounts.
  • HTTPS deploy tokens per repository. They’re the HTTPS equivalent of SSH deploy keys, with read or read-write access. Both deploy tokens and personal access tokens can be regenerated without creating a new one.
  • Code owner approval in branch protection. It blocks merge until each matching CODEOWNERS rule is approved.
  • Shared Redis configuration. A single [redis] CONN_STR serves as the default value for all subsystems that use Redis.

What’s new in Gitea Actions?

  • A build queue view, showing running jobs first and then waiting ones, in the order runners pick them up.
  • Artifact preview in the browser: text, images, PDFs, and generated HTML, like test reports.
  • Matrices built from outputs of previous jobs.
  • strategy.max-parallel, to limit how many matrix jobs run at once.
  • self: references to actions and workflows on the same instance.None of this compensates for losing a year of CI history. Define RUN_RETENTION_DAYS, check ROOT_URL, and review your host lists. Then, update.