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,61 +1,120 @@
---
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
</h1>
<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.
</p>
</div>
<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="mx-auto mt-16 grid max-w-6xl gap-6 px-4 sm:gap-8">
{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">
{useCase.tags.map((tag) => (
<span class="inline-flex items-center rounded-full border border-muted px-3 py-1">
{tag}
</span>
))}
<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>
<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"
>
Read the playbook
<ArrowRight class="h-4 w-4 transition-transform group-hover:translate-x-1" />
</a>
</div>
</article>
))}
</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,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/)