Blog / Tutorials

Self-Host Gitea on a VPS: Your Own Lightweight Git Server

By the NoctHost TeamAugust 3, 2026Updated November 11, 20265 min read

Gitea runs on a VPS with 1 GB of RAM. The Gitea documentation says 2 CPU cores and 1 GB of RAM are typically enough for small teams and that a Raspberry Pi 3 handles small workloads, so a personal instance fits the Micro plan (1 vCPU, 1 GB, $10/mo).

GitHub is convenient, but not every repository needs to live on someone else's servers, private client work, personal projects, or anything you would rather not hand to a platform that trains models on public code. Gitea is a lightweight, self-hosted Git service: pull requests, issues, CI hooks and a clean web UI, running on a server you own.

It is famously light. The whole thing fits comfortably on the smallest VPS. Here is the full setup with HTTPS, SSH cloning that shows the right URLs, closed signups, and a backup you can actually restore.

What You Need

  • A VPS with 1 GB RAM (Gitea sips resources), such as the smallest Debian VPS or Ubuntu one
  • Ubuntu 22.04 or 24.04, or Debian 12, with SSH
  • A domain or subdomain pointed at the server

A single Go binary with SQLite idles at well under 200 MB of RAM. What grows is the disk, with your repositories and any release attachments or packages you upload.

Step 1: Install Docker

curl -fsSL https://get.docker.com | sh

Step 2: Compose with Caddy HTTPS

Save as docker-compose.yml. This runs Gitea with SQLite (fine for a personal or small-team instance) and Caddy for automatic certificates:

services:
  gitea:
    image: gitea/gitea:latest
    restart: always
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - GITEA__server__DOMAIN=git.example.com
      - GITEA__server__ROOT_URL=https://git.example.com/
      - GITEA__server__SSH_DOMAIN=git.example.com
      - GITEA__server__SSH_PORT=2222
      - GITEA__service__DISABLE_REGISTRATION=true
    volumes:
      - gitea:/data
    ports:
      - "2222:22"

  caddy:
    image: caddy:2-alpine
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
    depends_on:
      - gitea

volumes:
  gitea:
  caddy_data:

Any setting from Gitea's app.ini can be passed this way, as GITEA__section__KEY. Three of them carry the SSH setup:

  • Gitea's built-in SSH server listens on 22 inside the container and is mapped to host port 2222, so it does not collide with your own SSH on port 22.
  • SSH_PORT=2222 tells Gitea which port to print in clone URLs. Without it the web UI shows git@git.example.com:user/repo.git on port 22, which lands on your host's sshd and fails with a confusing permission error.
  • Port 2222 is published by Docker, which bypasses ufw, so it is reachable from the internet no matter what your firewall says. That is intended here; just know it, and only publish ports you mean to open. The web port 3000 is not published at all: Caddy reaches it over the internal network.

Step 3: The Caddyfile

git.example.com {
  reverse_proxy gitea:3000
}

Bring it up:

docker compose up -d

Step 4: First-Run Setup

Open https://git.example.com and complete the install screen. The database is SQLite (already configured), so just set your admin account, and do it immediately: until the install screen is finished, anyone who opens the page can complete it.

DISABLE_REGISTRATION=true in the compose file already closes public signups, so new users only exist when an admin creates them. If you want collaborators to sign up themselves, remove that line and turn on admin approval in Site Administration instead. A public Gitea with open registration attracts spam accounts within days.

Step 5: Clone Over SSH

Add your public key in Gitea under Settings → SSH Keys, then clone using the mapped port:

git clone ssh://git@git.example.com:2222/youruser/yourrepo.git

To skip typing the port, add a host entry to ~/.ssh/config on your laptop:

Host git.example.com
  Port 2222
  User git

After that, git clone git@git.example.com:youruser/yourrepo.git works like it does on any big host.

Step 6: Back It Up

Gitea has a built-in dump command that packs repositories, the SQLite database, attachments and config into one zip:

docker compose exec -u git gitea gitea dump -c /data/gitea/conf/app.ini --file /data/gitea-dump.zip

Run it nightly from cron and copy the zip off the server with rclone or scp. A backup on the same disk does not survive the server, which is the event you are backing up for. To restore, start a fresh Gitea, stop it, and unpack the dump into the matching paths under /data.

CI with Gitea Actions

Recent Gitea versions include Actions, a CI system that reads workflow files in the same format as GitHub Actions. Jobs run on a separate act_runner that you register against your instance. Run the runner on a different server if your builds are heavy: a compile job on the 1 GB machine that also serves Git will make the web UI crawl.

What It Costs

Gitea is one of the lightest useful things you can self-host, so the Micro plan (1 vCPU, 1 GB) runs a personal or small-team instance comfortably. On NoctHost that is about $10 a month, billed hourly from a prepaid balance you top up with crypto (no KYC) or a card, which suits keeping private repositories genuinely private.

Spin one up in about a minute

Email signup, pay with crypto or card, hourly billing. Trying a box costs cents: destroy it when you are done.

Deploy a server

Frequently asked

Gitea vs GitLab, which should I self-host?
Gitea is far lighter and runs on a 1 GB VPS; GitLab is more powerful but wants several GB of RAM and more upkeep. For personal repos and small teams, Gitea is the pragmatic choice.
Why does cloning over SSH fail with "permission denied"?
Usually the clone went to port 22, your host's own sshd, instead of Gitea on 2222. Check that SSH_PORT=2222 is set so the UI shows the right URL, or use the ~/.ssh/config entry above.
Can I use it with my existing Git tooling?
Yes. Gitea speaks standard Git over HTTPS and SSH, so your existing clients, IDE integrations and CI runners work unchanged, just point them at your domain.
Is SQLite good enough?
For a personal or small-team instance, yes. Switch to Postgres only if you grow to many active users; for most self-hosters SQLite is simpler and plenty fast.
How do I keep it updated?
Take a dump, then run docker compose pull && docker compose up -d. Gitea handles its own migrations on start, and your data lives in the volume, not the image.

Keep reading