Lesson 16 of 21

Install Gitea

Monthly cost: $0 Expected time: ~20–30 minutes

What Is Gitea

Gitea is a lightweight, self-hosted Git service — think of it as your own private GitHub. It runs on your VPS alongside OpenClaw and gives you:

Gitea is tiny (uses ~100MB RAM) and fits comfortably alongside OpenClaw on your 8GB VPS.

Step 1: Install Gitea with Docker

SSH into your server:

ssh claw@YOUR_SERVER_IP

Create a directory for Gitea:

mkdir -p ~/gitea
cd ~/gitea

Create a docker-compose.yml:

nano docker-compose.yml
services:
  gitea:
    image: gitea/gitea:latest
    container_name: gitea
    restart: unless-stopped
    environment:
      - USER_UID=1000
      - USER_GID=1000
    volumes:
      - ./data:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3000:3000"
      - "222:22"

Start Gitea:

docker compose up -d

Open the firewall for the web interface and Git-over-SSH:

sudo ufw allow 3000/tcp comment 'Gitea web'
sudo ufw allow 222/tcp comment 'Gitea SSH'

Step 2: Set Up HTTPS with Caddy

If you completed Lesson 15 (Install Caddy), you already have a reverse proxy with automatic HTTPS. Add Gitea to your Caddyfile:

sudo nano /etc/caddy/Caddyfile

Add this block:

git.yourdomain.com {
    reverse_proxy localhost:3000
}

That's it — Caddy handles HTTPS automatically. Reload:

sudo systemctl reload caddy

Restrict Access

Gitea should not be publicly accessible by default. Only allow your home IP and the VPS itself:

git.yourdomain.com {
    @blocked not client_ip YOUR_HOME_IP 127.0.0.1 ::1
    abort @blocked

    reverse_proxy localhost:3000
}

Replace YOUR_HOME_IP with your actual IP (find it at whatismyip.com). See Lesson 15 for details on IP allowlists, basic auth, and other access control options.

Now close the raw web port (keep 222 for Git SSH):

sudo ufw delete allow 3000/tcp

Gitea is now at https://git.yourdomain.com.

Step 3: Initial Configuration

Visit https://git.yourdomain.com (or http://YOUR_SERVER_IP:3000 if no domain). The first-run wizard appears:

  1. Database: Choose SQLite3 (simplest, fine for personal use)
  2. Site Title: Something like "My Gitea" or your name
  3. Repository Root Path: Leave default
  4. Server Domain: git.yourdomain.com (or your server IP)
  5. SSH Server Port: 222
  6. Gitea Base URL: https://git.yourdomain.com/ (or http://YOUR_SERVER_IP:3000/)
  7. Click Install Gitea

Then register your admin account — the first user automatically becomes the admin.

Save this login in Bitwarden.

Disable Public Registration

Your Gitea is for you and your OpenClaw. If registration is open, anyone who finds the URL can create an account. Disable it:

nano ~/gitea/data/gitea/conf/app.ini

Find or add the [service] section and set:

[service]
DISABLE_REGISTRATION = true

Restart Gitea for the change to take effect:

cd ~/gitea
docker compose restart

Step 4: Generate an API Token

You'll need this for OpenClaw to interact with Gitea:

  1. Click your avatar → Settings → Applications
  2. Under Manage Access Tokens, enter a name (e.g., "openclaw")
  3. Select scopes: repository: Read and Write, issue: Read and Write
  4. Click Generate Token
  5. Copy the token immediately — it's only shown once
  6. Save it in Bitwarden

Step 5: Back Up Gitea

Gitea's data lives in ~/gitea/data/. Back it up the same way as OpenClaw:

Manual backup

cd ~/gitea
docker compose stop
tar czf gitea-backup-$(date +%Y%m%d).tar.gz data/
docker compose up -d

Gitea's built-in backup command

docker exec -it gitea gitea dump -c /data/gitea/conf/app.ini

This creates a zip file at /tmp/gitea-dump-TIMESTAMP.zip inside the container. Copy it out:

docker cp gitea:/tmp/gitea-dump-*.zip ~/gitea/

Copy backups to your local machine periodically:

# On your LOCAL machine
scp claw@YOUR_SERVER_IP:~/gitea/gitea-backup-*.tar.gz ~/gitea-backups/

Automated backup via cron

crontab -e

Add:

0 3 * * 0 cd /home/claw/gitea && tar czf gitea-backup-$(date +\%Y\%m\%d).tar.gz data/ && find . -name 'gitea-backup-*' -mtime +30 -delete

This backs up every Sunday at 3 AM and deletes backups older than 30 days.

Step 6: Update Gitea

cd ~/gitea
docker compose pull
docker compose down
docker compose up -d

Your data is in a mounted volume, so it survives container replacement.

When You're Done

Further Reading