Merge pull request #111 from RayLabsHQ/www-seo

Writing a few guides on the application
This commit is contained in:
ARUNAVO RAY
2025-10-22 23:14:26 +05:30
committed by GitHub
28 changed files with 2889 additions and 953 deletions

View File

@@ -1,13 +1,30 @@
# Astro with Tailwind
# Gitea Mirror Marketing Site
```sh
bun create astro@latest -- --template with-tailwindcss
This Astro workspace powers the public marketing experience for Gitea Mirror. It includes the landing page, screenshots, call-to-action components, and the new use case library that highlights real-world workflows.
## Developing Locally
```bash
bun install
bun run dev
```
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/with-tailwindcss)
[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/with-tailwindcss)
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/with-tailwindcss/devcontainer.json)
The site is available at `http://localhost:4321`. Tailwind CSS v4 handles styling; classes can be used directly inside Astro, MDX, and React components.
Astro comes with [Tailwind](https://tailwindcss.com) support out of the box. This example showcases how to style your Astro project with Tailwind.
## Project Structure
For complete setup instructions, please see our [Tailwind Integration Guide](https://docs.astro.build/en/guides/integrations-guide/tailwind).
- `src/pages/index.astro` Main landing page
- `src/components/` Reusable UI (Header, Hero, Features, UseCases, etc.)
- `src/lib/use-cases.ts` Central data source for use case titles, summaries, and tags
- `src/pages/use-cases/` MDX guides for each use case, rendered with `UseCaseLayout`
- `src/layouts/UseCaseLayout.astro` Shared layout that injects the header, shader background, and footer into MDX guides
## Authoring Use Case Guides
1. Add or update a record in `src/lib/use-cases.ts`. This keeps the landing page and library listing in sync.
2. Create a new MDX file in `src/pages/use-cases/<slug>.mdx` with the `UseCaseLayout` layout and descriptive frontmatter.
3. Run `bun run dev` to preview the layout and ensure the new guide inherits global styles.
## Deployment
The marketing site is built with the standard Astro pipeline. Use `bun run build` to generate a production build before deploying.

View File

@@ -1,8 +1,8 @@
// @ts-check
import { defineConfig } from 'astro/config';
import tailwindcss from '@tailwindcss/vite';
import react from '@astrojs/react';
import mdx from '@astrojs/mdx';
// https://astro.build/config
export default defineConfig({
@@ -10,5 +10,5 @@ export default defineConfig({
plugins: [tailwindcss()]
},
integrations: [react()]
});
integrations: [react(), mdx()]
});

1037
www/bun.lock Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,236 +1,628 @@
# SEO Keywords & Content Strategy for Gitea Mirror
# SEO Keywords & Programmatic Content Strategy for Gitea Mirror
## Target Audience & Pain Points
### Primary Audience
- DevOps engineers managing GitHub repositories
- Companies looking to backup GitHub data
- Self-hosting enthusiasts
- Organizations migrating from GitHub to self-hosted solutions
- Developers needing GitHub disaster recovery
### Key Pain Points
- Manual GitHub to Gitea migration is time-consuming
- No automated backup solution for GitHub organizations
- Difficulty preserving repository structure during migration
- Need for scheduled, automatic synchronization
- Complex authentication setup for self-hosted Git services
## Keyword Categories & Opportunities
### 1. Problem-Solving Keywords (High Intent)
- **"github to gitea migration"** - Core functionality keyword
- **"mirror github repository to gitea"** - Direct search intent
- **"sync github gitea automatically"** - Automation focus
- **"backup github to self hosted"** - Backup use case
- **"github organization mirror tool"** - Organization-specific
- **"gitea import from github"** - Alternative phrasing
- **"migrate starred github repos"** - Specific feature
### 2. Comparison & Alternative Keywords
- **"github vs gitea migration"** - Comparison content
- **"gitea mirror alternatives"** - Competitor analysis
- **"self hosted github backup solutions"** - Solution category
- **"github repository sync tools"** - Tool category
- **"gitea github integration"** - Integration focus
- **"github backup automation"** - Automation emphasis
### 3. How-To & Tutorial Keywords
- **"how to mirror github to gitea"** - Tutorial intent
- **"setup gitea mirror docker"** - Installation guide
- **"gitea github sync tutorial"** - Step-by-step content
- **"automate github backup gitea"** - Automation tutorial
- **"mirror private github repos gitea"** - Private repos guide
- **"gitea import github wiki"** - Feature-specific tutorial
### 4. Feature-Specific Keywords
- **"gitea sso authentication setup"** - Auth feature
- **"gitea oidc provider configuration"** - OIDC setup
- **"gitea better auth integration"** - Specific tech stack
- **"gitea scheduled mirror"** - Scheduling feature
- **"gitea bulk repository import"** - Bulk operations
- **"gitea preserve organization structure"** - Organization feature
### 5. Platform & Deployment Keywords
- **"gitea mirror proxmox"** - Platform-specific
- **"gitea mirror docker compose"** - Docker deployment
- **"gitea mirror arm64"** - Architecture-specific
- **"gitea mirror reverse proxy"** - Infrastructure setup
- **"gitea authentik integration"** - Auth provider integration
### 6. Use Case Keywords
- **"self host github backup"** - Backup use case
- **"enterprise github migration gitea"** - Enterprise focus
- **"github disaster recovery gitea"** - DR use case
- **"github archive self hosted"** - Archival use case
- **"github organization backup automation"** - Org backup
### 7. Long-Tail Problem Keywords
- **"mirror github issues to gitea"** - Specific feature
- **"sync github releases gitea automatically"** - Release sync
- **"gitea mirror multiple organizations"** - Multi-org
- **"github starred repositories backup"** - Starred repos
- **"gitea mirror skip forks"** - Fork handling
### 8. Technical Integration Keywords
- **"gitea github api integration"** - API focus
- **"gitea webhook github sync"** - Webhook integration
- **"gitea ci/cd github mirror"** - CI/CD integration
- **"gitea github actions migration"** - Actions migration
## Blog Post Ideas & Content Strategy
### High-Priority Blog Posts
1. **"Complete Guide to Migrating from GitHub to Gitea in 2025"**
- **Target Keywords**: github to gitea migration, gitea import from github
- **Content**: Comprehensive migration guide with screenshots
- **Length**: 2,500-3,000 words
- **Include**: Step-by-step instructions, troubleshooting, best practices
2. **"How to Automatically Backup Your GitHub Repositories to Self-Hosted Gitea"**
- **Target Keywords**: backup github to self hosted, github backup automation
- **Content**: Focus on automation and scheduling features
- **Length**: 1,800-2,200 words
- **Include**: Docker setup, cron scheduling, backup strategies
3. **"Gitea Mirror vs Manual Migration: Which GitHub Migration Method is Best?"**
- **Target Keywords**: gitea mirror alternatives, github repository sync tools
- **Content**: Comparison post with pros/cons, feature matrix
- **Length**: 1,500-2,000 words
- **Include**: Comparison table, use case recommendations
4. **"Setting Up Enterprise GitHub Backup with Gitea Mirror and Docker"**
- **Target Keywords**: enterprise github migration gitea, github organization backup automation
- **Content**: Enterprise-focused guide with security considerations
- **Length**: 2,000-2,500 words
- **Include**: Multi-user setup, permission management, scaling
5. **"Mirror GitHub Organizations to Gitea While Preserving Structure"**
- **Target Keywords**: github organization mirror tool, gitea preserve organization structure
- **Content**: Deep dive into organization mirroring strategies
- **Length**: 1,500-1,800 words
- **Include**: Strategy explanations, configuration examples
6. **"Gitea SSO Setup: Complete Authentication Guide with Examples"**
- **Target Keywords**: gitea sso authentication setup, gitea oidc provider configuration
- **Content**: Cover all auth methods including header auth
- **Length**: 2,000-2,500 words
- **Include**: Provider examples (Google, Azure, Authentik)
7. **"How to Mirror Private GitHub Repositories to Your Gitea Instance"**
- **Target Keywords**: mirror private github repos gitea, gitea github api integration
- **Content**: Security-focused content with token management
- **Length**: 1,500-1,800 words
- **Include**: Token permissions, security best practices
8. **"Gitea Mirror on Proxmox: Ultimate Self-Hosting Guide"**
- **Target Keywords**: gitea mirror proxmox, self host github backup
- **Content**: LXC container setup tutorial
- **Length**: 1,800-2,200 words
- **Include**: Proxmox setup, resource allocation, networking
## Landing Page Optimization
### Title Tag Options
- "Gitea Mirror - Automated GitHub to Gitea Migration & Backup Tool"
- "GitHub to Gitea Mirror - Sync, Backup & Migrate Repositories Automatically"
- "Gitea Mirror - Self-Hosted GitHub Repository Backup & Sync Solution"
### Meta Description Options
- "Automatically mirror and backup your GitHub repositories to self-hosted Gitea. Support for organizations, private repos, scheduled sync, and SSO authentication. Docker & Proxmox ready."
- "The easiest way to migrate from GitHub to Gitea. Mirror repositories, organizations, issues, and releases automatically. Self-hosted backup solution with enterprise features."
### H1 Options
- "Automatically Mirror GitHub Repositories to Your Gitea Instance"
- "Self-Hosted GitHub Backup & Migration Tool for Gitea"
- "The Complete GitHub to Gitea Migration Solution"
### Key Landing Page Sections to Optimize
1. **Hero Section**
- Include primary keywords naturally
- Clear value proposition
- Quick start CTA
2. **Features Section**
- Target feature-specific keywords
- Use semantic variations
- Include comparison points
3. **Use Cases Section**
- Target use case keywords
- Include customer scenarios
- Enterprise focus subsection
4. **Installation Section**
- Target platform keywords
- Docker, Proxmox, manual options
- Quick start emphasis
5. **FAQ Section**
- Target long-tail keywords
- Common migration questions
- Technical integration queries
## Content Calendar Suggestions
### Month 1
- Week 1-2: "Complete Guide to Migrating from GitHub to Gitea"
- Week 3-4: "How to Automatically Backup Your GitHub Repositories"
### Month 2
- Week 1-2: "Gitea Mirror vs Manual Migration"
- Week 3-4: "Enterprise GitHub Backup Guide"
### Month 3
- Week 1-2: "Mirror GitHub Organizations Guide"
- Week 3-4: "Gitea SSO Setup Guide"
### Month 4
- Week 1-2: "Private Repository Mirroring"
- Week 3-4: "Gitea Mirror on Proxmox"
## SEO Research Tips
### When Using Ahrefs
1. **Search Volume**: Target 100-1,000 monthly searches initially
2. **Keyword Difficulty**: Aim for KD < 30 for new content
3. **SERP Analysis**: Check competitor content depth
4. **Parent Topics**: Find broader topics to target
5. **Featured Snippets**: Look for snippet opportunities
### Content Optimization
1. Include target keyword in:
- Title tag
- H1 (once)
- First 100 words
- At least one H2
- URL slug
- Meta description
2. Use semantic variations throughout
3. Include related keywords naturally
4. Optimize for search intent
5. Add schema markup for tutorials
## Tracking & Updates
### KPIs to Monitor
- Organic traffic growth
- Keyword rankings
- Click-through rates
- Conversion rates (signups/downloads)
- Time on page
### Regular Updates
- Review keyword performance monthly
- Update content quarterly
- Add new keywords based on search console data
- Monitor competitor content
- Track feature releases for new keyword opportunities
> **Goal**: Generate 5,000-15,000 organic visits/month within 6-12 months
> **Strategy**: Low-effort, high-intent pages targeting long-tail keywords
> **Focus**: Problem-solving content over generic tool descriptions
---
*Last Updated: [Current Date]*
*Next Review: [Date + 3 months]*
## 🎯 LOW-HANGING FRUIT: Quick Wins (Start This Week)
### Tier 1: Ultra Low-Effort, High-Intent Pages (1-2 hours each)
These are **simple template pages** with **minimal content** but **high search volume** and **buyer intent**.
| Page | Keyword | Monthly Searches | Difficulty | Effort | Priority |
|------|---------|-----------------|------------|--------|----------|
| `/use-cases/backup-github-repositories` | "backup github repositories" | 500-1K | Low (15) | 1h | ⭐⭐⭐⭐⭐ |
| `/use-cases/migrate-github-to-gitea` | "migrate github to gitea" | 300-800 | Low (10) | 1h | ⭐⭐⭐⭐⭐ |
| `/solutions/github-disaster-recovery` | "github disaster recovery" | 200-500 | Low (12) | 1h | ⭐⭐⭐⭐⭐ |
| `/vs/manual-vs-automated-github-migration` | "automated github migration" | 150-400 | Very Low (8) | 1.5h | ⭐⭐⭐⭐ |
| `/guides/setup-gitea-mirror-docker` | "gitea mirror docker setup" | 100-300 | Very Low (5) | 2h | ⭐⭐⭐⭐ |
**Why these work:**
- Specific, actionable queries ("how to backup", "migrate to")
- Low competition (KD < 15)
- High commercial intent (ready to install)
- Can reuse existing docs content
**Template for these pages:** 400-600 words, 30 minutes to write each
---
## 📊 KEYWORD STRATEGY: 3-Tier Approach
### Tier 1: Problem-Solving Keywords (HIGHEST PRIORITY)
**Intent**: "I have this specific problem"
**Effort**: Low (template-based)
**Pages needed**: 15
| Primary Keyword | Secondary Keywords | Est. Traffic | Page URL |
|----------------|-------------------|--------------|----------|
| backup github repositories | github backup tool, automated github backup | 500/mo | `/use-cases/backup-github-repositories` |
| migrate github to gitea | github gitea migration, import github to gitea | 400/mo | `/use-cases/migrate-github-to-gitea` |
| github disaster recovery | backup github organization, github downtime backup | 250/mo | `/solutions/github-disaster-recovery` |
| sync github to self-hosted | self-hosted github alternative, github to gitea sync | 200/mo | `/use-cases/sync-github-to-self-hosted-gitea` |
| preserve github history | github history backup, archive github repos | 180/mo | `/use-cases/preserve-github-history` |
| github vendor lock-in | avoid github lock-in, github alternatives | 150/mo | `/solutions/avoid-vendor-lock-in` |
| github backup automation | automate github mirror, scheduled github backup | 140/mo | `/use-cases/github-backup-automation` |
| mirror starred repositories | backup starred repos, export github stars | 120/mo | `/use-cases/starred-repos-collection` |
| github offline access | offline git mirror, air-gapped github | 100/mo | `/solutions/need-offline-git-access` |
| github rate limits | bypass github api limits, github api alternatives | 90/mo | `/solutions/github-rate-limits` |
**Total Tier 1 Traffic Potential**: ~2,500 visits/month
---
### Tier 2: Feature-Specific Keywords (MEDIUM PRIORITY)
**Intent**: "I want to do this specific thing"
**Effort**: Medium (requires explaining features)
**Pages needed**: 12
| Primary Keyword | Est. Traffic | Page URL |
|----------------|--------------|----------|
| mirror github issues | 80/mo | `/features/github-issues-migration` |
| sync github releases | 70/mo | `/features/github-releases-sync` |
| mirror github wiki | 60/mo | `/features/wiki-migration` |
| preserve github organization structure | 50/mo | `/features/organization-structure-preservation` |
| mirror private github repos | 180/mo | `/features/private-repository-mirroring` |
| github metadata migration | 45/mo | `/features/metadata-migration` |
| scheduled github sync | 120/mo | `/features/scheduled-synchronization` |
| batch github migration | 40/mo | `/features/batch-repository-processing` |
| github pull request migration | 35/mo | `/features/pull-request-mirroring` |
| git lfs mirror | 30/mo | `/features/git-lfs-support` |
**Total Tier 2 Traffic Potential**: ~1,200 visits/month
---
### Tier 3: Comparison Keywords (HIGH CONVERSION)
**Intent**: "Evaluating options"
**Effort**: Medium-High (research required)
**Pages needed**: 8
| Primary Keyword | Est. Traffic | Conversion Potential | Page URL |
|----------------|--------------|---------------------|----------|
| github backup tools comparison | 250/mo | Very High | `/vs/github-backup-solutions` |
| gitea vs github | 800/mo | Medium | `/vs/github-vs-gitea` |
| manual vs automated migration | 60/mo | High | `/vs/manual-vs-automated-migration` |
| git clone vs mirror | 45/mo | Medium | `/vs/git-clone-vs-automated-sync` |
| gitea alternatives | 150/mo | Medium | `/alternatives` |
| self-hosted git servers | 400/mo | Low | `/vs/self-hosted-vs-cloud-git` |
**Total Tier 3 Traffic Potential**: ~1,700 visits/month
---
## 🚀 IMPLEMENTATION ROADMAP: 4-Week Sprint
### Week 1: Foundation (5 pages)
**Goal**: Get first pages indexed, establish content structure
**Day 1-2: Setup** (4 hours)
- [ ] Create Astro content collections (`src/content/config.ts`)
- [ ] Build page templates (use-cases, features, solutions)
- [ ] Setup SEO component with structured data
- [ ] Create sitemap generator
**Day 3-5: Core Content** (8 hours)
- [ ] `/use-cases/backup-github-repositories` - 600 words
- [ ] `/use-cases/migrate-github-to-gitea` - 600 words
- [ ] `/solutions/github-disaster-recovery` - 500 words
- [ ] `/features/automatic-github-mirroring` - 700 words
- [ ] `/vs/manual-vs-automated-migration` - 800 words
**Day 6-7: Technical Setup** (3 hours)
- [ ] Submit sitemap to Google Search Console
- [ ] Setup Google Analytics 4
- [ ] Add schema.org markup
- [ ] Create robots.txt
- [ ] Setup canonical URLs
**Week 1 Target**: 5 pages live, indexed by Google
---
### Week 2: Scale Content (10 pages)
**Goal**: Batch create similar pages using templates
**Use Case Pages** (5 pages, 1 hour each):
- [ ] `/use-cases/sync-github-to-self-hosted-gitea`
- [ ] `/use-cases/preserve-github-history`
- [ ] `/use-cases/github-backup-automation`
- [ ] `/use-cases/starred-repos-collection`
- [ ] `/use-cases/vendor-lock-in-prevention`
**Feature Pages** (5 pages, 1.5 hours each):
- [ ] `/features/private-repository-mirroring`
- [ ] `/features/scheduled-synchronization`
- [ ] `/features/github-issues-migration`
- [ ] `/features/github-releases-sync`
- [ ] `/features/metadata-migration`
**Week 2 Target**: 15 total pages, monitor first impressions in GSC
---
### Week 3: Problem-Solution Focus (8 pages)
**Goal**: Target high-intent problem queries
**Solution Pages** (6 pages, 45 min each):
- [ ] `/solutions/avoid-vendor-lock-in`
- [ ] `/solutions/need-offline-git-access`
- [ ] `/solutions/github-rate-limits`
- [ ] `/solutions/github-pricing-too-expensive`
- [ ] `/solutions/comply-with-data-regulations`
- [ ] `/solutions/preserve-deleted-github-repos`
**Guide Pages** (2 pages, 2 hours each):
- [ ] `/guides/setup-gitea-mirror-docker`
- [ ] `/guides/migrate-github-organization-to-gitea`
**Week 3 Target**: 23 total pages, start seeing traffic
---
### Week 4: Comparison & Polish (7 pages + optimization)
**Goal**: High-conversion comparison content + optimization
**Comparison Pages** (4 pages, 2 hours each):
- [ ] `/vs/github-backup-solutions`
- [ ] `/vs/github-vs-gitea`
- [ ] `/vs/self-hosted-vs-cloud-git`
- [ ] `/alternatives`
**Integration Pages** (3 pages, 1 hour each):
- [ ] `/integrations/docker-compose`
- [ ] `/integrations/kubernetes`
- [ ] `/integrations/helm-charts`
**Optimization** (8 hours):
- [ ] Add internal linking between all pages
- [ ] Optimize images (WebP, alt text)
- [ ] Add FAQ sections to top 10 pages
- [ ] Create content calendar for Month 2
**Week 4 Target**: 30 total pages, 50-100 visitors/week
---
## 📝 CONTENT TEMPLATES
### Template 1: Use Case Page (400-600 words, 30 min)
```markdown
# [Use Case Title] - Gitea Mirror
> **In this guide**: Learn how to [solve specific problem] using Gitea Mirror's automated [feature].
## The Problem
[2-3 sentences describing the pain point]
**Common challenges:**
- Challenge 1
- Challenge 2
- Challenge 3
## How Gitea Mirror Solves This
[3-4 sentences explaining the solution]
**Key capabilities:**
- ✅ Capability 1
- ✅ Capability 2
- ✅ Capability 3
## Quick Start (5 Minutes)
\`\`\`bash
# Step 1: Pull the Docker image
docker pull giteamirror/gitea-mirror:latest
# Step 2: Run with environment variables
docker run -d \\
-e GITHUB_TOKEN=your_token \\
-e GITEA_URL=https://gitea.example.com \\
giteamirror/gitea-mirror
\`\`\`
[2 sentences on what happens next]
## Real-World Example
[Short scenario: "A DevOps team needed to..."]
## Related Features
- [Link to feature 1]
- [Link to feature 2]
## Get Started
[CTA button/link to GitHub repo]
---
**Keywords**: [primary], [secondary], [tertiary]
**Last Updated**: [Date]
```
**Why this works:**
- Answers search query immediately
- Shows code (high engagement)
- Internal links (SEO juice)
- Clear CTA
- **Total time: 30 minutes**
---
### Template 2: Feature Page (500-700 words, 45 min)
```markdown
# [Feature Name] - Gitea Mirror
> Automatically [feature benefit] from GitHub to Gitea with zero manual work.
## What Is [Feature Name]?
[2-3 sentences explaining the feature]
## Why You Need This
**Without Gitea Mirror:**
- ❌ Manual problem 1
- ❌ Manual problem 2
- ❌ Manual problem 3
**With Gitea Mirror:**
- ✅ Automated solution 1
- ✅ Automated solution 2
- ✅ Automated solution 3
## How It Works
1. **Step 1**: [Action]
2. **Step 2**: [Action]
3. **Step 3**: [Result]
## Configuration
\`\`\`yaml
# Example configuration
feature_enabled: true
option1: value
option2: value
\`\`\`
## Use Cases
### Use Case 1
[Scenario where this feature helps]
### Use Case 2
[Another scenario]
## Best Practices
- Tip 1
- Tip 2
- Tip 3
## See It In Action
[Screenshot or GIF]
## Get Started
[CTA]
---
**Related**:
- [Use case page]
- [Guide page]
```
---
### Template 3: Solution Page (300-500 words, 20 min)
```markdown
# [Problem Statement] - Solved
> **The Problem**: [One sentence problem]
> **The Solution**: Gitea Mirror's automated [approach]
## Why This Problem Matters
[2 sentences on impact]
**Consequences of not solving:**
1. Consequence 1
2. Consequence 2
3. Consequence 3
## How Gitea Mirror Fixes This
[Explain the solution in 3-4 sentences]
## Implementation
\`\`\`bash
# 2-3 line code snippet
\`\`\`
## Success Story
"[Quote or short anecdote]"
## Next Steps
1. [Link to getting started]
2. [Link to relevant feature]
[CTA button]
```
**Total time: 20 minutes**
---
## 🎨 SEO OPTIMIZATION CHECKLIST
### On-Page SEO (Per Page)
```
✅ Title tag: [Keyword] - Gitea Mirror (50-60 chars)
✅ Meta description with CTA (150-160 chars)
✅ H1 includes primary keyword
✅ URL slug = primary keyword
✅ First paragraph mentions keyword
✅ H2s include semantic variations
✅ Image alt text descriptive
✅ Internal links (3-5 per page)
✅ External links (1-2 authoritative sources)
✅ Schema.org markup (SoftwareApplication)
✅ Canonical URL set
✅ Mobile responsive
✅ Page speed < 3s
```
### Content Quality Checks
```
✅ Answers search intent completely
✅ 400-1500 word count (based on competition)
✅ Code examples where relevant
✅ Screenshots/visuals
✅ Updated date visible
✅ Clear CTA
✅ Related content links
✅ No keyword stuffing (1-2% density)
```
---
## 📈 TRACKING & METRICS
### Week 1-2 KPIs
- [ ] All pages indexed in Google (check GSC)
- [ ] 0 technical SEO errors (screaming frog)
- [ ] < 3s page load time
- [ ] Mobile usability 100/100
### Week 3-4 KPIs
- [ ] 10+ impressions/day in GSC
- [ ] 3+ clicks/day from organic
- [ ] 1+ page ranking in top 50
### Month 2 Goals
- [ ] 100+ impressions/day
- [ ] 20+ clicks/day
- [ ] 10+ keywords in top 50
- [ ] 5+ keywords in top 20
### Month 3 Goals
- [ ] 500+ impressions/day
- [ ] 50+ clicks/day
- [ ] 20+ keywords in top 20
- [ ] 10+ keywords in top 10
---
## 🔗 INTERNAL LINKING STRATEGY
**Hub & Spoke Model**
### Hub Pages (Link FROM these everywhere)
1. Homepage
2. `/use-cases/migrate-github-to-gitea` (main use case)
3. `/features/automatic-github-mirroring` (main feature)
### Spoke Pages (Link TO hubs + related spokes)
- Use case pages link to: Related features, guides, solutions
- Feature pages link to: Use cases, guides
- Solution pages link to: Use cases, features
- Guide pages link to: Features, use cases
**Example**:
```
/use-cases/backup-github-repositories
→ Links to:
- /features/scheduled-synchronization
- /features/automatic-github-mirroring
- /guides/setup-gitea-mirror-docker
- /solutions/github-disaster-recovery
```
---
## 💡 CONTENT HACKS: Work Smarter
### 1. Batch Similar Pages (2x faster)
Write all "use case" pages in one session using the template. Copy structure, change specifics.
### 2. Reuse Existing Content
- Main repo README Use case pages
- Docker docs Guide pages
- GitHub issues Problem pages
### 3. AI-Assisted Expansion
- Write 200-word outline manually
- Expand with AI to 600 words
- Edit for accuracy (10 min)
- **Time saved: 50%**
### 4. Screenshot Once, Use Everywhere
Create a `/public/screenshots/` library:
- Dashboard view
- Configuration screen
- Migration in progress
- Results page
Reuse across all pages.
### 5. Schema Markup Template
Create one JSON-LD template, reuse with variable substitution:
```json
{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "Gitea Mirror",
"description": "[PAGE_DESCRIPTION]",
"url": "[PAGE_URL]"
}
```
---
## 🎯 MONTH 2-3 EXPANSION PLAN
### Month 2: Depth Over Breadth
**Goal**: Make existing pages rank higher
**Activities**:
- [ ] Add 200 words to each existing page
- [ ] Add FAQ sections (5 Q&As per page)
- [ ] Create 10 more guide pages (tutorials)
- [ ] Add video embeds (YouTube shorts)
- [ ] Guest post on Dev.to (backlinks)
**New Pages** (10):
- 5 more use case pages
- 5 advanced guides
### Month 3: Authority Building
**Goal**: Establish Gitea Mirror as THE GitHub migration resource
**Activities**:
- [ ] Ultimate Guide: "Complete GitHub to Gitea Migration Guide" (3,000 words)
- [ ] Comparison matrix: All GitHub backup tools
- [ ] Interactive tool: "Migration time calculator"
- [ ] Video tutorials (5-10 minutes each)
- [ ] Community: Add testimonials/case studies
**New Pages** (15):
- 5 integration pages
- 5 technical spec pages
- 5 advanced solution pages
---
## 🏆 SUCCESS METRICS (6 Months)
### Conservative Target
- **Pages**: 50 indexed
- **Traffic**: 5,000 visits/month
- **Keywords**: 30 in top 20
- **Backlinks**: 15-20
- **GitHub Stars**: +50 from organic
### Optimistic Target
- **Pages**: 80 indexed
- **Traffic**: 12,000 visits/month
- **Keywords**: 50 in top 20, 20 in top 10
- **Backlinks**: 40-50
- **GitHub Stars**: +200 from organic
---
## 🔧 TECHNICAL SETUP (Do Once)
### Astro Content Collections
```typescript
// src/content/config.ts
import { defineCollection, z } from 'astro:content';
const useCases = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
description: z.string(),
keywords: z.array(z.string()),
problem: z.string(),
solution: z.string(),
difficulty: z.enum(['beginner', 'intermediate', 'advanced']),
timeToRead: z.number(),
relatedPages: z.array(z.string()).optional(),
}),
});
export const collections = {
'use-cases': useCases,
'features': defineCollection({ /* ... */ }),
'guides': defineCollection({ /* ... */ }),
'solutions': defineCollection({ /* ... */ }),
'vs': defineCollection({ /* ... */ }),
};
```
### Dynamic Route Template
```astro
---
// src/pages/use-cases/[...slug].astro
import { getCollection } from 'astro:content';
export async function getStaticPaths() {
const useCases = await getCollection('use-cases');
return useCases.map(entry => ({
params: { slug: entry.slug },
props: { entry },
}));
}
const { entry } = Astro.props;
const { Content } = await entry.render();
---
<Layout title={entry.data.title} description={entry.data.description}>
<article>
<h1>{entry.data.title}</h1>
<Content />
</article>
</Layout>
```
---
## 📋 QUICK ACTION CHECKLIST
**Today:**
- [ ] Create content collections structure
- [ ] Write first use case page (1 hour)
- [ ] Setup Google Search Console
**This Week:**
- [ ] Complete 5 high-priority pages
- [ ] Submit sitemap
- [ ] Add schema markup
**This Month:**
- [ ] 30 pages live
- [ ] Internal linking complete
- [ ] First organic traffic
---
**Last Updated**: January 2025
**Next Review**: February 2025
**Owner**: [Your Team]

View File

@@ -15,9 +15,10 @@ export function Header() {
}, []);
const navLinks = [
{ href: '#features', label: 'Features' },
{ href: '#screenshots', label: 'Screenshots' },
{ href: '#installation', label: 'Installation' }
{ href: '/#features', label: 'Features' },
{ href: '/#use-cases', label: 'Use Cases' },
{ href: '/#screenshots', label: 'Screenshots' },
{ href: '/#installation', label: 'Installation' }
];
return (
@@ -27,7 +28,7 @@ export function Header() {
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex items-center justify-between h-16">
{/* Logo */}
<a href="#" className="flex items-center gap-2 group">
<a href="/" className="flex items-center gap-2 group">
<img
src="/assets/logo.png"
alt="Gitea Mirror Logo"
@@ -65,4 +66,4 @@ export function Header() {
</header>
);
}
}

View File

@@ -93,32 +93,6 @@ export function Hero() {
/>
</a>
</div>
{/* Call to action buttons */}
{/* <div className="mt-8 sm:mt-10 flex flex-col sm:flex-row items-center justify-center gap-3 sm:gap-4 px-4 z-20">
<Button
size="lg"
className="relative group w-full sm:w-auto min-h-[48px] text-base bg-gradient-to-r from-primary to-accent hover:from-primary/90 hover:to-accent/90 shadow-lg shadow-primary/25 hover:shadow-xl hover:shadow-primary/30 transition-all duration-300"
asChild
>
<a
href="https://github.com/RayLabsHQ/gitea-mirror"
target="_blank"
rel="noopener noreferrer"
>
Get Started
<ArrowRight className="ml-2 h-4 w-4 transition-transform group-hover:translate-x-1" />
</a>
</Button>
<Button
size="lg"
variant="outline"
className="relative w-full sm:w-auto min-h-[48px] text-base border-primary/20 hover:bg-primary/10 hover:border-primary/30 hover:text-foreground transition-all duration-300"
asChild
>
<a href="#features">View Features</a>
</Button>
</div> */}
</div>
</section>
);

View File

@@ -0,0 +1,74 @@
---
import { ArrowRight } from 'lucide-react';
import { useCases } from '@/lib/use-cases';
---
<section id="use-cases" class="py-16 sm:py-24 px-4 sm:px-6 lg:px-8 bg-muted/30 border-y">
<div class="max-w-7xl mx-auto">
<div class="text-center max-w-3xl mx-auto mb-12 sm:mb-16">
<span class="inline-flex items-center rounded-full border px-3 py-1 text-xs font-semibold uppercase tracking-widest text-muted-foreground mb-4">
Use Cases
</span>
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold tracking-tight">
Proven Ways Teams Depend on
<span class="text-gradient from-primary to-accent block sm:inline"> Gitea Mirror</span>
</h2>
<p class="mt-4 text-base sm:text-lg text-muted-foreground">
Explore real-world workflows where automated mirroring removes risk, accelerates migrations, and keeps engineering teams shipping.
</p>
</div>
<div class="grid gap-4 sm:gap-6 lg:gap-8 lg:grid-cols-3">
{useCases.slice(0, 3).map((useCase) => (
<article class="group relative flex flex-col rounded-2xl border bg-background/80 p-6 sm:p-8 shadow-sm transition-all duration-300 hover:-translate-y-1 hover:shadow-lg">
<div class="absolute inset-0 rounded-2xl bg-gradient-to-br from-primary/5 via-accent/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
<div class="relative flex flex-col h-full">
<h3 class="text-xl font-semibold mb-3">
{useCase.title}
</h3>
<p class="text-sm sm:text-base text-muted-foreground mb-4">
{useCase.summary}
</p>
<dl class="grid gap-3 text-sm sm:text-base text-muted-foreground">
<div>
<dt class="font-semibold text-foreground">Pain Point</dt>
<dd>{useCase.painPoint}</dd>
</div>
<div>
<dt class="font-semibold text-foreground">Outcome</dt>
<dd>{useCase.outcome}</dd>
</div>
</dl>
<div class="mt-6 flex flex-wrap gap-2">
{useCase.tags.map((tag) => (
<span class="inline-flex items-center rounded-full border border-muted px-3 py-1 text-xs font-medium uppercase tracking-wide text-muted-foreground">
{tag}
</span>
))}
</div>
<a
href={`/use-cases/${useCase.slug}/`}
class="mt-auto inline-flex items-center gap-2 pt-6 text-sm font-medium text-primary transition-colors hover:text-primary/80"
>
Read the playbook
<ArrowRight class="h-4 w-4 transition-transform group-hover:translate-x-1" />
</a>
</div>
</article>
))}
</div>
<div class="mt-10 text-center">
<a
href="/use-cases/"
class="inline-flex items-center gap-2 rounded-full border border-primary/40 bg-primary/10 px-6 py-2 text-sm font-semibold text-primary transition-colors hover:bg-primary/15"
>
View more use cases
<ArrowRight class="h-4 w-4" />
</a>
</div>
</div>
</section>

View File

@@ -0,0 +1,79 @@
import { useCases } from '@/lib/use-cases';
import { ArrowRight } from 'lucide-react';
const featured = useCases.slice(0, 3);
const more = useCases.slice(3);
export function FeaturedUseCases() {
return (
<div className="mt-8 grid gap-6 lg:grid-cols-3">
{featured.map((item) => (
<article key={item.slug} className="group relative flex flex-col rounded-3xl border border-primary/50 bg-primary/5 p-6 sm:p-7 shadow-lg shadow-primary/10 transition-all duration-300 hover:-translate-y-1">
<div className="flex flex-wrap items-center gap-2 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground">
{item.tags.map((tag) => (
<span key={tag} className="inline-flex items-center rounded-full border border-muted px-2.5 py-1">{tag}</span>
))}
</div>
<h2 className="mt-4 text-xl font-semibold sm:text-2xl text-foreground">{item.title}</h2>
<p className="mt-3 text-sm sm:text-base text-muted-foreground">{item.summary}</p>
<div className="mt-5 grid gap-3 text-sm text-muted-foreground">
<div>
<h3 className="text-xs font-semibold uppercase tracking-wide text-foreground/70">Pain point</h3>
<p>{item.painPoint}</p>
</div>
<div>
<h3 className="text-xs font-semibold uppercase tracking-wide text-foreground/70">Outcome</h3>
<p>{item.outcome}</p>
</div>
</div>
<a
href={`/use-cases/${item.slug}/`}
className="mt-6 inline-flex w-max items-center gap-2 rounded-full border border-primary/50 px-4 py-2 text-sm font-semibold text-primary transition-colors hover:bg-primary/10"
>
View playbook
<ArrowRight className="h-4 w-4 transition-transform group-hover:translate-x-1" />
</a>
</article>
))}
</div>
);
}
export function MoreUseCases() {
return (
<div className="mt-8 grid gap-6 md:grid-cols-2">
{more.map((item) => (
<article key={item.slug} className="group relative flex flex-col rounded-3xl border border-muted bg-background/70 p-6 sm:p-7 transition-all duration-300 hover:-translate-y-1 hover:border-primary/40 hover:shadow-lg">
<div className="flex flex-wrap items-center gap-2 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground">
{item.tags.map((tag) => (
<span key={tag} className="inline-flex items-center rounded-full border border-muted px-2.5 py-1">{tag}</span>
))}
</div>
<h2 className="mt-4 text-xl font-semibold sm:text-2xl text-foreground/90">{item.title}</h2>
<p className="mt-3 text-sm sm:text-base text-muted-foreground">{item.summary}</p>
<div className="mt-5 grid gap-3 text-sm text-muted-foreground">
<div>
<h3 className="text-xs font-semibold uppercase tracking-wide text-foreground/70">Pain point</h3>
<p>{item.painPoint}</p>
</div>
<div>
<h3 className="text-xs font-semibold uppercase tracking-wide text-foreground/70">Outcome</h3>
<p>{item.outcome}</p>
</div>
</div>
<a
href={`/use-cases/${item.slug}/`}
className="mt-6 inline-flex w-max items-center gap-2 rounded-full border border-primary/50 px-4 py-2 text-sm font-semibold text-primary transition-colors hover:bg-primary/10"
>
View playbook
<ArrowRight className="h-4 w-4 transition-transform group-hover:translate-x-1" />
</a>
</article>
))}
</div>
)
}

View File

@@ -0,0 +1,115 @@
---
import '../styles/global.css';
import { Header } from '../components/Header';
import Footer from '../components/Footer.astro';
const {
content: {
title = 'Use Case',
description = 'Explore how Gitea Mirror helps engineering teams stay resilient.',
canonical = 'https://gitea-mirror.com/use-cases',
}
} = Astro.props;
---
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>{title} · Gitea Mirror</title>
<meta name="description" content={description} />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="canonical" href={canonical} />
<script is:inline>
const theme = localStorage.getItem('theme') ||
(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
document.documentElement.classList.toggle('dark', theme === 'dark');
</script>
</head>
<body class="min-h-screen bg-background text-foreground antialiased">
<Header client:load />
<main class="pt-24 pb-20">
<article class="use-case-content mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<slot />
</article>
</main>
<Footer />
</body>
</html>
<style is:global>
.use-case-content {
display: flex;
flex-direction: column;
gap: 2rem;
padding-top: 3rem;
padding-bottom: 3rem;
font-size: 1rem;
line-height: 1.75;
}
.use-case-content > :is(h1, h2, h3) {
font-weight: 700;
color: var(--foreground);
letter-spacing: -0.01em;
}
.use-case-content h1 {
font-size: clamp(2rem, 3vw + 1rem, 2.75rem);
}
.use-case-content h2 {
font-size: clamp(1.5rem, 2.5vw + 0.75rem, 2.125rem);
margin-top: 1rem;
}
.use-case-content h3 {
font-size: clamp(1.25rem, 1.5vw + 0.75rem, 1.5rem);
}
.use-case-content p {
margin: 0;
color: var(--muted-foreground);
}
.use-case-content ul,
.use-case-content ol {
padding-left: 1.5rem;
display: grid;
gap: 0.5rem;
color: var(--muted-foreground);
}
.use-case-content li::marker {
color: var(--primary);
}
.use-case-content pre {
background-color: color-mix(in srgb, var(--muted) 70%, transparent);
border-radius: 1rem;
padding: 1rem 1.25rem;
font-family: 'Fira Code', 'JetBrains Mono', ui-monospace, SFMono-Regular, monospace;
font-size: 0.95rem;
overflow-x: auto;
}
.use-case-content code:not(pre code) {
background-color: color-mix(in srgb, var(--muted) 70%, transparent);
color: var(--foreground);
padding: 0.1rem 0.35rem;
border-radius: 0.4rem;
font-size: 0.92em;
}
.use-case-content a {
color: color-mix(in srgb, var(--primary) 85%, var(--accent));
font-weight: 600;
text-decoration: underline;
text-decoration-thickness: 2px;
text-decoration-color: color-mix(in srgb, var(--primary) 50%, transparent);
}
.use-case-content a:hover {
text-decoration-color: var(--primary);
}
</style>

View File

@@ -0,0 +1,115 @@
---
import '../styles/global.css';
import { Header } from '../components/Header';
import Footer from '../components/Footer.astro';
const {
content: {
title = 'Use Case',
description = 'Explore how Gitea Mirror helps engineering teams stay resilient.',
canonical = 'https://gitea-mirror.com/use-cases',
}
} = Astro.props;
---
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>{title} · Gitea Mirror</title>
<meta name="description" content={description} />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="canonical" href={canonical} />
<script is:inline>
const theme = localStorage.getItem('theme') ||
(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
document.documentElement.classList.toggle('dark', theme === 'dark');
</script>
</head>
<body class="min-h-screen bg-background text-foreground antialiased">
<Header client:load />
<main class="pt-24 pb-20">
<article class="use-case-content mx-auto max-w-3xl px-4 sm:px-6 lg:px-8">
<slot />
</article>
</main>
<Footer />
</body>
</html>
<style is:global>
.use-case-content {
display: flex;
flex-direction: column;
gap: 2rem;
padding-top: 3rem;
padding-bottom: 3rem;
font-size: 1rem;
line-height: 1.75;
}
.use-case-content > :is(h1, h2, h3) {
font-weight: 700;
color: var(--foreground);
letter-spacing: -0.01em;
}
.use-case-content h1 {
font-size: clamp(2rem, 3vw + 1rem, 2.75rem);
}
.use-case-content h2 {
font-size: clamp(1.5rem, 2.5vw + 0.75rem, 2.125rem);
margin-top: 1rem;
}
.use-case-content h3 {
font-size: clamp(1.25rem, 1.5vw + 0.75rem, 1.5rem);
}
.use-case-content p {
margin: 0;
color: var(--muted-foreground);
}
.use-case-content ul,
.use-case-content ol {
padding-left: 1.5rem;
display: grid;
gap: 0.5rem;
color: var(--muted-foreground);
}
.use-case-content li::marker {
color: var(--primary);
}
.use-case-content pre {
background-color: color-mix(in srgb, var(--muted) 70%, transparent);
border-radius: 1rem;
padding: 1rem 1.25rem;
font-family: 'Fira Code', 'JetBrains Mono', ui-monospace, SFMono-Regular, monospace;
font-size: 0.95rem;
overflow-x: auto;
}
.use-case-content code:not(pre code) {
background-color: color-mix(in srgb, var(--muted) 70%, transparent);
color: var(--foreground);
padding: 0.1rem 0.35rem;
border-radius: 0.4rem;
font-size: 0.92em;
}
.use-case-content a {
color: color-mix(in srgb, var(--primary) 85%, var(--accent));
font-weight: 600;
text-decoration: underline;
text-decoration-thickness: 2px;
text-decoration-color: color-mix(in srgb, var(--primary) 50%, transparent);
}
.use-case-content a:hover {
text-decoration-color: var(--primary);
}
</style>

75
www/src/lib/use-cases.ts Normal file
View File

@@ -0,0 +1,75 @@
export interface UseCase {
slug: string;
title: string;
summary: string;
painPoint: string;
outcome: string;
tags: string[];
}
export const useCases: UseCase[] = [
{
slug: 'backup-github-repositories',
title: 'Backup GitHub Repositories',
summary: 'Continuously mirror GitHub repositories into self-hosted Gitea so your side projects stay safe even when GitHub hiccups.',
painPoint: 'Homelabbers rely on GitHub availability but want local backups that preserve history, metadata, and LFS assets.',
outcome: 'Automated syncs capture full repository history, metadata, and file storage so you always have an up-to-date local copy.',
tags: ['Redundancy', 'Continuous Sync', 'Homelab'],
},
{
slug: 'deploy-with-helm-chart',
title: 'Deploy with Helm Chart',
summary: 'Install the project on Kubernetes in a few commands using the maintained Helm chart to keep your backup mirror humming.',
painPoint: 'Self-hosters want reproducible Git backups without hand-rolling manifests for every cluster or upgrade.',
outcome: 'Versioned Helm values capture backup config, making redeploys and upgrades fast, scriptable, and low-risk.',
tags: ['Kubernetes', 'Helm', 'Homelab'],
},
{
slug: 'proxmox-lxc-homelab',
title: 'Spin Up on Proxmox LXC',
summary: 'Run the one-liner Proxmox VE script to launch gitea-mirror inside a tuned LXC container for your lab backups.',
painPoint: 'Proxmox homelabbers want a repeatable Git backup without manually wiring containers, volumes, and services.',
outcome: 'The community script provisions the container, installs Bun, and wires persistence so mirroring works minutes after boot.',
tags: ['Proxmox', 'Automation', 'Homelab'],
},
{
slug: 'sync-github-to-self-hosted-gitea',
title: 'Sync GitHub to Self-Hosted Gitea',
summary: 'Run continuous mirrors so your homelab Gitea instance stays in lockstep with GitHub without manual pulls.',
painPoint: 'Tinkerers want to keep a local Gitea in sync but `git pull --mirror` cron jobs break on metadata and new repos.',
outcome: 'Gitea Mirror auto-discovers repos, syncs metadata, and respects intervals so your LAN copy matches upstream every hour.',
tags: ['Continuous Sync', 'Self-Hosted', 'Homelab'],
},
{
slug: 'preserve-github-history',
title: 'Preserve GitHub History Forever',
summary: 'Archive commit history, issues, and releases into Gitea so side projects survive account removals or repo deletion.',
painPoint: 'Homelab archivists fear SaaS changes wiping years of work, but manual exports miss metadata and LFS assets.',
outcome: 'Scheduled mirrors capture full history with metadata snapshots, giving you an air-gapped archive you control.',
tags: ['Archival', 'Metadata', 'Homelab'],
},
{
slug: 'github-backup-automation',
title: 'Automate GitHub Backups',
summary: 'Replace brittle scripts with policy-driven schedules, health checks, and alerts that keep your Git backups honest.',
painPoint: 'Cron jobs and shell scripts fail silently, leaving you with stale mirrors when you need a restore most.',
outcome: 'Gitea Mirror tracks sync status, retries failures, and exposes health endpoints so you can trust every backup window.',
tags: ['Automation', 'Observability', 'Homelab'],
},
{
slug: 'starred-repos-collection',
title: 'Build a Starred Repo Collection',
summary: 'Mirror starred GitHub projects into your own Gitea library so favorites stay browsable even when upstream disappears.',
painPoint: 'Curators star dozens of repos but lose them when owners delete or rename, and theres no offline copy.',
outcome: 'The starred collector funnels every star into a dedicated Gitea org with metadata intact for long-term tinkering.',
tags: ['Curation', 'Automation', 'Homelab'],
},
{
slug: 'vendor-lock-in-prevention',
title: 'Stay Ready to Leave GitHub',
summary: 'Keep an always-current mirror so you can pivot from GitHub to self-hosted tooling whenever policies shift.',
painPoint: 'Indie builders worry about pricing, auth changes, or ToS updates but lack a live fallback they can swap to instantly.',
outcome: 'Continuous mirrors mean you can flip DNS to Gitea, keep working locally, and evaluate alternatives without downtime.',
tags: ['Vendor Independence', 'Continuity', 'Homelab'],
},
];

View File

@@ -4,6 +4,7 @@ import { Header } from '../components/Header';
import { Hero } from '../components/Hero';
import ShaderBackground from '../components/ShaderBackground.astro';
import Features from '../components/Features.astro';
import UseCases from '../components/UseCases.astro';
import Screenshots from '../components/Screenshots.astro';
import { Installation } from '../components/Installation';
import { CTA } from '../components/CTA';
@@ -123,6 +124,7 @@ const structuredData = {
<Hero client:load />
</div>
<Features />
<UseCases />
<Screenshots />
<Installation client:load />
<CTA client:load />
@@ -187,4 +189,4 @@ const structuredData = {
}
</style>
</body>
</html>
</html>

View File

@@ -0,0 +1,92 @@
---
layout: ../../layouts/UseCaseLayout.astro
title: "Backup GitHub Repositories with Gitea Mirror"
description: "Run a homelab-friendly playbook to mirror GitHub into self-hosted Gitea with automated schedules, health checks, and restore drills."
canonical: "https://gitea-mirror.com/use-cases/backup-github-repositories/"
---
## Why homelabbers care
GitHub is great—right up until an outage, SSO change, or account lockout strands your projects. Gitea Mirror keeps a self-hosted copy of everything (history, metadata, LFS) so you can keep working locally. This playbook walks through the minimal Docker setup the project ships with and shows how to prove your backups actually work.
## Requirements
- Docker Engine and Compose on the host that will run the mirror
- A GitHub personal access token with `repo`, `read:org`, and `admin:org` if you mirror orgs
- A self-hosted Gitea instance (can be on the same box) and admin or org owner credentials
- Open ports 4321 (web UI) and 3000 (default Gitea) inside your network
## Step-by-step
### 1. Clone the repo and start the stack
```bash
git clone https://github.com/RayLabsHQ/gitea-mirror.git
cd gitea-mirror
docker compose -f docker-compose.alt.yml up -d
```
The `alt` compose file ships with sane defaults for a single-node backup mirror. It stores data in `./data`. If you need a different location, set `DATA_DIR=/path` in `.env` before boot.
Verify the containers:
```bash
docker compose -f docker-compose.alt.yml ps
docker compose -f docker-compose.alt.yml logs -f gitea-mirror
```
Wait for "Server started" before moving on.
### 2. Generate tokens and connect GitHub
1. Create a GitHub personal access token (classic) with at least `repo`, `read:org`, and `admin:org` if you want organization mirrors.
2. Log in to Gitea and create an access token for an admin/owner account with `write:repository`.
3. Visit `http://<host>:4321` and sign up—the first user becomes admin.
4. Complete the setup wizard:
- Paste the GitHub PAT and Gitea URL/token.
- Choose which GitHub owners (user/org) to track.
- Leave sync interval at the default 1 hour to start.
### 3. Stage your first backup job
On the dashboard:
1. Click **Sync Now** for a small test repository.
2. Open Gitea and confirm the mirror appears with the right owner/org.
3. Enable **Mirror metadata** and **Mirror LFS** if you rely on issues, wikis, or large assets.
For broader coverage, switch the organization strategy to **Preserve structure** so Gitea mirrors your GitHub org layout automatically.
### 4. Schedule a recurring sync window
Under **Settings → Mirror Options**:
- Set the global interval (for example 30 minutes) to keep backups fresh.
- If you only need nightly backups, add a schedule window such as `02:00-02:30`.
- Enable **Auto-discovery** so new repositories are picked up whenever they appear.
### 5. Prove the backup works
Treat the mirror like any other DR asset:
1. Temporarily block outbound GitHub access on your machine.
2. Clone from Gitea instead: `git clone http://<gitea-host>/<owner>/<repo>.git`.
3. Confirm commit history, tags, releases, and issues exist.
4. Remove the block and document the restore steps in your homelab wiki.
## Health checks & monitoring
- The container exposes `/api/health`; add it to Uptime Kuma, Healthchecks.io, or Prometheus.
- Mirror failures surface in the activity log; consider exporting them through the `/api/events` endpoint.
- Disk usage lives under `Settings → Storage`; make sure the host volume has headroom for LFS blobs.
## Hardening tips
- Put the stack behind a reverse proxy (Traefik, Caddy, Nginx) and enable TLS.
- Rotate both GitHub and Gitea tokens quarterly; the UI will flag expired credentials.
- Snapshot the `data/` volume (ZFS/BTRFS) or back it up with `restic` so the mirror survives host failure.
## Next steps
- Promote the mirror to read-only users who do not need GitHub access.
- Layer on the [Helm](../deploy-with-helm-chart) or [Proxmox LXC](../proxmox-lxc-homelab) playbooks when you outgrow the single-node setup.

View File

@@ -0,0 +1,106 @@
---
layout: ../../layouts/UseCaseLayout.astro
title: "Deploy Gitea Mirror with the Helm Chart"
description: "Install the Gitea Mirror backup service on Kubernetes with the official Helm chart, including secrets, persistence, and upgrade workflow."
canonical: "https://gitea-mirror.com/use-cases/deploy-with-helm-chart/"
---
## Why ship it to Kubernetes
If your homelab already runs a cluster (k3s, Talos, MicroK8s), Helm is the fastest way to keep Gitea Mirror close to the rest of your self-hosted stack. The chart in `helm/gitea-mirror` bundles the deployment, service, ingress, and persistence so you can version your backup mirror just like any other release.
## Requirements
- Kubernetes 1.23+ with storage (Rook, Longhorn, local-path, etc.)
- Helm 3.8+
- GitHub PAT and Gitea API token ready (same scopes as the Docker playbook)
- Namespace with outbound access to GitHub and your Gitea host
## Step-by-step
### 1. Prepare a values file
Create `values-gitea-mirror.yaml` with the credentials you want the chart to render. Only `github` and `gitea` fields are required for a basic backup deployment.
```yaml
gitea-mirror:
github:
username: "your-gh-user"
token: "ghp_..."
gitea:
url: "https://git.lab.local"
token: "gitea_..."
mirror:
interval: "30m"
owners:
- "your-gh-user"
persistence:
enabled: true
size: 5Gi
service:
type: ClusterIP
ingress:
enabled: true
className: "traefik"
hosts:
- host: "mirror.lab.local"
paths:
- path: "/"
pathType: Prefix
tls:
- hosts: ["mirror.lab.local"]
secretName: "mirror-tls"
```
### 2. Install into a namespace
```bash
kubectl create namespace gitea-mirror
helm upgrade --install gitea-mirror ./helm/gitea-mirror \
--namespace gitea-mirror \
--values values-gitea-mirror.yaml
```
Helm renders a `Deployment`, `Service`, optional `Ingress`, and PVC if persistence is enabled. The pod mounts storage at `/app/data` for the SQLite DB and cached repositories.
### 3. Verify the release
```bash
kubectl -n gitea-mirror get pods,svc,pvc
kubectl -n gitea-mirror logs deploy/gitea-mirror --tail=100
```
Watch for `Server started` in the logs. Once ready, browse to the ingress host (or userland port-forward with `kubectl port-forward svc/gitea-mirror 4321:8080`). Complete the first-run wizard just like the Docker playbook.
### 4. Keep it updated
- Pull chart updates when you bump the repo: `git pull` then re-run the `helm upgrade` command.
- Override the container image tag with `--set image.tag=v3.7.2` if you need to pin.
- Use Helm rollbacks if a release misbehaves: `helm rollback gitea-mirror <REVISION> -n gitea-mirror`.
## Observability
- Attach the `/api/health` endpoint to your clusters probing (Kubernetes probes are already configured by the chart).
- Expose the metrics endpoint via a `ServiceMonitor` if you run Prometheus; add `extraAnnotations` to make it discoverable.
- Watch PVC growth with `kubectl df-pv` or your storage dashboard to ensure LFS blobs do not exhaust the volume.
## Disaster-recovery drill
1. Scale the deployment down: `kubectl -n gitea-mirror scale deploy gitea-mirror --replicas=0`.
2. Snapshot the PVC (CSI snapshots or Velero).
3. Restore into a test namespace and scale the deployment back up.
4. Confirm you can log in and the mirrored repositories are intact.
## Cleanup
```bash
helm uninstall gitea-mirror -n gitea-mirror
kubectl delete namespace gitea-mirror
```
Remove the PVC manually if you want a clean slate: `kubectl delete pvc gitea-mirror-storage -n gitea-mirror`.
Ready to run on bare metal instead? Head over to the [Proxmox LXC playbook](../proxmox-lxc-homelab).

View File

@@ -0,0 +1,67 @@
---
layout: ../../layouts/UseCaseLayout.astro
title: "Automate GitHub Backups"
description: "Replace fragile cron scripts with scheduled mirrors, health checks, and alerts that keep GitHub backups trustworthy."
canonical: "https://gitea-mirror.com/use-cases/github-backup-automation/"
---
## Why automation beats cron
Shell scripts and `git clone --mirror` jobs work until they dont—usually when GitHub rotates tokens, repositories rename, or metadata gets missed. Gitea Mirror centralizes scheduling, retries, and monitoring so your backups keep running while you sleep.
## Requirements
- Gitea Mirror deployment with outbound HTTPS access
- GitHub PAT + Gitea token stored in the UI or environment
- Healthcheck endpoint (Healthchecks.io, Cronitor, Uptime Kuma) for alerts
- Optional: Mailer or webhook destinations for failure notifications
## Step-by-step
### 1. Configure schedules centrally
1. Visit **Settings → Mirror Options**.
2. Set the global interval (e.g. `30 minutes`).
3. Use **Schedule windows** to run heavy syncs overnight (e.g. `02:00-05:00`).
4. Override intervals per org/repo when you need faster protection for a critical project.
### 2. Turn on smart retries
- Under **Advanced**, enable **Backoff retries** so failed syncs retry with exponential delay.
- Toggle **Stale sync alerts** to get warned when a repo hasnt synced in your target window.
- Set the failure threshold (for example, alert after 3 consecutive failures).
### 3. Wire in health monitoring
- Add a Healthchecks.io ping to the **Outgoing webhooks** field with `/api/health`.
- If you self-host Uptime Kuma, create an HTTP check against `http://<mirror-host>:4321/api/health`.
- Subscribe an email or webhook channel under **Notifications** for failure summaries.
### 4. Manage credentials safely
- Store tokens in the built-in secret storage rather than `.env` files on disk.
- Turn on **Token expiry reminders** (set e.g. 30 days before the expiry) to rotate proactively.
- Use GitHub fine-grained PATs per org to minimize blast radius.
### 5. Document recovery steps
- Save the `docker compose`/Helm/Proxmox commands you used in your homelab wiki.
- Export the mirror configuration JSON (`/api/export`) monthly so you can rehydrate quickly.
- Note which repos are excluded and why; auditors will ask.
## Validate automation
- Force a failure by revoking a PAT, confirm alerts fire, then restore the token.
- Run `bun run manage-db check` (or the UI health check) to ensure migrations and tasks are clean.
- Diff the last sync times via the dashboard CSV export.
## Best practices
- Group repos by criticality so you can assign tighter schedules where it matters.
- Keep the mirror in the same timezone as your documentation to simplify scheduling.
- Pair automation with the [Preserve GitHub History](../preserve-github-history/) playbook to maintain context, not just code.
## Related playbooks
- [Backup GitHub Repositories](../backup-github-repositories/)
- [Run Gitea Mirror inside a Proxmox LXC](../proxmox-lxc-homelab/)

View File

@@ -0,0 +1,120 @@
---
layout: ../../layouts/UseCaseIndexLayout.astro
title: "Gitea Mirror Use Cases"
description: "Homelab-friendly playbooks that keep GitHub repos mirrored inside Gitea without promising enterprise guarantees."
canonical: "https://gitea-mirror.com/use-cases/"
---
import { ArrowRight, ShieldAlert, Sparkles, Home } from 'lucide-react';
import { useCases } from '@/lib/use-cases';
<section class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="rounded-3xl border border-primary/20 bg-gradient-to-br from-primary/10 via-background to-background p-8 sm:p-12 shadow-lg">
<div class="flex flex-wrap items-center gap-3 text-xs font-semibold uppercase tracking-[0.25em] text-primary">
<Sparkles class="h-4 w-4" />
Built by and for homelab tinkerers
</div>
<h1 class="mt-6 text-3xl font-bold sm:text-4xl md:text-[2.75rem] md:leading-tight">
Gitea Mirror in Action: Use Cases for Self-Hosted GitHub Backups
</h1>
<p class="mt-4 max-w-3xl text-base sm:text-lg text-muted-foreground">
Gitea Mirror is an open-source side project. Its perfect for your homelab, indie dev studio, or early-stage team that
needs backups and optional failover. Theres <strong class="font-semibold text-foreground">no enterprise SLA</strong>—just
practical playbooks you can own, fork, and improve.
</p>
<div class="mt-6 grid gap-4 sm:grid-cols-2">
<div class="flex items-start gap-3 rounded-2xl border border-muted bg-background/80 p-4">
<div>
<h2 class="!mt-0 text-sm font-semibold uppercase tracking-wide text-foreground/80">Ideal for</h2>
<p class="mt-1 text-sm text-muted-foreground">
Homelabbers, solo builders, and scrappy startups that want GitHub peace of mind without managed pricing.
</p>
</div>
</div>
<div class="flex items-start gap-3 rounded-2xl border border-muted bg-background/80 p-4">
<div>
<h2 class="!mt-0 text-sm font-semibold uppercase tracking-wide text-foreground/80">Worth noting</h2>
<p class="mt-1 text-sm text-muted-foreground">
Community support only. No compliance guarantees, no 24/7 pager. Kick the tires before depending on it.
</p>
</div>
</div>
</div>
</div>
</section>
<section id="use-cases" class="py-16 sm:py-24 px-4 sm:px-6 lg:px-8">
<div class="max-w-7xl mx-auto">
<div class="text-center max-w-3xl mx-auto mb-12 sm:mb-16">
<span class="inline-flex items-center rounded-full border px-3 py-1 text-xs font-semibold uppercase tracking-widest text-muted-foreground mb-4">
Use Cases
</span>
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold tracking-tight">
Real-World Gitea Mirror Workflows
</h2>
<p class="mt-4 text-base sm:text-lg text-muted-foreground">
Discover how developers and teams are using Gitea Mirror to create reliable, self-hosted backups of their GitHub repositories. These use cases provide step-by-step instructions for common scenarios.
</p>
</div>
<div class="grid gap-4 sm:gap-6 lg:gap-8 lg:grid-cols-3">
{useCases.map((useCase) => (
<article class="group relative flex flex-col rounded-2xl border bg-background/80 p-6 sm:p-8 shadow-sm transition-all duration-300 hover:-translate-y-1 hover:shadow-lg">
<div class="absolute inset-0 rounded-2xl bg-gradient-to-br from-primary/5 via-accent/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
<div class="relative flex flex-col h-full">
<h3 class="text-xl font-semibold mb-3">
{useCase.title}
</h3>
<p class="text-sm sm:text-base text-muted-foreground mb-4">
{useCase.summary}
</p>
<dl class="grid gap-3 text-sm sm:text-base text-muted-foreground">
<div>
<dt class="font-semibold text-foreground">Pain Point</dt>
<dd>{useCase.painPoint}</dd>
</div>
<div>
<dt class="font-semibold text-foreground">Outcome</dt>
<dd>{useCase.outcome}</dd>
</div>
</dl>
<div class="mt-6 flex flex-wrap gap-2">
{useCase.tags.map((tag) => (
<span class="inline-flex items-center rounded-full border border-muted px-3 py-1 text-xs font-medium uppercase tracking-wide text-muted-foreground">
{tag}
</span>
))}
</div>
<a
href={`/use-cases/${useCase.slug}/`}
class="mt-auto inline-flex items-center gap-2 pt-6 text-sm font-medium text-primary transition-colors hover:text-primary/80"
>
Read the playbook
<ArrowRight class="h-4 w-4 transition-transform group-hover:translate-x-1" />
</a>
</div>
</article>
))}
</div>
</div>
</section>
<section class="mx-auto mt-16 max-w-7xl px-4 sm:px-6 lg:px-8 pb-8">
<div class="rounded-3xl border border-primary/20 bg-primary/5 p-6 sm:p-10 text-center">
<h2 class="text-2xl font-semibold sm:text-3xl">Have a niche workflow?</h2>
<p class="mt-3 text-sm sm:text-base text-muted-foreground">
Fork the project, open an issue, or drop a PR. These guides are community-made—just like the tooling behind them.
</p>
<a
href="https://github.com/RayLabsHQ/gitea-mirror"
class="mt-6 inline-flex items-center gap-2 rounded-full border border-primary/50 bg-background px-5 py-2 text-sm font-semibold text-primary transition-colors hover:bg-primary/10"
>
Contribute on GitHub
<ArrowRight class="h-4 w-4" />
</a>
</div>
</section>

View File

@@ -0,0 +1,69 @@
---
layout: ../../layouts/UseCaseLayout.astro
title: "Preserve GitHub History Forever"
description: "Archive commits, issues, releases, and LFS assets into Gitea so hobby projects survive account removals or repo deletions."
canonical: "https://gitea-mirror.com/use-cases/preserve-github-history/"
---
## Keep the entire story, not just the code
GitHub accounts get banned, repos go private, and owners rage-delete history. If you care about the full timeline—issues, releases, wiki—Gitea Mirror snapshots everything on a schedule so the story survives in your homelab.
## Requirements
- Running Gitea Mirror (follow the [backup playbook](../backup-github-repositories/))
- GitHub PAT with metadata scopes (`repo`, `read:org`)
- Destination Gitea with enough disk for cloned repos + attachments
- Optional: object storage or snapshots for long-term archiving of the mirror volume
## Step-by-step
### 1. Set archival-friendly defaults
In the admin UI under **Settings → Mirror Options**:
- Enable **Mirror metadata**.
- Enable **Mirror releases** and **Mirror wiki**.
- Turn on **Include attachments** so release assets and issue uploads copy across.
### 2. Create an "Archive" organization in Gitea
1. In Gitea, create an org like `github-archive` with read-only members.
2. Back in Gitea Mirror, edit each owner and set the destination to the archive org.
3. Enable **Lock mirrors** so accidental edits on the archive side are blocked.
### 3. Choose retention & cadence
- Set the global interval to `1h` for active projects or `12h` for dormant ones.
- Configure **Snapshot retention** (for example `keep last 30`) so old mirror runs remain inspectable.
- Schedule a weekly full sync window during off-hours to re-check metadata drift.
### 4. Record provenance
- Tag each archived repo in Gitea with the upstream URL and the first mirrored date.
- Enable **Mirror webhooks** to push sync summaries into Matrix/Discord for auditing.
- Export a CSV of repos quarterly as part of your homelab documentation.
### 5. Back up the backup
- Snapshots: Use ZFS/BTRFS or Proxmox backups on the mirrors data volume.
- Offsite: `restic`/`rclone` the `data/` directory to a NAS or object store.
- Test: Restore to a test Gitea instance and spot-check history every few months.
## Verify the archive
1. Delete a draft issue on GitHub.
2. Wait for the next sync; open the issue in Gitea—you should still see the original content.
3. Compare `git tag -l` in both remotes to ensure releases match.
4. Use `git lfs ls-files` to confirm large assets made it across.
## Maintenance checklist
- Rotate tokens annually and document the rotation date in the repo README.
- Monitor disk growth; configure `persistence.size` if you run the Helm chart.
- Log anomalies—failed runs, conflicts—in your homelab journal to track trends.
## Related playbooks
- [Automate GitHub Backups](../github-backup-automation/)
- [Build a Starred Repo Collection](../starred-repos-collection/)

View File

@@ -0,0 +1,80 @@
---
layout: ../../layouts/UseCaseLayout.astro
title: "Run Gitea Mirror inside a Proxmox LXC"
description: "Provision the community-maintained Proxmox VE LXC container for Gitea Mirror and wire it into your homelab backup workflow."
canonical: "https://gitea-mirror.com/use-cases/proxmox-lxc-homelab/"
---
## Why run it on Proxmox
When most of your homelab lives in Proxmox VE, the community LXC script is the fastest path from zero to a managed Gitea Mirror node. It handles Bun, systemd, persistent storage, and future upgrades so you can focus on keeping Git backups fresh.
## Requirements
- Proxmox VE host with the [community-scripts repository](https://community-scripts.github.io/ProxmoxVE/) enabled
- Storage pool with ~6GB free (default script allocation) and an available bridge (usually `vmbr0`)
- GitHub PAT and Gitea token scoped for mirroring
- DNS or IP address for the container on your LAN
## Step-by-step
### 1. Launch the installer
SSH into the Proxmox host and run:
```bash
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/gitea-mirror.sh)"
```
The helper script prompts for:
- **Node**: the Proxmox host that will own the container
- **Storage**: local-lvm, ZFS dataset, etc.
- **Network bridge**: e.g. `vmbr0`
- **IP assignment**: DHCP or static (consider static for a backup appliance)
- **Container size**: defaults to 2 vCPU, 2GiB RAM, 6GiB disk—bump RAM if you mirror large orgs
Accept the defaults or adjust as needed. The script downloads the release, installs Bun, seeds systemd, and prints the access URL on completion.
### 2. First login and setup
1. Browse to `http://<container-ip>:4321`.
2. Create the admin account (first user = admin).
3. Enter your GitHub PAT and Gitea API token in the onboarding wizard.
4. Select the GitHub owners you want mirrored and enable auto-discovery for new repos.
### 3. Validate persistence and services
Inside the container (`pct enter <CTID>`):
```bash
systemctl status gitea-mirror
ls /opt/gitea-mirror/data
```
You should see `gitea-mirror.db` and a `repos/` directory. Data lives under `/opt/gitea-mirror/data`; back it up or snapshot the underlying storage pool regularly.
### 4. Expose the service (optional)
- Add a Proxmox firewall rule or reverse proxy entry (Traefik/Caddy/HAProxy) if you want TLS.
- Create a DNS record (`mirror.lab.local`) pointed at the container for easier access.
### 5. Upgrades & maintenance
- Re-run the installer script; it detects existing installs, backs up `/opt/gitea-mirror/data`, downloads the latest release, and restarts the service.
- Watch for warnings about upgrades from v2 → v3 wiping config—take a snapshot first if you still run v2 artifacts.
- Check logs with `journalctl -u gitea-mirror -n 200` or `journalctl -u gitea-mirror -f` for live tailing.
## Disaster-recovery drill
1. In Proxmox, snapshot the container (or use ZFS/BTRFS snapshots on the storage pool).
2. Stop GitHub access temporarily and clone from the Gitea mirror to confirm the backup works.
3. Restore the snapshot on a different node to ensure the service boots cleanly with the preserved data volume.
## Troubleshooting
- **Port 4321 already used**: change `PORT` in `/opt/gitea-mirror.env` and restart with `systemctl restart gitea-mirror`.
- **Disk full**: extend the container disk in Proxmox, then run `pct resize <CTID> rootfs +5G`.
- **Token expired**: log in to the UI → Settings to update GitHub/Gitea credentials.
Looking for a cluster-native deployment? Try the [Helm playbook](../deploy-with-helm-chart).

View File

@@ -0,0 +1,61 @@
---
layout: ../../layouts/UseCaseLayout.astro
title: "Build a Starred Repo Collection"
description: "Mirror your starred GitHub projects into a dedicated Gitea library so favorites remain available offline."
canonical: "https://gitea-mirror.com/use-cases/starred-repos-collection/"
---
## Curate without losing projects
Stars are a personal library—but they vanish when creators delete repos or your account is rate limited. Gitea Mirror can automatically capture every starred repository into a dedicated Gitea organization, complete with issues and releases, so your inspiration lives on.
## Requirements
- Gitea Mirror up and running (Docker, LXC, or Helm)
- GitHub PAT for the account whose stars you want mirrored
- Destination Gitea with a personal organization ready (e.g. `stars`)
- Optional: DNS entry for the mirror so friends can browse the collection
## Step-by-step
### 1. Enable starred owner tracking
1. In the onboarding wizard (or later under **Settings → Owners**), add your GitHub username.
2. Enable the **Include starred repositories** toggle.
3. Set the destination in Gitea to a dedicated org, e.g. `stars-jamie`.
### 2. Categorize the collection
- Create sub-organizations in Gitea (e.g. `stars-iot`, `stars-ai`).
- Use Destination Overrides inside the dashboard to route specific stars into themed orgs.
- Tag repos in Gitea with labels like `language:rust`, `topic:homelab` for quick filtering.
### 3. Schedule incremental updates
- Set the star discovery interval to something light like `1h` so new stars import quickly.
- Use the **Starred sync window** (e.g. `00:00-00:30`) to avoid interfering with org backups.
- Turn on **Starred repo cleanup** if you want unstarred projects removed from the library.
### 4. Showcase the library
- Point a read-only Gitea user at the org so friends can browse without write access.
- Host the Gitea instance behind a reverse proxy with HTTPS, then link it on your blog.
- Export the repo list weekly and share it as a curated newsletter.
## Verify the collection works
1. Star a new repo on GitHub.
2. Wait for the star interval or click **Sync now** in the dashboard.
3. Confirm the repo appears in your `stars` org with issues/releases intact.
4. Unstar it on GitHub; if cleanup is enabled, confirm it disappears on the next sync.
## Nice-to-haves
- Add a `README.md` in the Gitea org homepage explaining your tagging rules.
- Pair with [Preserve GitHub History](../preserve-github-history/) so you keep metadata, not just code.
- Use the [Helm deployment](../deploy-with-helm-chart/) if you want the collection available inside your cluster.
## Related playbooks
- [Backup GitHub Repositories](../backup-github-repositories/)
- [Automate GitHub Backups](../github-backup-automation/)

View File

@@ -0,0 +1,71 @@
---
layout: ../../layouts/UseCaseLayout.astro
title: "Sync GitHub to Your Self-Hosted Gitea"
description: "Keep a homelab Gitea instance continuously updated with GitHub by using Gitea Mirror's discovery, scheduling, and metadata sync."
canonical: "https://gitea-mirror.com/use-cases/sync-github-to-self-hosted-gitea/"
---
## Keep SaaS and self-hosted in lockstep
You may still collaborate on GitHub every day, yet want a LAN Gitea copy you control. Gitea Mirror bridges the two: it tracks owners, auto-discovers repos, mirrors metadata, and keeps a local instance only minutes behind upstream without hand-written cron jobs.
## Requirements
- Gitea Mirror deployed (Docker, Proxmox LXC, or Helm)
- GitHub PAT with `repo`, `read:org`, and `admin:org` scopes
- Gitea API token for the target account/org
- Stable connectivity between the mirror host and both GitHub + Gitea
## Step-by-step
### 1. Connect accounts in the admin wizard
1. Sign in at `http://<mirror-host>:4321`.
2. Open **Settings → Connections**.
3. Paste the GitHub PAT and choose the owners (user + orgs) you want mirrored.
4. Add your self-hosted Gitea URL and token; pick the destination org structure (typically **Preserve structure**).
### 2. Enable continuous discovery
- Go to **Settings → Mirror Options** and toggle **Auto-discovery**.
- Set the discovery interval (for example `15 minutes`) so new repositories, forks, and transfers sync automatically.
- Optionally add a "Starred" owner to pull in personal favorites alongside org repos.
### 3. Configure sync cadence
Decide how far behind GitHub the mirror can lag:
- Global interval: start with `15 minutes` for active projects.
- Use **Custom intervals** on specific orgs/repositories if you need faster mirrors (as low as 5 minutes).
- Set a quiet window (e.g. `01:00-05:00`) for heavy metadata pulls to avoid daytime throttling.
### 4. Mirror metadata and LFS
Under **Repository defaults**:
- Enable **Mirror metadata** so issues, labels, and milestones stay in sync.
- Enable **Mirror LFS** if your repos store binaries; confirm your Gitea instance has LFS enabled.
- Turn on **Delete missing** only if you want Gitea to remove repos when they disappear upstream.
### 5. Validate the local mirror
- Select a repo in the dashboard and click **Sync now**.
- In Gitea, verify commit history, tags, issues, and releases match GitHub.
- Run a quick diff: `git remote add gitea http://<gitea>/<owner>/<repo>.git && git fetch gitea` then `git log origin/main..gitea/main` — it should be empty.
## Monitoring & alerts
- Check the **Activity** page for failed runs; set up Healthchecks.io/webhooks on the `/api/health` endpoint.
- Enable email notifications so administrators learn about repeated failures or token expiry.
- Export `/api/repos/:id/logs` periodically to archive sync history alongside the repos themselves.
## Tips for smooth syncing
- Avoid running more than one mirror against the same Gitea target; let Gitea Mirror manage the schedule centrally.
- When restructuring orgs, pause auto-discovery, move repos in Gitea, then resume to prevent thrash.
- Rate limits cropping up? Move the mirror onto a different IP or configure GitHub fine-grained PATs per org.
## Related playbooks
- [Backup GitHub Repositories](../backup-github-repositories/) for the base Docker deployment
- [Run Gitea Mirror inside a Proxmox LXC](../proxmox-lxc-homelab/) if you want the mirror on a dedicated appliance

View File

@@ -0,0 +1,61 @@
---
layout: ../../layouts/UseCaseLayout.astro
title: "Stay Ready to Leave GitHub"
description: "Use Gitea Mirror to keep an always-current fallback so policy or pricing changes at GitHub never stall your projects."
canonical: "https://gitea-mirror.com/use-cases/vendor-lock-in-prevention/"
---
## Keep your exit hatch open
GitHub can change pricing, authentication rules, or terms without notice. With Gitea Mirror running, you always have a live copy of code and metadata inside infrastructure you control—so switching to self-hosted Gitea, Forgejo, or something else becomes a DNS change, not a fire drill.
## Requirements
- Production-ready Gitea instance (backed by your usual storage and TLS)
- Gitea Mirror configured with owner discovery and metadata sync
- Documentation of your current GitHub org structure (for validation)
- Optional: reverse proxy + SSO for a smooth cutover experience
## Step-by-step
### 1. Mirror everything continuously
- Add every GitHub organization you care about as an owner in Gitea Mirror.
- Enable **Preserve structure** so Giteas org layout matches GitHub.
- Turn on metadata + LFS mirroring to ensure issues, releases, and binaries are ready on day one.
### 2. Simulate a cutover
1. Pick a pilot team.
2. Ask them to work exclusively out of the Gitea mirror for a sprint.
3. Capture feedback about permissions, webhooks, CI integrations, and adjust.
### 3. Keep integrations dual-homed
- Point your CI (e.g. Woodpecker, Jenkins) at both GitHub and Gitea using mirrored tokens.
- Maintain matching webhook payloads so automation keeps running post-swap.
- Mirror secrets (deploy keys, bot accounts) into the Gitea org to remove blockers.
### 4. Document the flip procedure
- Write a runbook: DNS updates, webhook changes, `git remote set-url` commands.
- Version-control the document inside the mirror so updates stay in sync.
- Rehearse twice a year; include steps to roll back to GitHub if needed.
### 5. Watch for drift
- Review the Gitea mirror weekly for newly created repos, teams, or permissions.
- Parse the `/api/owners` endpoint to ensure auto-discovery still works.
- Set alerts on the mirrors activity log so you catch sync failures quickly.
## Success criteria
- A developer can change their `origin` remote to Gitea and push without errors.
- CI pipelines succeed when pointed exclusively at the mirror.
- All active repos have synced within your SLA (for example, last run < 2 hours ago).
- The runbook includes contact info, rollback steps, and verification checklists.
## Related playbooks
- [Sync GitHub to Your Self-Hosted Gitea](../sync-github-to-self-hosted-gitea/)
- [Deploy Gitea Mirror with the Helm Chart](../deploy-with-helm-chart/)