Back to articles
Technology Insight

Building a Self-Hosted Private Git Server with Gitea and Object Storage: A High-Performance Enterprise Guide

May 29, 2026

Introduction

In the modern DevOps landscape, source code is an organization’s most valuable intellectual property. While public platforms like GitHub and GitLab offer robust features, they come with recurring per-user licensing costs, vendor lock-in, and compliance challenges regarding data residency. For enterprises seeking absolute control over their codebases without the resource overhead of heavy infrastructure, self-hosting is the logical path forward.

However, traditional self-hosted solutions often demand significant computational resources. Enter Gitea: a lightweight, ultra-fast, open-source Git service written in Go. When paired with Object Storage (such as AWS S3, Cloudflare R2, or MinIO) for data persistence, Gitea transforms into an enterprise-grade, highly scalable version control system that costs a fraction of standard SaaS alternatives. This comprehensive guide walks you through architecting and deploying this high-performance Git environment.

Why Choose Gitea and Object Storage?

Before diving into the technical implementation, it is essential to understand why the combination of Gitea and Object Storage represents a superior architectural paradigm for modern engineering teams.

1. Exceptional Performance and Low Resource Consumption

Unlike GitLab, which requires multiple gigabytes of RAM to run efficiently due to its heavy Ruby and Rails architecture, Gitea is compiled into a single Go binary. It operates seamlessly on minimal hardware—even a basic single-core VPS with 1GB of RAM can comfortably support dozens of active developers. It delivers siêu nhanh (ultra-fast) response times for repository cloning, pushing, and web UI navigation.

2. Infinite Scalability with Object Storage

Traditionally, Git repositories are stored on local block storage (EBS, NVMe SSDs). As your development history grows and large binaries are introduced, block storage costs scale linearly, and resizing disks introduces operational downtime. By offloading repository data, attachments, LFS (Large File Storage), and avatars to Object Storage, you achieve:

  • Virtually unlimited capacity without manual disk management.
  • Drastically reduced storage costs compared to premium SSD block storage.
  • Built-in data durability and automated replication provided by the cloud vendor.
---

Prerequisites and Architecture Overview

To successfully deploy this architecture, ensure you have the following components prepared:

  • A Linux cloud server (Ubuntu 22.04 LTS or 24.04 LTS recommended) with a public IP address.
  • A registered domain or subdomain (e.g., git.yourcompany.com) pointed to your server.
  • An Object Storage bucket with access keys (Access Key ID and Secret Access Key).
  • Docker and Docker Compose installed on the host system.

The architecture consists of a Docker-based Gitea deployment utilizing a PostgreSQL database for metadata and an external Object Storage bucket for the actual Git repository layers and assets.

---

Step-by-Step Deployment Guide

Step 1: Preparing the Directory Structure

First, access your server via SSH and establish a dedicated directory structure to keep your configuration organized and maintainable.

mkdir -p /opt/gitea/{data,config,postgres}cd /opt/gitea

Step 2: Configuring Docker Compose

Using Docker Compose ensures configuration reproducibility and isolates the environment. Create a docker-compose.yml file within the /opt/gitea directory:

version: '3'services:  server:    image: gitea/gitea:latest-rootless    container_name: gitea    environment:      - USER_UID=1000      - USER_GID=1000      - GITEA__database__DB_TYPE=postgres      - GITEA__database__HOST=db:5432      - GITEA__database__NAME=gitea      - GITEA__database__USER=gitea      - GITEA__database__PASSWD=YourSecurePasswordHere    restart: always    volumes:      - ./data:/var/lib/gitea      - ./config:/etc/gitea      - /etc/timezone:/etc/timezone:ro      - /etc/localtime:/etc/localtime:ro    ports:      - "3000:3000"      - "2222:2222"    depends_on:      - db  db:    image: postgres:15-alpine    container_name: gitea_db    restart: always    environment:      - POSTGRES_USER=gitea      - POSTGRES_PASSWORD=YourSecurePasswordHere      - POSTGRES_DB=gitea    volumes:      - ./postgres:/var/lib/postgresql/data
Security Note: Always replace YourSecurePasswordHere with a unique, cryptographically secure string before deploying to a production environment.

Step 3: Integrating Object Storage in app.ini

Gitea handles complex configurations via its app.ini file. To route your data to Object Storage, update your configuration file (typically located under ./config/gitea/app.ini after initial initialization) with the following structure customized for an S3-compatible backend:

[storage]STORAGE_TYPE = minioMINIO_ENDPOINT = s3.amazonaws.comMINIO_ACCESS_KEY_ID = YOUR_ACCESS_KEY_IDMINIO_SECRET_ACCESS_KEY = YOUR_SECRET_ACCESS_KEYMINIO_BUCKET = your-gitea-bucket-nameMINIO_LOCATION = us-east-1MINIO_USE_SSL = true[repo.storage]STORAGE_TYPE = minio[lfs]STORAGE_TYPE = minio

This unified storage configuration instructs Gitea to write Git LFS objects, repositories, and general attachments directly to the specified bucket, maintaining only operational metadata within the local PostgreSQL instance.

Step 4: Launching the Services

With the files configured, initiate the stack in detached mode:

docker compose up -d

Verify that both containers are running optimally by checking the status logs via docker compose logs -f.

---

Configuring a Secure Reverse Proxy with Nginx

For professional business use, securing data in transit via HTTPS is non-negotiable. Install Nginx and obtain a Let’s Encrypt SSL certificate to protect your Gitea instance.

sudo apt updatesudo apt install nginx certbot python3-certbot-nginx -y

Configure an Nginx server block to map incoming traffic from your domain to the internal Gitea container running on port 3000, enforcing strict TLS profiles for enterprise compliance.

server {    listen 80;    server_name git.yourcompany.com;    location / {        proxy_pass http://localhost:3000;        proxy_set_header Host $host;        proxy_set_header X-Real-IP $remote_addr;        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;        proxy_set_header X-Forwarded-Proto $scheme;    }}

Generate the SSL certificates automatically by executing: sudo certbot --nginx -d git.yourcompany.com.

---

Best Practices for Enterprise Maintenance

Deploying the infrastructure is only the first phase. Maintaining an enterprise-grade Git environment requires adherence to standard operational procedures:

  • Automated Metadata Backups: While repository objects reside safely in Object Storage, the database contains user accounts, issues, and pull request histories. Schedule daily automated backups of the PostgreSQL database using pg_dump.
  • Fine-Grained IAM Roles: Secure your storage bucket by applying the principle of least privilege. The API keys utilized by Gitea should possess access rights exclusively restricted to that specific bucket.
  • Webhooks and CI/CD Integration: Leverage Gitea’s native webhook capabilities to integrate with automation tools like Jenkins, Woodpecker CI, or GitHub Actions runners, enabling streamlined deployment pipelines.

Conclusion

By pairing the ultra-lightweight architecture of Gitea with the structural durability of Object Storage, businesses can achieve full control over their source code ecosystem. This setup eliminates prohibitive monthly per-seat licensing fees while providing developers with a high-performance, responsive platform. With the deployment centralized on infrastructure you own, your team can collaborate confidently, knowing your IP is secure, compliant, and scale-ready.

Building a Self-Hosted Private Git Server with Gitea and Object Storage: A High-Performance Enterprise Guide | DPTCloud