GitHub was down for 7 hours 35 minutes: three forks that pop up in the evening

August 17 GitHub did not work normally for seven and a half hours. It wasn’t just slow — it wasn’t working at all: a fifth of web and API requests failed, downloading repository archives and raw content failed in about half of cases. A day after this thread, “Alternatives to GitHub” on Hacker News gathered more than five hundred votes, and Cursor opened a beta of its own self-hosted repository hosting on the same day.

Below is not a call to “move away immediately,” but an analysis: what exactly broke, what you can keep on your own, how much hardware and time it will cost, and where self-hosting will make things worse, not better.

13:40 UTC. Timeline from the status page

All timestamps come from the official incident feed on githubstatus.com, in UTC.

Time What was reported
13:40 “We are investigating reports of degraded performance for some GitHub services”
13:45 “We are seeing roughly 20% errors in various scenarios, including Pull Requests, Issues, and others”
14:58 ~20% errors on web traffic and API; downloading archives and raw content — ~50% errors
15:42 Also affecting SAML and OIDC authentication, SCIM and Team Sync
17:34 “We identified the problematic component and took action”, residual impact remains
20:45 Sporadic Copilot authentication failures continue; Copilot via CLI and GitHub App not affected
21:15 Incident closed, detailed reasons promised later

In total, 7 hours 35 minutes from the first report to closure. Git operations, API, webhooks, Issues, Pull Requests, Actions, Pages and Copilot were affected — basically everything except static documentation pages.

Note:

Note the line 15:42. Not only was page serving down, but corporate login via SAML/OIDC and team synchronization failed as well. For an organization whose repository access relies on SSO, this means that a new employee or a new machine in CI could not access anything at all during the incident.

What you lose along with GitHub — and what of this is really yours

Before choosing a replacement, it’s useful to break down what you actually keep on someone else’s server. The list ends up longer than just “code”:

  • The repositories themselves. Here everything is fine: git is distributed, every developer has a full history clone. This is the only part that automatically survives the platform’s disappearance.
  • Issues, pull requests, discussions, reviews. This is no longer git. It lives in the platform’s database and is exported only via the API.
  • Actions and build artifacts. Configs live in the repository, but runners, caches and secrets do not.
  • Releases and binaries. If your installer downloads files from github.com/.../releases/download/..., then GitHub’s failure breaks the installation for all your users.
  • Package and container registry. ghcr.io is also GitHub.
  • Pages. Documentation site.
  • Access rights and SSO. The very line 15:42.
Important:

A practical takeaway that does not require any migration: if your product or your CI pulls files from releases or images from ghcr.io on a critical path — mirror it. It’s cheaper than changing forks, and it covers most of the pain from such incidents.


Diagram based on official Forgejo, Gitea and GitLab documentation

Decision matrix: by task, not by feature list

Comparing forks by the number of checkmarks is a bad idea: all three have issues, PRs, wiki, LFS and API. The difference shows up in two places — resource consumption and who decides how the project evolves.


Resource guidelines: for GitLab — from docs.gitlab.com, for Forgejo and Gitea there isn’t a formal minimum in the official docs

Let’s go through the rows.

The “no fork at all” option

If the goal is simply to have a local copy of several repositories, a fork is not needed. A bare repository over SSH solves it completely:

# on the server
sudo adduser --disabled-password git
sudo -u git mkdir -p /home/git/repos/myproject.git
sudo -u git git init --bare /home/git/repos/myproject.git

# on the workstation
git remote add mirror git@myserver:/home/git/repos/myproject.git
git push --mirror mirror

No containers, no updates, no attack surface on top of sshd. If you’re just starting with this, don’t miss the first-hour VPS onboarding guide, while the moneyback offer lasts. No web UI, issues or CI — but that’s not what you asked for.

Forgejo and Gitea: one container

These are two very close relatives. Forgejo was created in October 2022 as a fork of Gitea and, per the project’s own wording, became a “hard fork” at the start of 2024. Versions up to v8.0 inclusive were distributed under MIT, starting with v9.0 — under GPL-3.0+; Codeberg e.V. keeps the domain.

Changing the license is not an abstraction: it directly affects whether you’re allowed to build your own distribution and what you’ll have to give back. How to check such things in advance, we covered separately — checklist for self-hosting a project.

Warning:

Comparative Forgejo page listing Gitea’s drawbacks is a statement from one side, not an independent audit. Facts verified there: fork dates, license change, and who owns the domains. Do not rely on their evaluative wording about “maximizing profits” — leave that to the authors and decide for yourself.

Current versions at the time of publishing: Forgejo 16.0.2 (stable, released July 30, 2026, support until October 29, 2026) and 15.0.6 in the LTS branch (support until July 15, 2027). Gitea currently has 1.27.2 as of August 14, 2026.

Official compose from Forgejo documentation:

networks:
  forgejo:
    external: false

services:
  server:
    image: codeberg.org/forgejo/forgejo:16
    container_name: forgejo
    environment:
      - USER_UID=1000
      - USER_GID=1000
    restart: always
    networks:
      - forgejo
    volumes:
      - ./forgejo:/data
      - /etc/localtime:/etc/localtime:ro
    ports:
      - '3000:3000'
      - '222:22'

Gitea differs by exactly three things — network name, image docker.gitea.com/gitea:1.27.2 and mounting /etc/timezone:

services:
  server:
    image: docker.gitea.com/gitea:1.27.2
    container_name: gitea
    environment:
      - USER_UID=1000
      - USER_GID=1000
    restart: always
    volumes:
      - ./gitea:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3000:3000"
      - "222:22"
Error:

Do not publish 3000:3000 publicly and do not leave the installer open. The first run of Forgejo and Gitea shows a setup wizard without a password — whoever reaches the form first becomes admin. The correct order: start the container bound to 127.0.0.1:3000, place a reverse proxy in front with TLS, and only then complete the installation via the HTTPS address.

A minimal localhost binding looks like this — change the port line:

    ports:
      - '127.0.0.1:3000:3000'
      - '222:22'

And two blocks in the Caddyfile (Caddy will obtain the certificate itself):

git.example.com {
    reverse_proxy 127.0.0.1:3000
}
Info:

Port 222. Inside the container runs its own SSH daemon for Forgejo — not the system sshd on 22. Therefore clones look like ssh://git@git.example.com:222/user/repo.git. If you want the usual git@git.example.com:user/repo.git without the port number, there are two ways: forward the container SSH to 22, and move the system sshd to another port, or configure port forwarding through the host’s authorized_keys with a wrapper command. The first option is simpler, the second safer when working with multiple services.

There is no official minimum RAM in the Forgejo and Gitea documentation — neither on the binary installation page nor in the docker section. A practical guideline for a small team: one gigabyte for the entire stack with SQLite is usually enough, but as soon as CI runners connect, the bar rises — builds eat as much as your project consumes.

Backup that really backs up

Both projects have a built-in dump command. Official Docker variant (example — Gitea; for Forgejo the command is forgejo dump):

docker exec -u git -it -w /tmp $(docker ps -qf 'name=^gitea$') \\
  bash -c '/usr/local/bin/gitea dump -c /data/gitea/conf/app.ini'

In the resulting ZIP you get app.ini, the custom/ directory, the data/ directory (attachments, avatars, LFS, indexes, SQLite file), a full copy of repos/, SQL dump gitea-db.sql and logs. Logs for restoration are not needed — you can discard them.

Warning:

Gitea documentation explicitly states: for a consistent dump, the service should be stopped. Dumping on a live instance may capture the database and repository files in different states. For a home installation this means a short nightly window with docker compose stop before taking the copy, not “we’ll pull it on the fly and hope it matches.”

CI: that moment when “one container” ends

Both Forgejo and Gitea support CI with syntax similar to GitHub Actions. Exactly similar: the Forgejo docs phrase it clearly — “GitHub Actions and Forgejo Actions are not the same, and something may not work right away.” The github context is provided as an alias to forgejo for portability, but parity of features is not guaranteed.

What is documented as a limitation:

  • pull requests from forks have restricted access to secrets and read-only tokens;
  • OIDC is disabled for pull_request events from forks;
  • user-provided container images are NEVER updated automatically after the first run;
  • daylight saving time changes break schedules: when moving forward, runs are skipped; when moving back, runs run twice;
  • reusable workflow references work only for local and in-instance links, not for repositories on another server.
Security:

Runners almost always are asked to grant access to /var/run/docker.sock. This is equivalent to root on the host: whoever can create containers can mount the root filesystem. If your Forge has public repositories and external contributors, such a runner should not be run on the same host where the Forge lives. The minimally acceptable setup is a separate VM for the runner with an explicit ban on running workflows from forks.

GitLab CE: when 16 GB are warranted

GitLab is a different class of beast. The hardware requirements documentation lists figures for a single-node install: baseline 8 vCPU and 16 GB RAM; in constrained environments 8 GB with a note on performance, and 40 GB of disk space for the node itself plus space for repositories and databases.

Official start of the CE edition:

sudo docker run --detach \\
  --hostname gitlab.example.com \\
  --env GITLAB_OMNIBUS_CONFIG="external_url 'http://gitlab.example.com'" \\
  --publish 443:443 --publish 80:80 --publish 22:22 \\
  --name gitlab \\
  --restart always \\
  --volume $GITLAB_HOME/config:/etc/gitlab \\
  --volume $GITLAB_HOME/logs:/var/log/gitlab \\
  --volume $GITLAB_HOME/data:/var/opt/gitlab \\
  --shm-size 256m \\
  gitlab/gitlab-ce:<version>-ce.0

Inside a single image — a Rails application, PostgreSQL, Redis, Sidekiq, Nginx, Prometheus and another ten components. Hence the --shm-size 256m, memory requirements, and startup time measured in minutes, not seconds.

What you get in return: subgroups (Forgejo and Gitea do not support them — this is explicitly stated in Gitea’s documentation comparison table), merge conflict resolution in the UI, built-in CI without separate setup, and noticeably more advanced review tools.

Warning:

And the price of this maturity in maintenance. On August 17, 2026 — the same day as the GitHub incident — GitLab released critical patch releases 19.2.4, 19.1.6, 19.0.8 and 18.11.11. CVE-2026-19478 (code injection via GraphQL directive, CVSS 9.4) and CVE-2026-19650 (CSRF in GraphQL multiplex-request handler, CVSS 7.1) were fixed. Both vulnerabilities affect CE and EE starting from 18.2. Self-hosting means that updating in response to such a notice is your responsibility, and you have to do it on the same day.

Migration: what comes with you, and what stays behind

Gitea and Forgejo can import repositories from GitHub along with metadata, and the migration UI includes checkboxes for issues, pull requests, releases, labels, and milestones. Gitea’s migration documentation is very concise: it only says that to transfer such elements you must specify at least a username, and there is no detailed list of what is transferred or any restrictions. For GitLab, the transfer is done with a third-party tool, about which Gitea’s documentation also says nothing.

In other words, there are few promises in the documentation — you’ll have to verify with your own data.

Success:

The migration plan that avoids surprises:

  1. Spin up Forge and do not touch the active workflow. GitHub remains the primary source.
  2. Import one medium repository with issues and PRs enabled. Check visually: did the authors of comments, dates, links like #123, attachments survive?
  3. Configure mirroring of the remaining repositories in one direction — GitHub as the source, Forge as the copy.
  4. Live like this for at least a month, including one Forge update cycle. If the update went without manual intervention, you can consider switching.
  5. Change the direction: Forge becomes the source, GitHub mirrors for external users.

Step 4 is the most often skipped, and it answers the core question — will you be able to sustain this long term.

How much does it really cost

A fair breakdown looks like this. One-off costs — in the evening: deploy the container, set up a reverse proxy, configure backups, import repositories. Ongoing costs are not a one-evening affair:

  • Updates outside your schedule. Security releases come when they come. The GitLab 19.2.4 example above is exactly about that.
  • Backups you’ve tested. A database dump plus the /data directory is enough in terms of content, but a backup that has never been restored is not a real backup.
  • Disk growth. Repositories, LFS, package registry, and CI artifacts grow independently, and space for artifacts is usually the first to run out.
  • Monitoring. Forge that went down on Friday and you learned about on Monday is worse than having Forge. At minimum — alerting for downtime and dwindling space; how to run such a thing on your own machine was discussed in the ntfy material.
  • Availability. GitHub had 7 hours 35 minutes of downtime on August 17. On your VPS with one disk and no replica in a year you could see more — just no one counts those hours or writes about them.
Question:

What about your production setup? Who has already migrated to Forgejo or Gitea — how much time per month does maintenance take and what turned out to be surprisingly inconvenient after GitHub? And separately, I’m curious about runners: do you keep them on the same host or move them to a separate machine?

Sources