Building a Self-Hosted Private Git Server with Gitea and Object Storage: A High-Performance Enterprise Guide
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/giteaStep 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/dataSecurity 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 = minioThis 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 -dVerify 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 -yConfigure 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.
