Files
infrastructure/MIGRATION.md

7.8 KiB

Gitea Migration: SQLite → PostgreSQL

Overview

Migrating Gitea from:

  • Old: git.infra.nkode.tech (SQLite, Dokploy on 191.101.0.153)
  • New: git.infra.donovankelly.xyz (PostgreSQL, Dokploy on 191.101.0.153)

This is a destructive migration — back up everything before proceeding.


Prerequisites

  • DNS: Point git.infra.donovankelly.xyz191.101.0.153
  • Old Gitea export at /home/clawdbot/clawd/gitea-export/ on the VPS
  • Docker and docker-compose available on the Dokploy server
  • The new compose service deployed via Dokploy (but NOT yet migrated)

Step-by-Step Migration

Step 1: DNS Setup

Add an A record:

git.infra.donovankelly.xyz → 191.101.0.153

Wait for propagation (check with dig git.infra.donovankelly.xyz).

Step 2: Stop the Old Gitea Instance

In Dokploy, stop the old Gitea application (nkode-giteasqlite).

# Or via CLI on 191.101.0.153:
docker stop <old-gitea-container>

Step 3: Deploy the New Stack (Fresh, No Data Yet)

Deploy the compose service from Dokploy. This will start:

  • PostgreSQL 16 (empty database)
  • Gitea (fresh install, connected to Postgres)
  • Act Runner (will fail until token is set — that's OK)

Wait for Gitea to be healthy:

docker logs -f gitea
# Look for "Starting new Web server"

Step 4: Stop Gitea (Keep Postgres Running)

docker stop gitea

We need Gitea stopped to safely import data.

Step 5: Migrate the SQLite Database to PostgreSQL

Option A: Using gitea dump and restore (Recommended)

The export already has gitea-dump.zip. We'll use Gitea's built-in migration:

# Copy the SQLite database into the Gitea container's volume
docker cp /home/clawdbot/clawd/gitea-export/gitea.db gitea:/data/gitea/gitea.db

# Start gitea temporarily to run the migration
docker start gitea

# Run the database migration from SQLite to Postgres
docker exec -u git gitea gitea doctor convert --type sqlite --database /data/gitea/gitea.db

# If `doctor convert` isn't available in your version, use dump/restore:
# First, generate a SQL dump from SQLite using the gitea binary:
docker exec -u git gitea gitea dump --type postgres --database /data/gitea/gitea.db --file /tmp/gitea-pg-dump.sql

# Then import it into Postgres:
docker exec -i gitea-postgres psql -U gitea -d gitea < /tmp/gitea-pg-dump.sql

Option B: Using gitea migrate on fresh start

If the above doesn't work cleanly, use pgloader to convert SQLite → Postgres directly:

# Install pgloader (on the host or in a container)
docker run --rm --network gitea-net \
  -v /home/clawdbot/clawd/gitea-export/gitea.db:/data/gitea.db \
  dimitri/pgloader:latest \
  pgloader /data/gitea.db \
  postgresql://gitea:YOUR_POSTGRES_PASSWORD@postgres:5432/gitea

Option C: Manual approach using Gitea's dump file

# Extract the dump
cd /tmp
unzip /home/clawdbot/clawd/gitea-export/gitea-dump.zip

# The dump contains gitea-db.sql (SQLite format)
# Convert using pgloader or sqlite3 + sed for Postgres compatibility

Recommended approach: Option A with doctor convert

Step 6: Copy Repository Data and LFS

The git repositories, LFS objects, avatars, and other data files need to be copied into the new volume:

# Find the new gitea-data volume mount point
VOLUME_PATH=$(docker volume inspect gitea-data --format '{{ .Mountpoint }}')

# Stop gitea first
docker stop gitea

# Copy the data directory contents
sudo cp -a /home/clawdbot/clawd/gitea-export/data/git/* ${VOLUME_PATH}/git/
sudo cp -a /home/clawdbot/clawd/gitea-export/data/gitea/avatars ${VOLUME_PATH}/gitea/
sudo cp -a /home/clawdbot/clawd/gitea-export/data/gitea/repo-avatars ${VOLUME_PATH}/gitea/
sudo cp -a /home/clawdbot/clawd/gitea-export/data/gitea/attachments ${VOLUME_PATH}/gitea/
sudo cp -a /home/clawdbot/clawd/gitea-export/data/gitea/uploads ${VOLUME_PATH}/gitea/ 2>/dev/null || true
sudo cp -a /home/clawdbot/clawd/gitea-export/data/ssh/* ${VOLUME_PATH}/ssh/ 2>/dev/null || true

# Fix ownership (Gitea runs as UID 1000 / git user)
sudo chown -R 1000:1000 ${VOLUME_PATH}/

# Start gitea again
docker start gitea

Step 7: Verify the Migration

# Check Gitea logs for errors
docker logs gitea --tail 100

# Test the web UI
curl -s https://git.infra.donovankelly.xyz/api/v1/version

# Log in with your existing credentials
# Check that repos, users, orgs, webhooks are all present

Checklist:

  • Can log in with existing user accounts
  • All repositories are visible and cloneable
  • LFS objects are accessible
  • Webhooks are configured
  • Organizations and teams are intact
  • Avatars display correctly
  • SSH keys work (ssh -T git@git.infra.donovankelly.xyz -p 22222)

Step 8: Set Up Gitea Actions Runner

# Generate a runner registration token
docker exec -u git gitea gitea actions generate-runner-token

# Copy the token output, then update .env:
# RUNNER_REGISTRATION_TOKEN=<paste-token-here>

# Restart the runner
docker restart gitea-act-runner

# Verify the runner is connected
docker logs gitea-act-runner

You can also register the runner via the Gitea web UI:

  1. Go to Site AdministrationRunners
  2. Click Create new runner
  3. Copy the token

Step 9: Configure Dokploy Domain / SSL

In Dokploy, configure the compose service's domain:

  1. Go to the "Infrastructure" project → compose service
  2. Add domain git.infra.donovankelly.xyz pointing to the gitea service on port 3000
  3. Enable HTTPS (Let's Encrypt)

Step 10: Update Git Remotes

On all machines that had the old remote:

git remote set-url origin https://git.infra.donovankelly.xyz/<user>/<repo>.git
# or for SSH:
git remote set-url origin ssh://git@git.infra.donovankelly.xyz:22222/<user>/<repo>.git

Step 11: Clean Up

  • Remove the old Gitea application from Dokploy
  • Remove old Docker volumes
  • Update any CI/CD webhooks pointing to the old domain
  • Update any OAuth apps using the old domain
  • Remove DNS record for git.infra.nkode.tech (optional, keep for redirect)

Rollback Plan

If migration fails:

  1. Stop the new stack: docker compose down
  2. Restart the old Gitea container in Dokploy
  3. The old data is untouched in /home/clawdbot/clawd/gitea-export/

Architecture

┌─────────────────────────────────────┐
│           Dokploy (Traefik)         │
│   git.infra.donovankelly.xyz:443    │
│              ↓ :3000                │
│  ┌─────────────────────────────┐    │
│  │         Gitea 1.24          │    │
│  │  (Actions enabled)          │    │
│  │  SSH :222 → external :22222 │    │
│  └──────────┬──────────────────┘    │
│             │                       │
│  ┌──────────▼──────────────────┐    │
│  │      PostgreSQL 16          │    │
│  │    (gitea database)         │    │
│  └─────────────────────────────┘    │
│                                     │
│  ┌─────────────────────────────┐    │
│  │     Act Runner              │    │
│  │  (CI/CD workflows)         │    │
│  └─────────────────────────────┘    │
└─────────────────────────────────────┘

Files

File Purpose
docker-compose.yml Service definitions
.env Secret values (DO NOT commit)
.env.example Template for secrets
MIGRATION.md This document