Added a few more articles

This commit is contained in:
Arunavo Ray
2025-10-03 13:15:24 +05:30
parent 21e2f4717c
commit beda2ce66c
10 changed files with 684 additions and 52 deletions

View File

@@ -19,7 +19,7 @@ import { useCases } from '@/lib/use-cases';
</div>
<div class="grid gap-4 sm:gap-6 lg:gap-8 lg:grid-cols-3">
{useCases.map((useCase) => (
{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">
@@ -60,5 +60,15 @@ import { useCases } from '@/lib/use-cases';
</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

@@ -32,4 +32,44 @@ export const useCases: UseCase[] = [
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

@@ -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

@@ -1,56 +1,97 @@
---
layout: ../../layouts/UseCaseLayout.astro
layout: ../../layouts/UseCaseIndexLayout.astro
title: "Gitea Mirror Use Cases"
description: "Discover the top workflows teams unlock with automated GitHub to Gitea mirroring."
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';
import { ArrowRight } from 'lucide-react';
<div class="mx-auto max-w-3xl px-4 text-center">
<span class="inline-flex items-center rounded-full border px-3 py-1 text-xs font-semibold uppercase tracking-widest text-muted-foreground">
Use Case Library
</span>
<h1 class="mt-6 text-3xl font-bold sm:text-4xl md:text-5xl">
Operational playbooks for backup-ready engineering teams
<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">
Each guide shows how to configure Gitea Mirror, schedule mirrors, and validate results so your team can ship with confidence.
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="mx-auto mt-16 grid max-w-6xl gap-6 px-4 sm:gap-8">
<div class="grid gap-4 sm:gap-6 lg:gap-8 lg:grid-cols-3">
{useCases.map((useCase) => (
<article class="group relative overflow-hidden rounded-3xl border bg-background/80 p-8 shadow-sm transition-all duration-300 hover:-translate-y-1 hover:shadow-lg">
<div class="absolute inset-0 rounded-3xl bg-gradient-to-br from-primary/5 via-accent/5 to-transparent opacity-0 transition-opacity duration-300 group-hover:opacity-100" />
<div class="relative">
<div class="flex flex-wrap items-center gap-3 text-xs font-medium uppercase tracking-wider text-muted-foreground">
<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">
<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>
<h2 class="mt-6 text-2xl font-semibold sm:text-3xl">
{useCase.title}
</h2>
<p class="mt-4 text-sm sm:text-base text-muted-foreground">
{useCase.summary}
</p>
<div class="mt-6 grid gap-4 text-sm sm:text-base text-muted-foreground">
<div>
<h3 class="text-sm font-semibold uppercase tracking-wide text-foreground/80">Pain Point</h3>
<p>{useCase.painPoint}</p>
</div>
<div>
<h3 class="text-sm font-semibold uppercase tracking-wide text-foreground/80">Outcome</h3>
<p>{useCase.outcome}</p>
</div>
</div>
<a
href={`/use-cases/${useCase.slug}/`}
class="mt-8 inline-flex items-center gap-2 text-sm font-semibold text-primary transition-colors hover:text-primary/80"
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" />
@@ -59,3 +100,21 @@ import { ArrowRight } from 'lucide-react';
</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,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/)