Gitea: How to Painlessly Self-Host Your Organization’s Source Code


The Inedo Team

The Inedo Team


Webinar: CI/CD on Self-Hosted Docker Made Simple with BuildMaster 05th September, 2023

Webinar: The Future of .NET is… On-prem CI/CD? 23rd June, 2023


Gitea: How to Painlessly Self-Host Your Organization’s Source Code

Posted on .

Is “the public cloud” really the best place for your source code?

According to Gartner, over 90% of organizations plan to embrace hybrid- or multi-cloud strategies to mitigate the risks of “putting all your eggs in one basket”. Many are starting to do the same with their source control – and you’ve probably been thinking the same.

However, when you evaluate alternatives to “the public cloud” for your source code, you’ll keep running into the huge, complex, bulky, and expensive platforms that don’t seem to really be designed for self-management. Fortunately, Gitea is a great alternative.

In this article, we’ll talk about why Gitea is becoming a great option for self-managed source control, and why you should consider it for your organization.

We’ll also discuss Gitea’s best practices including:

Why is Gitea a compelling alternative for your organization’s source code?

When you’re evaluating a self-hosted Git server for source control, the first decision to make is the type of tool:

  • Monolithic Development Platform that has “Git repositories” as one of its many features (e.g. GitLab)
  • Dedicated Git Server that focuses on self-hosted source control (e.g. Gitea)

There are a lot of reasons why a Monolith Development Platform may be the wrong choice, especially if you only need self-hosted Git source control. But the most compelling reason is the complexity and the cost of maintenance.

Monoliths like GitLab Enterprise have a very complicated architecture and reliable operating system services like Redis, Gitaly, PostgreSQL, and Sidekiq to function. While it’s relatively easy to install these using the provisioning scripts they provide, maintaining the installation of all of these components – plus the monolithic platform itself – is complex, especially if you’re not a Linux expert. This isn’t surprising, considering that monolith platforms are primarily hosted, software-as-a-service tools, and supporting self-hosted isn’t their primary objective.

Gitea, on the other hand, bills itself as “a painless self-hosted Git service” – and as we’ll show you in this article, that’s very accurate. For example, Gitea is just a single executable file and uses just a single data directory to back up.

While Gitea isn’t the only dedicated Git Server, it is by far the most popular and is quickly becoming the dominant choice.

Challenges with Gitea

Although Gitea has all of the features most teams will need in a source control repository, users familiar with a different repository may find the navigation unfamiliar. It may be missing some “nice to have” things, but Gitea is very actively maintained – and those features will be added, and the product will continue to evolve with the rest of the tools on the market.

The main objection to Gitea is the limited commercial support. However, this is where the simplicity of Gitea really shines – and you may actually be better off without commercial support.

Gitea is very easy to install and maintain, and you likely won’t run into issues. But when you do, you can quickly find an answer from support forums or chatrooms. It’s probably something others have run into, and if not – the Gitea maintainers themselves will quickly help get it resolved. This has been their hobby and passion for nearly a decade.

Monoliths, on the other hand, are much more complex – and have a lot more things that can go wrong. Running into an issue will very likely require a support interaction, which means filling out a ticket, or scheduling a call with your account manager. Because self-hosting is not their primary business, your ticket will likely be routed to a specialized, senior engineer for help,  and prioritized and addressed during normal business hours at the pace of large business. 

Gitea Components and Installation

Gitea is just a single, executable file. That’s it!

That makes installation an absolute breeze on Linux or Windows:

  1. Install git
  2. Download gitea binary executable
  3. Register the gitea executable as a service/daemon
  4. Run initial configuration

There are lots of guides for how to install Gitea on Linux (including installing Gitea on Ubuntu), and the Windows guidance is starting to catch up.

Of course, there are some more complex installation options, like using a Kubernetes cluster or using an external database like PostgreSQL, but those generally aren’t required for most installations.

How to Install Gitea on Windows

Gitea will run on all modern versions of Windows, and has very minimum system requirements: 2 CPU cores and 1GB RAM is typically sufficient for small teams/projects, and you can scale up as needed.

Before installing Gitea, make sure to install the git client tools on the server.

Download the gitea executable

There are a few Windows-specific downloads in the Gitea download center, but the one you’ll most likely want is gitea-<latest-version>-windows-4.0-amd64.exe. This file is for all modern versions of Windows.

You can install Gitea to any location, but C:\gitea is generally suggested.

Register Gitea as a Windows Service

The Gitea Windows Service instructions detail this step, but it really just involves using sc.exe to register the service.

sc.exe create gitea start=auto binPath="“C:\gitea\gitea.exe” web --config “C:\gitea\custom\conf\app.ini”"

Optional: Creating a User Account

While not required, it’s generally recommended to use limited-access user accounts to run Windows services. The above command will default to using LocalSystem, which has administrative privileges.

If you do use a different account to run the service, you’ll need to give that user account read access to C:\gitea\** and read-write access to the data and log subdirectories.

Run Initial Gitea Configuration

When you first run Gitea, there will likely be no configuration file in the location you specified (e.g. C:\gitea\custom\conf\app.ini from the command earlier). As such, Gitea will run in “initial configuration” mode to help you set up the service for the first time.

To perform the initial configuration, simply navigate to the default Gitea web interface at http://localhost:3000 and configure the following items.

Select the database engine to use, and optionally configure file paths (or use the defaults). The built-in SQLite database is adequate for nearly all use cases. We do not recommend using SQL Server, as it’s not officially supported yet and has been reported as being very buggy.

Create an initial user account, which will be like the root account of the service.

After saving the initial configuration, you can then edit the created configuration file. The Gitea configuration file cheat sheet documents all of the settings, but there are two we recommend setting:

[server] ROOT_URL = (set to the actual URL of your server)

[service] DISABLE_REGISTRATION = false (prevent anonymous new user creation)

Disabling registration is recommended if you plan to integrate with Active Directory, which is also recommended on Windows.

Configure SSL

Although not technically required for Gitea itself, using git without https – even internally – is difficult. While Gitea has support for ACME built-in, it’ll be easiest on Windows to configure IIS as a reverse proxy.

Microsoft’s guide for Reverse Proxy with URL Rewrite v2 and Application Request Routing has some great guidance on how to do that if you haven’t before.

Gitea Active Directory Integration

Gitea provides a lot of authentication options, and you can configure it to integrate with your Active Directory.

The easiest way to integrate with your domain is by leveraging “LDAP via Bind DN”. This mostly refers to how you configure the settings. For example, instead of specifying a login user like you may be used to (admin@mycompany.local or mycompany/admin), you will need to specify “distinguished names” like CN=Admin,DN=mycompany,DN=local as well as configure specific LDAP paths and queries.

There’s a bit of a learning curve to BindDN, and it may require a bit of trial and error. Before configuring Active Directory in Gitea, make sure that you have a domain user account that can perform searches. While you can use any user with permission, it’s best to maintain a special purpose, limited access account. For example, searcher@mycompany.local with searcher as the password.

You’ll first need to find the distinguished name for your search user. To do this, make sure the advanced tools are enabled by navigating to Active Directory Users & Groups > “View” > “Advanced Features”. Then, navigate to your user, use the right-click menu to go to properties, click the “Attribute Editor” tab, then finally look for the distinguishedName property. It will look something like CN=Domain Searcher,CN=Users,DC=mycompany,DC=local.

Next, you’ll need the distinguished name for the organizational unit you wish to search. You can find this in the same manner under Active Directory Users & Groups by right-clicking on the OU object instead. The distinguishedName for an OU will look something like CN=Users,DC=mycompany,DC=local

Once you’ve gathered those values, navigate to Site Administration > Authentication Source, and add a new LDAP (via BindDN).

  • Authentication Name can be the friendly name of your domain, like MyCompany
  • Security Protocol should be Unencrypted for regular LDAP, or LDAPS if you’ve configured that already
  • Host should be your domain suffix, not the LDAP server. E.g. mycompany.local instead of mydc1.mycompany.local
  • Port should be 389 (default for LDAP) or 636 (default for LDAPS)
  • Bind DN should be the distinguishedName of your search user, such as CN=Domain Searcher,CN=Users,DC=mycompany,DC=local
  • Bind Password should be that password, like searcher
  • User Search Base should be the distinguishedName of your OU, such as CN=Users,DC=mycompany,DC=local
  • User Filter should be (&(objectClass=user)(sAMAccountName=%s))
  • Admin Filter is optional but can be based on the distinguishedName of a group Like (&(memberOf=CN=Git Administrators,CN=Users,DC=mycompany,DC=local))
  • Username Attribute should be sAMAccountName
  • First Name Attribute should be givenName
  • Surname Attribute should be sn
  • Email Attribute should be mail

These settings may vary from domain to domain. But once configured, users will be able to log in with their domain email address or domain username.

How to Migrate to Gitea

One of the major advantages of using lightweight, dedicated tools in a toolchain is that it’s relatively easy to try different tools and discover what works best for your team. While changing tools is easy, it’s not trivial. In addition to training and process changes, data migration will often be a consideration before trying new tools.

Fortunately, Git repositories are self-contained and have a history of all code changes, including a trail of all commits, merges, and the people who made those changes. This means that when you migrate a git repository from one tool to another, all of that history will remain intact.

Migrating a Repository Using the Gitea UI

Gitea has a built-in migration tool that can migrate from any Git service. Simply navigate to “New Migration”, and you’ll be presented with a list of options such as the repository name on Gitea, the URL of the repository you want to clone, etc.

If you’re migrating from GitLab and GitHub, Gitea will provide options to migrate milestones, releases, issues, etc. Other settings like the default branch, permissions, protected branches, tag restrictions, etc. may not be migrated, and are things you’ll want to set up in the Gitea repository.

Creating a Migration Plan With Repository Mirroring

When evaluating and migrating to a new tool, it’s best to do so incrementally and in parallel. That is, use both tools for a little while, perhaps only on a few projects, and plan to slowly migrate away from the old as you use the new.

Gitea has a feature called repository mirroring that makes this staged migration easy. You can configure a Gitea repository to pull or push commits to another Git repository. This allows you to:

  • Start with Gitea in “read-only” mode, and pull changes from your current source control repository. This will let developers see the new UI and make sure some of your automation (build servers, etc.) will still work.
  • Provisionally swap to Gitea and push changes to your current source control repository. This involves setting the current repository to “read-only”, and instructing developers on how to push to Gitea instead. It’s really just a new URL.
  • Decommission the old source control server, once you’re satisfied.

Scripting Migrations

If you have a lot of repositories to migrate, it may be easier to write a script to migrate them.

The easiest way to go about this would be to use the Gitea API to create a blank repository, and then use the Git command line to clone repositories from your existing service into Gitea:

git clone --mirror «url to old repository»
git remote set-url origin «url to new gitea repository»
git push --mirror origin

You can also use the Gitea API to set things like default branches, permissions, mirroring, etc.

How to Plan for Gitea Back-up

Gitea provides thorough backup and restore documentation.

The backup strategy that you’ll use will depend on the operating system, whether you’ve opted for an external database, and how you’ve configured the paths that Gitea uses.

At an absolute minimum, there are two things you’ll need to back up:

  • The configuration file, which defaults to «gitea-directory»/custom/conf/app.ini
  • Data directory, which defaults to «gitea-directory»/data and includes the database, git repositories, avatars, issue attachments, etc.

Backing up Gitea on Windows

On Windows, it’s easiest to just back up the entire Gitea folder (i.e. c:\gitea) using your preferred backup tool, and save enough snapshots to mitigate file corruption and accidental data deletion risks.

Virtually all backup tools will leverage Window’s Volume Shadow Copy Services, which means that you can just keep Gitea running while the backup proceeds.

However, if you’re using an external database like PostgreSQL or MySQL, it’s advised to shut down Gitea so that the files and databases are synchronized during backup.

Scaling Gitea in the Enterprise

Although Gitea has never been “field tested” to scale to millions of users that supports, a Gitea instance configured to run as a load-balanced server or Kubernetes cluster and it can scale to more users than you would ever need.

A single-server instance of Gitea can easily support up to 1,000 users with normal developer usage. And with powerful hardware, you can support even more. For example, Codeberg, an emerging platform for open-source development, has over 10,000 users on just a single server.

The reason that Gitea works so well is two-fold.

  1. Git itself is efficient at transferring data, and users will be uploading and downloading a relatively small number of commits against each repository
  2. Gitea mostly transfers files and doesn’t need to write to its internal database very often, which means concurrency issues almost never occur 

Bottlenecks with Gitea

If you’re using git to exclusively transfer large, non-code assets like videos, or using Gitea as some sort of CDN, then you’ll likely run into network bottlenecks. This is when you should consider load balancing.

If you’re heavily relying on Gitea’s commenting features and posting thousands of issue comments or pull request comments each day, then you may run into database slowness issues. However, migrating to an external database may resolve that.

Scaling with Federation

Instead of moving towards a load-balanced or clustered configuration to support more usage, you will likely be better served with multiple, single-server instances of Gitea. This is called “federation” – and it’s something that’s becoming more and more popular in large organizations.

Federation allows you to delegate the administration of Gitea instances along organizational groups, and then create a “federated governance” structure. This means that you’ll require that the groups have certain features enabled (security, etc.), and you can even write a script to verify those features. But, otherwise, let them try different ways to manage Gitea.

One group may find that a plug-in or customization adds a lot of value – and then other groups can simply follow that usage. This federated approach increases organizational agility overall.

In addition, managing a handful of single instances will generally be much easier than managing a cluster of servers. And lower risk. Especially when it comes time to roll out upgrades.

Disaster Recovery for Gitea

Gitea’s repository mirroring makes it relatively easy to replicate critical Git repositories so that teams can still work at minimal capacity until the production environment is back up and running.

For developers, the most critical capability to restore is the ability to read/download code. Even if they can’t share/upload their code to the repository right away, they won’t be blocked from working on changes locally. This is why a two-stage disaster recovery plan is generally preferred for source control.

To prepare for this scenario, you’ll need to set up a second Gitea server in your disaster recovery environment ( and configure the critical repositories to pull changes from the production environment (

Disaster Stage One: Read-only for Hours

When disaster strikes, you just need to change your DNS to have the new Within minutes, users will be able to access all repositories again but will get errors if they try to push changes.

Once the production environment is restored, just change the DNS back and users will be able to read and write again. Some may never have even realized that there was a disaster.

Disaster Stage Two: Temporary Environment for Days

If you need to use the disaster recovery environment for the long haul, then simply disable repository mirroring and allow push access. This could work indefinitely.

When you’re ready to go back to the production environment, you’ll need to come up with a plan for migrating all of the changes that were pushed to the disaster recovery server.

The easiest approach is to :

  1. Configure your production server to mirror changes from disaster recovery
  2. Alert users of downtime
  3. Set all disaster recovery repositories to read-only
  4. Wait until all mirroring is complete
  5. Disable mirroring configuration on production
  6. Change DNS

Next Steps for Your Self-Managed Toolchain

Monolithic Development Platforms like GitHub, GitLab, and Azure DevOps are wildly popular because they’re easy to get started. But they’re not for everyone. A lot of organizations aren’t comfortable with their software supply chain being in “the public cloud”, and many prefer to use a suite of tools that meet their evolving needs instead of following the Monolithic way.

Gitea is a great option for these organizations because it’s focused on just being a single, easy-to-manage tool in the software supply chain. It’s rapidly growing in popularity as a result of this and will continue to improve as the community grows.