Gitea is the most lightweight self-hosted Git platform — a single Go binary that provides GitHub-compatible repositories, pull requests, issue tracking, CI/CD (Gitea Actions, compatible with GitHub Actions syntax), and a web UI, all running on minimal hardware. Deployed on a Hong Kong VPS, it gives Asia-Pacific engineering teams a private code host with fast Git operations via CN2 GIA routing from mainland China, without GitHub’s per-seat pricing or data sovereignty concerns.
Why Self-Host Git?
- Data sovereignty — source code stays on your infrastructure, not on GitHub’s US servers
- China accessibility — GitHub is accessible from mainland China but slow and unreliable; Gitea on a Hong Kong VPS with CN2 GIA delivers fast
git push/git pullfor developers in China - Cost — GitHub Teams costs $4/user/month; Gitea on a VPS you already have costs nothing per user
- Compliance — regulated industries requiring code to remain in controlled infrastructure
- Full control — custom branch protection rules, webhook integrations, and mirror configurations
VPS Requirements
Gitea is remarkably efficient — 1 GB RAM handles dozens of active developers with hundreds of repositories. A 2 GB VPS comfortably serves most engineering teams.
Step 1: Install Gitea via Docker
apt update && apt upgrade -y
curl -fsSL https://get.docker.com | sh
systemctl enable --now docker
mkdir -p /opt/gitea/{data,config}
chown -R 1000:1000 /opt/gitea
cat > /opt/gitea/docker-compose.yml << 'EOF'
version: '3.8'
services:
gitea:
image: gitea/gitea:latest
container_name: gitea
restart: unless-stopped
ports:
- "127.0.0.1:3000:3000" # Web interface (proxied via Nginx)
- "0.0.0.0:2222:22" # Git SSH (direct — needed for git clone over SSH)
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__database__DB_TYPE=sqlite3
- GITEA__server__DOMAIN=git.yourdomain.com
- GITEA__server__ROOT_URL=https://git.yourdomain.com
- GITEA__server__SSH_DOMAIN=git.yourdomain.com
- GITEA__server__SSH_PORT=2222
- GITEA__service__DISABLE_REGISTRATION=false
- GITEA__service__REQUIRE_SIGNIN_VIEW=false
- GITEA__mailer__ENABLED=true
- GITEA__mailer__FROM=gitea@yourdomain.com
- GITEA__mailer__PROTOCOL=smtp
- GITEA__mailer__SMTP_ADDR=smtp.yourprovider.com
- GITEA__mailer__SMTP_PORT=587
- GITEA__mailer__USER=gitea@yourdomain.com
- GITEA__mailer__PASSWD=YOUR_SMTP_PASSWORD
volumes:
- /opt/gitea/data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
EOF
cd /opt/gitea && docker compose up -d
docker compose logs -f giteaStep 2: Configure Nginx with SSL
apt install -y nginx certbot python3-certbot-nginx
cat > /etc/nginx/sites-available/gitea << 'EOF'
server {
listen 80;
server_name git.yourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name git.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/git.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/git.yourdomain.com/privkey.pem;
# Allow large repository pushes
client_max_body_size 512m;
client_body_timeout 300s;
location / {
proxy_pass http://127.0.0.1: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;
proxy_read_timeout 300s;
proxy_buffering off;
}
}
EOF
ln -s /etc/nginx/sites-available/gitea /etc/nginx/sites-enabled/
certbot --nginx -d git.yourdomain.com
nginx -t && systemctl reload nginx
ufw allow 80/tcp && ufw allow 443/tcp && ufw allow 2222/tcp
ufw enableStep 3: Initial Setup
Visit https://git.yourdomain.com — the first-time setup wizard appears:
- Database: SQLite3 (suitable for teams under 50; use PostgreSQL for larger teams)
- Repository root path:
/data/gitea/repositories - Site title: Your organisation name
- Administrator account: create your first admin user
After initial setup, configure in Site Administration → Settings:
- Disable open registration if this is a private internal instance
- Configure email confirmation for new accounts
- Set default repository visibility to Private
Step 4: SSH Key Setup for Developers
<code"># Developer adds SSH key in Gitea: Settings → SSH/GPG Keys → Add Key
# Then clones via SSH on the custom port:
git clone ssh://git@git.yourdomain.com:2222/org/repo.git
# Or configure SSH client to use port 2222 automatically:
# In ~/.ssh/config on developer's machine:
Host git.yourdomain.com
HostName git.yourdomain.com
Port 2222
User git
IdentityFile ~/.ssh/id_ed25519
# With this config, standard git clone works:
git clone git@git.yourdomain.com:org/repo.gitStep 5: Mirror from GitHub
Gitea can mirror public or private GitHub repositories — useful for creating a local cache of dependencies or migrating from GitHub:
- In Gitea: + New Repository → Migrate
- Migration Source: GitHub
- Enter repository URL and optionally a GitHub personal access token
- Enable This repository will be a mirror
- Mirror interval: every 8 hours
Gitea periodically syncs from GitHub, giving your team a local cache with fast access via CN2 GIA routing — git clone from your Gitea mirror in Hong Kong is dramatically faster for mainland Chinese developers than cloning directly from GitHub.com.
Step 6: Gitea Actions (CI/CD)
Gitea Actions is compatible with GitHub Actions workflow syntax — the same YAML, same on: push triggers, and many of the same actions.
<code"># Install Gitea Actions runner on your VPS or a separate machine curl -L https://gitea.com/gitea/act_runner/releases/latest/download/act_runner-linux-amd64 \ -o /usr/local/bin/act_runner chmod +x /usr/local/bin/act_runner # Register runner with your Gitea instance act_runner register \ --instance https://git.yourdomain.com \ --token RUNNER_TOKEN_FROM_GITEA_ADMIN \ --name hk-vps-runner \ --labels ubuntu-latest # Start runner as systemd service cat > /etc/systemd/system/gitea-runner.service << 'EOF' [Unit] Description=Gitea Actions Runner After=network.target [Service] ExecStart=/usr/local/bin/act_runner daemon WorkingDirectory=/opt/gitea-runner Restart=always [Install] WantedBy=multi-user.target EOF mkdir -p /opt/gitea-runner systemctl enable --now gitea-runner
Example Workflow
<code"># .gitea/workflows/deploy.yml (GitHub Actions compatible syntax)
name: Deploy to Production
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy via SSH
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.VPS_SSH_KEY }}
script: |
cd /var/www/myapp
git pull origin main
npm install && npm run build
pm2 reload myappStep 7: Migrate from GitHub
<code"># Migrate all repositories from a GitHub organisation
# Gitea admin: Site Administration → Git Repositories → Migrate → GitHub
# Or via Gitea API:
ORG="your-github-org"
GITEA_TOKEN="your-gitea-admin-token"
GITHUB_TOKEN="your-github-token"
# List GitHub repos and create mirrors in Gitea
curl -s "https://api.github.com/orgs/$ORG/repos?per_page=100" \
-H "Authorization: token $GITHUB_TOKEN" | \
python3 -c "
import sys, json
repos = json.load(sys.stdin)
for r in repos:
print(r['name'], r['clone_url'])
" | while read NAME URL; do
curl -s -X POST "https://git.yourdomain.com/api/v1/repos/migrate" \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"clone_addr\":\"$URL\",\"repo_name\":\"$NAME\",\"mirror\":true,\"auth_token\":\"$GITHUB_TOKEN\"}"
doneUpdating Gitea
<code">cd /opt/gitea docker compose pull gitea docker compose up -d docker compose logs gitea | tail -20
Conclusion
Gitea on a Hong Kong VPS gives Asia-Pacific engineering teams a fast, private Git platform — git push and git clone over CN2 GIA routing completes in seconds for developers in mainland China, a significant improvement over direct GitHub access. Gitea Actions provides GitHub Actions-compatible CI/CD pipelines running on your own runner infrastructure, and the SQLite backend means zero database administration overhead for teams up to 50 developers.
Host your code privately: Browse Server.HK Hong Kong VPS plans — a 2 GB plan runs Gitea for a full engineering team alongside other services.