Initial infrastructure setup: Gitea + PostgreSQL + Actions Runner
This commit is contained in:
21
.env.example
Normal file
21
.env.example
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Gitea Infrastructure Environment Variables
|
||||||
|
# Copy to .env and fill in values
|
||||||
|
|
||||||
|
# Domain
|
||||||
|
GITEA_DOMAIN=git.infra.donovankelly.xyz
|
||||||
|
|
||||||
|
# PostgreSQL
|
||||||
|
POSTGRES_USER=gitea
|
||||||
|
POSTGRES_PASSWORD=CHANGE_ME_generate_with_openssl_rand_hex_16
|
||||||
|
POSTGRES_DB=gitea
|
||||||
|
|
||||||
|
# Gitea Secrets (preserve from old instance's app.ini)
|
||||||
|
INTERNAL_TOKEN=
|
||||||
|
LFS_JWT_SECRET=
|
||||||
|
OAUTH2_JWT_SECRET=
|
||||||
|
SECRET_KEY=
|
||||||
|
|
||||||
|
# Gitea Actions Runner
|
||||||
|
# Generate after Gitea is running:
|
||||||
|
# docker exec gitea gitea actions generate-runner-token
|
||||||
|
RUNNER_REGISTRATION_TOKEN=REPLACE_ME_AFTER_FIRST_DEPLOY
|
||||||
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.env
|
||||||
249
MIGRATION.md
Normal file
249
MIGRATION.md
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
# 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.xyz` → `191.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`).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 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:
|
||||||
|
```bash
|
||||||
|
docker logs -f gitea
|
||||||
|
# Look for "Starting new Web server"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: Stop Gitea (Keep Postgres Running)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 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**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 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
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 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
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 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 Administration** → **Runners**
|
||||||
|
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:
|
||||||
|
```bash
|
||||||
|
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 |
|
||||||
127
docker-compose.yml
Normal file
127
docker-compose.yml
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
gitea:
|
||||||
|
image: docker.gitea.com/gitea:1.24
|
||||||
|
container_name: gitea
|
||||||
|
environment:
|
||||||
|
- USER_UID=1000
|
||||||
|
- USER_GID=1000
|
||||||
|
- GITEA_CUSTOM=/data/gitea
|
||||||
|
# Database
|
||||||
|
- GITEA__database__DB_TYPE=postgres
|
||||||
|
- GITEA__database__HOST=postgres:5432
|
||||||
|
- GITEA__database__NAME=${POSTGRES_DB}
|
||||||
|
- GITEA__database__USER=${POSTGRES_USER}
|
||||||
|
- GITEA__database__PASSWD=${POSTGRES_PASSWORD}
|
||||||
|
- GITEA__database__SSL_MODE=disable
|
||||||
|
# Server
|
||||||
|
- GITEA__server__DOMAIN=${GITEA_DOMAIN}
|
||||||
|
- GITEA__server__SSH_DOMAIN=${GITEA_DOMAIN}
|
||||||
|
- GITEA__server__ROOT_URL=https://${GITEA_DOMAIN}/
|
||||||
|
- GITEA__server__HTTP_PORT=3000
|
||||||
|
- GITEA__server__SSH_PORT=22222
|
||||||
|
- GITEA__server__SSH_LISTEN_PORT=222
|
||||||
|
- GITEA__server__START_SSH_SERVER=true
|
||||||
|
- GITEA__server__DISABLE_SSH=false
|
||||||
|
- GITEA__server__LFS_START_SERVER=true
|
||||||
|
- GITEA__server__LFS_JWT_SECRET=${LFS_JWT_SECRET}
|
||||||
|
- GITEA__server__OFFLINE_MODE=true
|
||||||
|
- GITEA__server__APP_DATA_PATH=/data/gitea
|
||||||
|
# Security
|
||||||
|
- GITEA__security__INSTALL_LOCK=true
|
||||||
|
- GITEA__security__SECRET_KEY=${SECRET_KEY}
|
||||||
|
- GITEA__security__INTERNAL_TOKEN=${INTERNAL_TOKEN}
|
||||||
|
- GITEA__security__REVERSE_PROXY_LIMIT=1
|
||||||
|
- GITEA__security__REVERSE_PROXY_TRUSTED_PROXIES=*
|
||||||
|
- GITEA__security__PASSWORD_HASH_ALGO=pbkdf2
|
||||||
|
# Service
|
||||||
|
- GITEA__service__DISABLE_REGISTRATION=true
|
||||||
|
- GITEA__service__REQUIRE_SIGNIN_VIEW=false
|
||||||
|
- GITEA__service__ENABLE_OPENID_SIGNUP=false
|
||||||
|
- GITEA__service__ENABLE_OPENID_SIGNIN=false
|
||||||
|
# OAuth2
|
||||||
|
- GITEA__oauth2__JWT_SECRET=${OAUTH2_JWT_SECRET}
|
||||||
|
# Actions
|
||||||
|
- GITEA__actions__ENABLED=true
|
||||||
|
# Repository
|
||||||
|
- GITEA__repository__ROOT=/data/git/repositories
|
||||||
|
- GITEA__repository__ENABLE_GO_GET=true
|
||||||
|
# LFS
|
||||||
|
- GITEA__lfs__PATH=/data/git/lfs
|
||||||
|
# Session
|
||||||
|
- GITEA__session__PROVIDER=file
|
||||||
|
- GITEA__session__PROVIDER_CONFIG=/data/gitea/sessions
|
||||||
|
# Log
|
||||||
|
- GITEA__log__MODE=console
|
||||||
|
- GITEA__log__LEVEL=info
|
||||||
|
# Mailer
|
||||||
|
- GITEA__mailer__ENABLED=false
|
||||||
|
# Cron
|
||||||
|
- GITEA__cron.update_checker__ENABLED=false
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- gitea-data:/data
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
- "22222:222"
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
networks:
|
||||||
|
- gitea-net
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:3000/api/v1/version"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 5
|
||||||
|
start_period: 60s
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: gitea-postgres
|
||||||
|
environment:
|
||||||
|
- POSTGRES_USER=${POSTGRES_USER}
|
||||||
|
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||||
|
- POSTGRES_DB=${POSTGRES_DB}
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- postgres-data:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- gitea-net
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_period: 30s
|
||||||
|
|
||||||
|
act-runner:
|
||||||
|
image: gitea/act_runner:latest
|
||||||
|
container_name: gitea-act-runner
|
||||||
|
environment:
|
||||||
|
- GITEA_INSTANCE_URL=http://gitea:3000
|
||||||
|
- GITEA_RUNNER_REGISTRATION_TOKEN=${RUNNER_REGISTRATION_TOKEN}
|
||||||
|
- GITEA_RUNNER_NAME=default-runner
|
||||||
|
- GITEA_RUNNER_LABELS=ubuntu-latest:docker://node:20-bookworm,ubuntu-22.04:docker://ubuntu:22.04
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- runner-data:/data
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
depends_on:
|
||||||
|
gitea:
|
||||||
|
condition: service_healthy
|
||||||
|
networks:
|
||||||
|
- gitea-net
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
gitea-data:
|
||||||
|
driver: local
|
||||||
|
postgres-data:
|
||||||
|
driver: local
|
||||||
|
runner-data:
|
||||||
|
driver: local
|
||||||
|
|
||||||
|
networks:
|
||||||
|
gitea-net:
|
||||||
|
driver: bridge
|
||||||
Reference in New Issue
Block a user