[{"data":1,"prerenderedAt":153},["ShallowReactive",2],{"seo-verification":3,"blog-migrate-your-github-repos-to-self-hosted-gitea-on-a-vps-en":6},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"id":7,"slug":8,"slugs":9,"title":12,"excerpt":13,"readTime":14,"views":15,"isPinned":16,"publishedAt":17,"category":18,"categories":23,"featuredImage":25,"bgImage":26,"posterImage":27,"relatedSolution":28,"intro":31,"sections":32,"ctaTitle":95,"ctaBody":96,"ctaButton":97,"ctaUrl":98,"relatedPosts":99},279,"migrate-your-github-repos-to-self-hosted-gitea-on-a-vps",{"fr":10,"en":8,"ar":11},"migrer-depots-github-vers-gitea-vps","نقل-مستودعات-github-إلى-gitea-على-خادم-vps-خاص","Migrate Your GitHub Repos to Self-Hosted Gitea on a VPS","Export your repos, issues and labels via the GitHub API, import them into Gitea in under an hour, and update your local remotes — no history loss, no SaaS dependency.",9,0,false,"2026-08-18T00:00:00+00:00",{"id":19,"name":20,"slug":21,"color":22,"icon":21},3,"Deployment","deploiement","bg-success\u002F10 text-success",[24],{"id":19,"name":20,"slug":21,"color":22,"icon":21},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fmigrer-depots-github-vers-gitea-vps-poster.svg",{"categorySlug":29,"appSlug":30},"development","gitea","Repeated GitHub outages in August 2026 and rising GitHub Actions costs pushed thousands of teams to look for a concrete exit. Gitea, installed on a VPS with a single binary, provides a compatible API and a native CI runner. This guide takes you from GitHub export to your first `git push` on your own forge, in under an hour.",[33,37,47,50,72,75,78,81,92],{"type":34,"title":35,"body":36},"h2","Why move from GitHub to a self-hosted forge","GitHub remains the reference, but three trends converged in 2026 to make the move concrete rather than theoretical.\n\nFirst: outages. Several incidents documented on \u003Ca href=\"https:\u002F\u002Fwww.githubstatus.com\">githubstatus.com\u003C\u002Fa> affected Git Operations and Actions in August 2026, blocking production pipelines at the worst time. The Hacker News thread \"Alternatives to GitHub\" reached 472 points and 299 comments on 2026-08-17 — a sign the question is no longer academic.\n\nSecond: CI minute costs. GitHub Actions is free up to a monthly quota on public repositories, but any team that exceeds that quota on private repos pays per minute — with a multiplier depending on the runner OS. Details are available on \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fpricing\">github.com\u002Fpricing\u003C\u002Fa>.\n\nThird: code sovereignty. Some teams prefer that the only access to their repository is root on their own VM, not a unilaterally revocable SaaS token.",{"type":38,"title":39,"items":40},"ul","What self-hosted Gitea delivers in practice",[41,42,43,44,45,46],"**Full history preserved**: Gitea's API import consumes a GitHub tar.gz archive — commits, branches and tags intact.","**Issues and labels migrated**: the `POST \u002Fapi\u002Fv1\u002Frepos\u002Fmigrate` endpoint transfers issues, milestones and labels in one pass.","**Native CI runner**: gitea-runner (based on act) understands GitHub Actions workflow syntax — most pipelines work without rewriting.","**Predictable cost**: a VPS with 1 vCPU and 1 GB RAM is enough for a small team; the software is open source, with no licence fee or minute quota.","**Compatible webhooks**: Gitea exposes the same events (`push`, `pull_request`, `release`) as GitHub — third-party integrations stay wired without changes.","**Local API token**: access is managed in your own interface, never at a third party.",{"type":34,"title":48,"body":49},"Prerequisites","Before you start, gather the following.\n\n**GitHub side**: a personal access token (`Settings → Developer settings → Personal access tokens`) with `repo` and `read:org` scopes. Keep it handy — you will use it in every `curl` call.\n\n**Gitea side**: an already-installed Gitea instance (see our guide \"Host Gitea on Your Own VPS\") and an admin token (`gitea-admin → Settings → Applications → Generate Token`). Note your base URL as `https:\u002F\u002Fgit.your-domain.com`.\n\n**Local workstation**: `git` 2.x, `curl` and `jq` installed. Allow **1 GB of RAM** minimum on the VPS for importing average-sized repositories.",{"type":51,"title":52,"steps":53},"steps","Migration step by step",[54,57,60,63,66,69],{"title":55,"body":56},"Create the target Gitea organisation","In the Gitea interface, go to **`+` → New Organization**, pick a name matching your GitHub organisation (this simplifies the remote update later).\n\nOr via the API:\n```bash\ncurl -s -X POST https:\u002F\u002Fgit.your-domain.com\u002Fapi\u002Fv1\u002Forgs \\\n  -H \"Authorization: token YOUR_GITEA_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"username\":\"my-org\",\"visibility\":\"private\"}'\n```",{"title":58,"body":59},"List and export GitHub repositories","Retrieve your repository list (paginated at 100 per page):\n```bash\ncurl -s -H \"Authorization: token YOUR_GITHUB_TOKEN\" \\\n  \"https:\u002F\u002Fapi.github.com\u002Forgs\u002FMY_ORG\u002Frepos?per_page=100&page=1\" \\\n  | jq -r '.[].name' > repos.txt\n```\nThe GitHub endpoint used here is `GET \u002Frepos\u002F{owner}\u002F{repo}\u002Ftarball\u002F{ref}` for a full archive, and `GET \u002Forgs\u002F{org}\u002Frepos` for the inventory. Check the official documentation at \u003Ca href=\"https:\u002F\u002Fdocs.github.com\u002Fen\u002Frest\u002Frepos\u002Fcontents\">docs.github.com\u003C\u002Fa>.",{"title":61,"body":62},"Import each repository via the Gitea API","The `POST \u002Fapi\u002Fv1\u002Frepos\u002Fmigrate` endpoint of Gitea API v1 accepts a GitHub source URL (official documentation: \u003Ca href=\"https:\u002F\u002Fgitea.io\u002Fapi\u002Fswagger\">gitea.io\u003C\u002Fa>). For each repository:\n```bash\nwhile IFS= read -r REPO; do\n  curl -s -X POST https:\u002F\u002Fgit.your-domain.com\u002Fapi\u002Fv1\u002Frepos\u002Fmigrate \\\n    -H \"Authorization: token YOUR_GITEA_TOKEN\" \\\n    -H \"Content-Type: application\u002Fjson\" \\\n    -d \"{\\n      \\\\\\\"clone_addr\\\\\\\": \\\\\\\"https:\u002F\u002Fgithub.com\u002FMY_ORG\u002F$REPO\\\\\\\",\\n      \\\\\\\"auth_token\\\\\\\": \\\\\\\"YOUR_GITHUB_TOKEN\\\\\\\",\\n      \\\\\\\"uid\\\\\\\": 2,\\n      \\\\\\\"repo_name\\\\\\\": \\\\\\\"$REPO\\\\\\\",\\n      \\\\\\\"issues\\\\\\\": true,\\n      \\\\\\\"labels\\\\\\\": true,\\n      \\\\\\\"milestones\\\\\\\": true,\\n      \\\\\\\"mirror\\\\\\\": false\\n    }\"\ndone \u003C repos.txt\n```\n`uid` is the numeric ID of your Gitea organisation (visible via `GET \u002Fapi\u002Fv1\u002Forgs\u002Fmy-org`). `mirror: false` means a one-time import — set it to `true` for continuous sync during the transition period.",{"title":64,"body":65},"Update local remotes","For each repository cloned on your workstation:\n```bash\ngit remote set-url origin https:\u002F\u002Fgit.your-domain.com\u002Fmy-org\u002Fmy-repo.git\n```\nOr via SSH if you have added your public key in Gitea (`Settings → SSH \u002F GPG Keys`):\n```bash\ngit remote set-url origin git@git.your-domain.com:my-org\u002Fmy-repo.git\n```\nVerify with `git remote -v`, then test with `git fetch` to confirm the remote responds.",{"title":67,"body":68},"Update webhooks","In Gitea, for each repository: **Settings → Webhooks → Add Webhook**. Paste the URL of your CI or third-party service (Slack, Woodpecker CI, etc.), replacing `github.com` with `git.your-domain.com`.\n\nThe available events (`push`, `pull_request`, `issues`, `release`) are identical to GitHub's — payloads share the same base structure for most integrations.",{"title":70,"body":71},"Migrate the CI pipeline to gitea-runner","Install the official runner on your VPS:\n```bash\nwget -O gitea-runner https:\u002F\u002Fdl.gitea.com\u002Fact_runner\u002Flatest\u002Fact_runner-latest-linux-amd64\nchmod +x gitea-runner\n.\u002Fgitea-runner register --no-interactive \\\n  --instance https:\u002F\u002Fgit.your-domain.com \\\n  --token YOUR_RUNNER_TOKEN \\\n  --name vps-runner \\\n  --labels ubuntu-latest:docker:\u002F\u002Fnode:20-bullseye\n.\u002Fgitea-runner daemon &\n```\nThe runner token is generated in Gitea: **Site Administration → Runners → Create new Runner Token**.\n\nYour existing `.github\u002Fworkflows\u002F*.yml` files are understood by gitea-runner without modification for common actions (`actions\u002Fcheckout`, `actions\u002Fsetup-node`, etc.). Rename `.github\u002Fworkflows\u002F` to `.gitea\u002Fworkflows\u002F` to use Gitea's native path (both are supported, but `.gitea\u002F` is the canonical one).",{"type":34,"title":73,"body":74},"Post-migration checks","Once migration is complete, validate these three points before revoking GitHub access.\n\n**SSH clones**: from a freshly cloned workstation, `git clone git@git.your-domain.com:my-org\u002Fmy-repo.git` should succeed without a password prompt if your public key is registered in Gitea.\n\n**Active webhooks**: in each repository, open **Settings → Webhooks** and click **Test Delivery**. A `200` code in the delivery logs confirms your CI is receiving events.\n\n**Intact history**: `git log --oneline -10` on the migrated repository should display the same ten latest commits as on GitHub, in the same order.",{"type":76,"body":77},"tip","If you are migrating dozens of repositories, run the migration `curl` calls in parallel using `xargs -P 4` to cut the total wait time by four. Gitea handles concurrent imports without data loss — the only limit is GitHub's outbound bandwidth and your VPS's inbound bandwidth.",{"type":34,"title":79,"body":80},"Common errors — troubleshooting","Here are the three most frequent situations during a migration.",{"type":51,"title":25,"steps":82},[83,86,89],{"title":84,"body":85},"SSH: `Permission denied (publickey)`","Symptom: `git clone git@git.your-domain.com:…` fails with `Permission denied (publickey)`.\n\nCheck: in Gitea, **Settings → SSH \u002F GPG Keys** — the public key you are using must be listed there. Add it if absent (`cat ~\u002F.ssh\u002Fid_ed25519.pub | pbcopy` or `xclip`).\n\nIf the key is present but the error persists, verify that Gitea's SSH port is `22` (or the configured port): `ssh -vT git@git.your-domain.com -p 22` will show the negotiation and Gitea's acceptance message if the key is recognised.",{"title":87,"body":88},"Remote: `fatal: repository not found`","Symptom: `git fetch` returns `fatal: repository 'https:\u002F\u002Fgit.your-domain.com\u002F…' not found`.\n\nDiagnosis: `git remote -v` — check that the URL points to your Gitea instance and not `github.com`. If the URL is correct, log in to the Gitea interface and confirm the repository exists under the correct organisation name. A silently failed `POST \u002Fapi\u002Fv1\u002Frepos\u002Fmigrate` leaves the repository absent with no error message in the local remote.",{"title":90,"body":91},"Silent webhooks after migration","Symptom: a `git push` does not trigger a build in your CI.\n\nDiagnosis: in Gitea, **Settings → Webhooks → last delivery**: the \"Response\" field shows the HTTP code returned by your CI. A `404` means the webhook URL points to a non-existent route; a `401` means a misconfigured HMAC secret.\n\nEnable runner debug mode: in the gitea-runner configuration file, set `log_level` to `debug` and restart the daemon. Logs will show each event received and the job activation code.",{"type":34,"title":93,"body":94},"Host Gitea on a ServOrbit VPS","Gitea runs comfortably on a VPS with **1 vCPU and 1 GB RAM** for a small team. For an organisation of ten developers with an active CI, 2 vCPU and 2 GB is a reasonable starting point — the runner and Gitea can share the same VM at that size.\n\nIf server administration is not your priority, ServOrbit's **VPS administration** option covers exactly this case: security updates, monitoring and incident response — you keep root access, we keep the VM healthy. Your forge stays yours, without sharing infrastructure with other teams.\n\nDeploy the Gitea template from the Marketplace, select your OS (Ubuntu or Debian) and your VPS size, and you have a configured instance in minutes. VPS plans from `{{vps.start.price}}`.","Your own Git forge, on your VPS","A VPS with root access, dedicated IPv4 and choice of OS (Ubuntu, Debian, AlmaLinux): the foundation for hosting Gitea without SaaS dependency. Gitea template available in the Marketplace.","Activate Gitea on a VPS","\u002Fmarketplace\u002Fdevelopment\u002Fgitea",[100,120,138],{"id":101,"slug":102,"slugs":103,"title":106,"excerpt":107,"readTime":108,"views":109,"isPinned":16,"publishedAt":110,"category":111,"categories":117,"featuredImage":25,"bgImage":26,"posterImage":119,"relatedSolution":25},75,"host-forgejo-on-your-own-vps",{"fr":104,"en":102,"ar":105},"heberger-forgejo","استضافة-forgejo-على-خادم-vps-الخاص-بك","Self-Host Forgejo on Your VPS: Complete 2025 Guide","Deploy Forgejo on your VPS with Docker, SSL, Actions runners and hardened security. Step-by-step guide for a sovereign Git forge.",10,1,"2026-04-06T00:00:00+00:00",{"id":112,"name":113,"slug":114,"color":115,"icon":116},7,"Self-hosting","self-hosting","bg-indigo-500\u002F10 text-indigo-400","cloud",[118],{"id":112,"name":113,"slug":114,"color":115,"icon":116},"\u002Fblog\u002Fcovers\u002Fheberger-forgejo-poster.svg",{"id":121,"slug":122,"slugs":123,"title":126,"excerpt":127,"readTime":128,"views":109,"isPinned":16,"publishedAt":129,"category":130,"categories":135,"featuredImage":25,"bgImage":26,"posterImage":137,"relatedSolution":25},212,"woodpecker-ci-and-forgejo-cicd-pipeline-on-a-vps",{"fr":124,"en":122,"ar":125},"woodpecker-ci-pipeline-vps-forgejo","woodpecker-ci-وforgejo-خط-أنابيب-cicd-على-خادم-vps","Woodpecker CI and Forgejo: CI\u002FCD pipeline on a VPS","Deploy Woodpecker CI with Forgejo on your VPS for a self-hosted, lightweight and sovereign open source CI\u002FCD pipeline. Step-by-step Docker guide.",4,"2026-08-02T00:00:00+00:00",{"id":131,"name":132,"slug":133,"color":134,"icon":133},2,"Automation","automatisation","bg-brand-action\u002F10 text-brand-action",[136],{"id":131,"name":132,"slug":133,"color":134,"icon":133},"\u002Fblog\u002Fcovers\u002Fwoodpecker-ci-pipeline-vps-forgejo-poster.svg",{"id":139,"slug":140,"slugs":141,"title":144,"excerpt":145,"readTime":146,"views":15,"isPinned":16,"publishedAt":147,"category":148,"categories":149,"featuredImage":25,"bgImage":26,"posterImage":151,"relatedSolution":152},273,"migrate-cicd-to-gitea-or-forgejo-leave-github-actions",{"fr":142,"en":140,"ar":143},"github-actions-payant-migrer-ci-cd-gitea-forgejo-vps","gitea-وforgejo-بديل-github-actions-المدفوع-على-vps","Migrate CI\u002FCD to Gitea or Forgejo: leave GitHub Actions","Since March 2026, GitHub charges CI minutes on private repositories. Migrate to Gitea Actions or Forgejo on a VPS: same YAML files, fixed monthly cost.",11,"2026-08-16T00:00:00+00:00",{"id":131,"name":132,"slug":133,"color":134,"icon":133},[150],{"id":131,"name":132,"slug":133,"color":134,"icon":133},"\u002Fblog\u002Fcovers\u002Fgithub-actions-payant-migrer-ci-cd-gitea-forgejo-vps-poster.svg",{"categorySlug":29,"appSlug":30},1787581007887]