Von GitHub zu selbstgehostetem Forgejo
TOC
- 1. Übersicht
- 2. Ausgangslage: Warum weg von GitHub?
- 3. Beleg: GitHub-Ausfälle Februar–April 2026
- 4. Was Forgejo konkret löst
- 5. Warum Forgejo
- 6. CI-Lastanalyse (Basis der Server-Dimensionierung)
- 7. Server-Dimensionierung
- 8. Architektur
- 9. Server-Empfehlungen & Preise
- 10. Performance-Tuning: .NET & Garbage Collector (Runner)
- 11. On-Prem-Readiness-Checkliste
- 12. Risiken
- 13. Fazit mit retrospektiv betrachteten, administrativen Aufwand
1. Übersicht
GitHub verursacht für unsere Entwicklung Frustration, hohe Kosten und Ausfälle.
Eine Analyse der “ehrlicheren Statusdaten” (Februar–April 2026) zeigt:
An unseren vier genutzten Diensten lag die kombinierte Verfügbarkeit bei nur 93,4 % – im Schnitt ~11 Stunden pro
Woche mit mindestens einem beeinträchtigten Dienst.
Dem sei dazu gesagt, dass dies lediglich die von Microsoft “bestätigten” Werte sind.
Ähnlich dem deutschen Bahn Trick messe ich in meinen Daten seit Oktober 2025 eine durchschnittliche Verfügbarkeit von gerade einmal 83%.
Die vier gemessenen Dienste sind hierbei:
- Github Actions
- Git Operations
- Pull Requests
- Pages
Die Lösung zu diesen Problemen ist ein selbst gehostetes Forgejo auf einem eigenen Server im Haus.
Das beseitigt die Geschwindigkeits-, Rate-Limit- und Datenhoheits-Probleme an der Wurzel, schaltet
fehlende Funktionen - wie etwa Fast-Forward-Merges oder ArtefaktHandling - frei und macht zB Stakeholder-Accounts für das Produktmanagement kostenlos.
Ich möchte an dieser Stelle verdeutlichen, dass der administrative Aufwand für diesen Quellcode und BuildServer nur ein Bruchteil des Aufwands ist,
der von mir Gegenwärtig auf das Github System aufgebracht werden muss.
Der grösste Pain-Point sind gegenwärtig die Github Actions,
welche für uns gleichzeitig die wichtigste Komponente des ganzen Systems ist,
und welche der Produktivität jedes einzelnen Entwcklers mehrmals pro Woche einen Dämpfer verpasst.
Aus diesem Grund ist die Folgende Entscheidungsfindung bedeutend von dieser Thematik geprägt.
Eine Auswertung unserer realen CI-Last unter WarpBuild ergibt einen gemessenen Spitzenbedarf von 104 vCPU und 416 GB RAM bei maximal 13 gleichzeitig laufenden (windows) Agents. Konsektutiv ergeben sich drei Server-Konstellationen als unsere Empfehlung:
| Variante | Hardware | Kerne / RAM | Preis (indikativ) |
|---|---|---|---|
| ★ Empfehlung: Vorkonfektionierter Silent-Tower | LS ComputerSysteme EPYC 9555P | 128 vCPU / 768 GB DDR5-6400 | € 35.288,00 € |
| Vorkonfektionierter Silent-Tower 2 | Thomas-Krenn TA1506, EPYC 9555P | 128 vCPU / 768 GB DDR5-6400 | € 50.758,00 € |
| DIY lastgen | Leiser Eigenbau-Tower, 2× EPYC 7763 | 128 vCPU / 1 TB DDR4-3200 | ~35.000 CHF |
| Refurbished | Refurbished Dell R6525 (1U), 2× EPYC 7763 | 128 vCPU / 1 TB DDR4-3200 | ~CHF 25.000 |
| Metal Host (Cloud) | zB cloudscale | 128 vcpu + 512g | ~7.000 CHF / Monat |
Entscheidung: vorkonfektionierter Silent-Tower-Server (1× EPYC 9555P, 768 GB DDR5-6400).
Ausschlaggebend war die Verfügbarkeit:
- fertig konfiguriert
- Fertig gebaut
- Bis zu 5 Jahre Garantie
- In wenigen Tagen lieferbar
Also ohne Sourcing- oder Bauaufwand und ohne Kühlerproblem (keine 1U/2U SchubladenTurbine).
64 schnelle Zen-5-Kerne (128 Threads) decken die gemessene 104-vCPU-Spitze.
Die auf den ersten Blick überproportionierte Arbeitsspeicher Kapazität liegt hier tatsächlich nicht an der benötigten Kapazität,
sondern der Anzahl der einzelnen Module um die für C# am wichtigsten benötigte Ressource zu liefern,
nämlich eine Maximierung der zur Verfügung stehenden Speicher-Bandbreite.
Zusätzlich erscheinen die Alternativen durch die geringe Preisdifferenz weniger Attraktiv.
Der Lastgen Tower wäre eine 30-40% Performance einbusse gegenüber der empfohlenen Variante.
Beim Dell R6525 gestaltet sich das Bild sehr ähnlich.
Zudem ist hier auch die Verfügbarkeit, Garantie und Zustand ein weiterer Punkt, den es zu betrachten gilt.
Ebenfalls haben diese 1U Server keine guten Modifikationsalternativen.
Hierdurch wären keine Fanmods möglich, wodurch diese “Turbine” enormen Larm und Hitze erzeugt.
Diese Server versperren den Zugang zu BIOS funktionen und besitzen lediglich 40mm Lüfter.
Dadurch befinden sich damit dort kleine, heulende Lüfter, die 24/7 auf 15.000 Umdrehungen pro Minute rotieren.
Die Cloudhosted alternative fungiert hier lediglich als Referenz und ist nicht als Vorschlag zu betrachten.
Der Preis ist hier angenähert, da solch grosse Server oft nur als Offerte eingeholt werden können.
Es besteht allerdings die Möglichkeit, einzelne Server für einzelne Runner anzumieten.
Github kostet uns gegenwärtig je nach Auslastung jährlich 50.000 USD - 55.000 USD.
2. Ausgangslage: Warum weg von GitHub?
| Schmerzpunkt | Auswirkung heute | Lösung mit selbst gehostetem Forgejo |
|---|---|---|
| Langsam | Latenz bei Clone, PR, UI – verstärkt durch USA-Anbindung | Server im eigenen Haus → LAN-Latenz statt Transatlantik |
| Teuer | 50-55k USD, tendenz steigend | Keine weiteren kosten |
| Ausfälle | Tägliche Ausfälle (nicht immmer gleich schwerwiegend) | 99.9% uptime möglich |
| Kein Einfluss auf RunnerImages | cmi-metatool kann nicht auf .NET 10 Pakete gehoben werden, da diese erst mit MSBuild 18 unterstützt sind. .NET 8 verliert LTS im November 2026 | RunnerImage im eigenen Zugriff |
| API-Rate-Limit | Automatisierungen/Bots werden gedrosselt | Eigene Instanz, Limits frei konfigurierbar |
| Keine kostenlosen Stakeholder-Accounts | PM zahlt pro Sitz oder hat keinen Zugang | Forgejo: unbegrenzte Nutzer kostenlos |
| Dediziertes Accountmanagement | Jeder Entwickler braucht einen eigenen Account | Forgejo: Oidc/Ldap -> EntraID Account |
| Fehlende Funktionen | z. B. Fast-Forward-Merge fehlt | In Forgejo nativ vorhanden (FF-only, Rebase, Squash) |
| USA-Bindung | Datenhoheit, rechtliche Abhängigkeit | Daten bleiben in der Schweiz, im eigenen Haus |
| Tägliche Störungen | ~17 h/Woche Beeinträchtigung (Kapitel 3) | Wir kontrollieren Verfügbarkeit und Wartung selbst |
| Verdeckte Kosten | Ausgelaufene Buildartefakte werden Berechnet und können nur aufwändig gelöscht werden | Keine (Open Source) |
| Kontakt | Github Mitarbeiter reagieren meist gar nicht | Open Source Code ermöglicht forks, Antworten aus dem Team bisher nach spät. 1 Tag |
| Leitung | Existiert seit Sommer 2025 nicht mehr. | Codeberg und mehrere direkte Teams, Antworten binnen Tagen auf Mails |
| Vertrauen | Hacks durch eigene Mitarbeiter, Leaks, etc. | CVEs klar kommuniziert. Keine kritischen Lücken in privaten Instanzen vorhanden |
Ein sehr grosser Indikator für die Githubsche Dekadenz liegt in dem Fehlen eines Kopfes.
Github ist ein Schiff ohne Kapitän.
Das kann zB im Verge nachgelesen werden.
Der CEO Posten wurde wurde im Sommer 2025 von Thomas Dohmke aufgegeben und das Team wurde direkt dem CoreAI Team unterstellt.
Diesem fehlt objektiv Betrachtet die Kompetenz, dieses Produkt in die Zukunft zu führen.
3. Beleg: GitHub-Ausfälle Februar–April 2026
Die offizielle Statusseite (githubstatus.com) meldet reale Ausfälle seit geraumer Zeit nicht mehr verlässlich.
Wir nutzen daher die ehrlichere, aus dem Atom-Feed rekonstruierte Auswertung von mrshu.
Da Microsoft den Atom-Feed seit Mai 2026 nur noch unregelmässig aktualisiert, werten wir bewusst das saubere Fenster Februar bis April 2026 (89 Tage) aus.
Betrachtet man mit den Erkenntnissen aus Kapitel 2 die Daten vor 2025,
so ergibt sich ein weit stabileres Bild von nur sehr wenigen, grösseren Ausfällen.
Generell herrscht hier im Schnitt eine Verfügbarkeit von >98%.
Hingegen im April 2026 erreichen wir einen gemessenen, zugegebenen Wert von 78,33%.
In meinen persönlichen Messungen - also eine Berechnung der Zeitfenster eines 8h Arbeitstages,
in denen mindestens einer der vier verwendeten Dienste nicht Verfügbar ist - komme ich sogar lediglich auf 71%.
Sollten wir jemals gezwungen sein so schnell wie Möglich einen Fix herauszugeben,
weil wir zum Beispiel opfer einer aktiv ausgenutzten Sicherhitslücke sind,
dann ist so ein Bild einfach nicht tragbar.

In den folgenden Abschnitten werden nur die offiziellen, von Microsoft herausgegebenen Ausfalldaten analysiert.
Dem sei jedoch vorangestellt, dass die Dunkelziffer hier weit höher ist.
Meine Datenerhebung ergibt sich aus der Analyse unsere Github Jobs für Actions,
Health Pings für unsere Pages und generelle Automatisierungen, die Aufgrund der Verfügbarkeit fehlschlagen und deshalb gelogged werden.
Gerade in den Git Operations komme ich im Monat Mai auf 84 Stunden, in denen git Operations so eingeschränkt nutzbar waren,
dass ein einfacher Branchwechsel über Github bis zu 12(!) Minuten dauert.
Ich werte ausserdem die Zeitfenster aus und komme am 21.04. zu einem Aufallfenster der Github Actions von 16 Stunden.
3.1 Unsere vier genutzten Dienste
| Dienst | Vorfälle | davon major | davon critical | Ausfallzeit |
|---|---|---|---|---|
| Pull Requests | 16 | 4 | 1 | 98,2 h |
| Actions | 20 | 6 | 2 | 50,0 h |
| Git Operations | 9 | 3 | 0 | 22,1 h |
| Pages | 5 | 4 | 0 | 9,7 h |
3.2 Kombinierte Sicht (das, was wir täglich spüren)
- 35 Vorfälle betrafen mindestens einen unserer vier Dienste.
- 140,9 h kombinierte Beeinträchtigung in 31 getrennten Zeitfenstern über 89 Tage.
- ⇒ Kombinierte Verfügbarkeit unserer Arbeitsfläche: 93,40 %.
- ⇒ Im Schnitt ~11,1 Stunden pro Woche mit mindestens einem gestörten Dienst.
- Gesamtbild GitHub (alle Komponenten): 96 Vorfälle im Fenster (Feb 37 · Mär 32 · Apr 27).
93,4 % Verfügbarkeit entsprechen keinem marktüblichen SLA (üblich sind 99,9% - und dafür zahlen wir enorme Summen).
Methodik
- Vorfälle nach
started_atgefiltert - Wartungsfenster exkludiert
duration_minutesje Komponente aufsummiert;- Union über Zeitfenster mit Ausfällen, um Duplikate zu vermeiden
3.3 Ablehung der rechtsmässigen Rückerstattung
Verstärkt wird diese Entscheidung zusätzlich durch die Ablehung der Rückerstattung.
Wir bezahlen für eine vertraglich zugesicherte SLA von 99.9%,
die Microsoft seit mindestens Oktober 2025 - der Zeitpunkt, zu dem ich mein aktives Monitoring gestartet habe - jeden Monat bricht.
Diese Anfrage wurde bereits am 8. Mai eingereicht:

Nach mehrmaligen Rückfragen meldete sich der Github Support gestern (09.06.2026):
Hello Lukas,
Thank you for reaching out to GitHub support and I apologize for the miscommunication earlier. We understand that these outages are impactful to your business. Our public documentation indicates that service credit requests should be submitted within 30 days after the end of the current quarter. The first quarter 2026 ended in March, any request for SLA credits was to be processed after the end of the quarter (all through April) but this request came in on the 8th of May which is outside the time when such requests should be made. Regarding the request for SLA credits for Q2 2026 or FYQ4 (April to June) cannot be processed currently due to the fact that we are currently outside of the processing window as this request should be submitted sometime in July. You can see our current and previous uptime performance on the GitHub Uptime status for each service.
I’ll go ahead and mark this ticket as Solved, at this time.
Cheers, Anthony. GitHub Support.
Wir können also damit festhalten, dass das SLA Versprechen von Microsoft wertlos ist.
4. Was Forgejo konkret löst
Geschwindigkeit
Git-Operationen über das eigene LAN statt über den Atlantik.
Generell liefert Forgejo eine bessere Performance als Github.
Meine Private Instanz, die in etwas 350 Km Entfernung gehostet wird, und die Ich mit 20 anderen Entwicklern teile,
liefert folgende Werte in der Statusleiste:
Powered by Forgejo
Version: 15.0.2
Page: 16ms
Template: 2ms
Die Actions haben im Schnitt eine Wartezeit von weniger als 2 Sekunden (Konfigurierbar!).
Im Vergleich hierzu warten Jobs in Github des Öfteren bis zu 30 Minuten,
bis diese Ausgeführt werden.
Hinzu kommen noch diverse, in Ops genutzte Automatisierungsskripte.
Diese haben mit der instabilen und langsamen github api zu kämpfen.
Dieses Skript benötigte hierbei 58 Sekunden für 336 parallelisierte(!) Abfragen.
~/coding/CMI
at 13:10:55 ❯ /home/crashdummy/coding/CMI/cleanup-expired-artifacts.sh -y CMInformatik/cmi-metatool
Fetching artifacts for CMInformatik/cmi-metatool ...
Found 335 expired artifacts, 198.35 GB
Pruning 12 artifacts in parallel
💣 300 ok, 0 fail 💣
✅: 335 deleted, 0 failed
~/coding/CMI took 58s
at 13:11:53 ❯
Zusätzlich ist gerade der Disk IO der Github hosted Runner nicht performant,
wodurch der reine CI Overhead einen grossen Anteil der berechneten BuildMinuten frisst.
Spitzenreiter sind hier pro Run:
- NuGet restore (~2min 30s)
- Upload-Artifact (~1min)
- Download-Artifact (~50s (x5|x7))
Diese können mit lokalen Runnern auf wenige Sekunden reduziert werden.
Weiterhin können wir davon ausgehen, dass sämtliche andere Schritte weit weniger Zeit in Anspruch nehmen werden.
Schattenkosten
Generell benötigt es stets enormen Aufwand, um herauszufinden, was hier tatsächlich die Kosten dieses SCM sind.
Auf die versteckten Kosten zB der Artefakte - auf das ich mit dem in Geschwindigkeit erwähnten Skript reagiere -
stösst man erst, wenn man versteht, wie github hier intern arbeitet.
Gemäss Dokumentation erzeugen diese Artefakte keine “weiteren” kosten.
Allerdings liegen diese - nicht mehr Nutzbaren - Artefakte auf Microsoft’s Cloud Speicher und verursachen Lagerkosten.
Es ist bezeichnend, dass Microsoft’s Scott Hanselman sogar einen Analyzer geschrieben hat,
um solche Kosten aufzudecken.
Ausfälle
Wird diese Forderung angenommen existieren nur wenige Ausfallmöglichkeiten.
Bis auf die IP und etwaige NAT regeln, liegt es an uns, diese zu verhindern.
| Risiko | Eintrittswahrscheinlichkeit | Möglicher Workaround | Impact |
|---|---|---|---|
| Server Defekt | gering | Backup git nach DNS gerouted, 3-4 CMI Laptops als temporäre Runner | Server muss ersetzt werden |
| Netzwerkstörung | eher gering (UMB) | Dezentrales Arbeiten mit Git, keine Pipelines | Wartezeit, bis um UMB das Problem löst |
| Runner veraltet | nahezu unmöglich | Image wird aktualisiert | wenige Minuten keine “neuen” Builds |
| Konfigurations Problem | sehr unwahrscheinlich | Wiederherstellung der alten Konfiguration | Wenige kein Zugriff |
Keine Fremdem Raten Limits
Das ist gegenwärtig ein sehr akkutes Problem im DevOps Bereich.
Es existieren diverse Automatisierungsmechanismen über terraform, spacelift etc.
Weiterhin nutzen Claude Skills, MCPs oder andere Benutzer-Skripte ebenfalls die Github Api.
Hierbei spürt man oft sehr geringe Rate Limits.
Damit in dem Moment die Pipelines nicht in Fehler laufen, prüft mein privater Server im Sekundentakt auf Ratelimits,
und wechselt temporär die Github tokens von Benutzern mit erhöhten Rechten ein.
Eine eigene API ist davon nicht mehr betroffen
Stakeholder Accounts
CMI-Kunden und das PM teilen sich aktuell einen einzelnen ServiceAccount.
Neben dem offensichtlichen Identifizierungs-Problem und den zuvor genannten Ratelimits - das hier geteilt werden muss -,
ist es so auch schwieriger, Zugriffe feingranularer zu steuern.
CWS Entwickler Accounts
Ein sehr grosses Problem bildet aktuell die CWS Entwicklung ab.
Diese wird nicht nur von CMI Mitarbeitern ausgeführt, sondern auch von einigen Kunden selbst.
Gegenwärtig muss ihnen ein Zugriffsschlüssel zugesandt werden, mit dem Sie an die NuGet Pakete kommen,
die für die CWS Entwicklung relevant sind.
Dies bringt folgende Probleme mit sich:
- Zu viel Zugriff
- Keine eindeutige Möglichkeit der Identifizierung
- Keine Möglichkeit einzelne Kunden zu revoken
Durch die eigene Instanz können den Kunden eigene,
sehr eingeschränkte Accounts zugewiesen werden.
Fehlende Features
Neben dem Fehlen der DownloadZahlen für github Packages,
wodurch sich nicht ermitteln lässt, welche veralteten Pakete gelöscht werden können.
Auf meine Github Diskussion wurde hier nicht reagiert.
Ein weitere PainPoint ist das Fehlen des sog. Fast-Forward-Merge.
In Github ist das nicht möglich, in Forgejo allerdings schon.
Damit erspare ich mir einen rebase nach jedem Release jedes einzelnen Microservices.
Datenhoheit
Unabhängig von dem offensichtlichen Verlust der Seriosität durch Hacks der eigenen Mitarbeiter,
sowie diverser grösserer Sicherheitslückenauf Github,
stellt sich die Frage, ob digitale Souveränität für uns ein relevantes Ziel ist.
Es erweckt auch nicht den anschein, als würde sich das in nächster Zeit änddern
Ganz abgesehen davon, dass es nicht abzusehen ist, wie sich der Markt in den USA weiter entwickeln wird.
Es ist zusätzlich auch ein Verkaufsargument gegenüber unseren Kunden,
dass weder Daten, noch Code, Schwerzenbach verlassen.
Wartungsfenster
Abgesehen von den Ausfällen durch Bugs und Infrastruktur-Problemen,
gibt es auch geplante Wartungsfenster von Microsoft.
Das letzte Wartungsfesnter war dieses hier:
EU Network Maintenance This incident has been resolved. Thank you for your patience and understanding as we addressed this issue. A detailed root cause analysis will be shared as soon as it is available. Jun 6, 15:31 - 18:49 UTC ( GithubStatus )
Glücklicherweise ist das ein Samstag gewesen, allerdings war Github hier für 7(!) Stunden nahezu unerreichbar.
4.1 Was forgejo nicht direkt löst
Ganz Aufwandsfrei ist die Migration allerdings nicht.
Während aufgrund der (fast) identischen Api (Kapitel 5)
bei den meisten Requests lediglich die BasisUrl verändert werden muss,
gestalten sich manche Integrationen etwas schwieriger.
Infrastrucutre-over-terraform
Wir verwalten Github gegenwärtig über ein Infrastruktur Repository.
Hierzu existiert ein forgejo-provider,
der hier ähnlich, aber nicht identisch ist.
Spacelift
Spacelift unterstützt nativ lediglich Github, Gitlab, Bitbucket und Azure Devops.
Hier muss leider etwas erfinderisch gearbeitet werden.
Allerdings unterstützt Spacelift Raw Git
und besitzt eine cli.
Der Migrationsaufwand sollte damit überschaubar sein.
Dependabot
Das Projekt Dependabot ist integriert, um in unseren Repositories nach Sicherheitslucken zu suchen.
Allerdings existieren diverse altenativen, die den gleichen Effekt erzielen.
Die bekannteste Integration ist Renovate.
Hierzu muss lediglich ein ServiceUser erzeugt werden.
Die Renovate-Cli wird bspw. über Systemd-Timer mit so einer Config gestartet:
module.exports = {
platform: 'forgejo',
endpoint: 'https://git.cmi.ch/api/v1/',
token: process.env.RENOVATE_TOKEN,
gitAuthor: 'Renovate Bot <renovate@cmi.ch>',
autodiscover: true,
osvVulnerabilityAlerts: true,
dependencyDashboard: true
};Hiermit liefert renovate die gleiche Funktionalität wie Dependabot:

Eine Einrichtungsanleitung lääst sich hier
5. Warum Forgejo
Von Gitlab, zu Bitbucket, über SourceForge und Gogs,
sowie exotischen und proprietären Lösung wie visual Source Safe oder Team Foundation Server.
Ich habe in den letzten Jahren jedes nennenswerte ALM System als Poweruser bedient wenn nicht sogar verwaltet.
Lässt man die Projektplanungsmöglichkeiten ausser Acht - diese werden von uns gegenwärtig über Youtrack abgebildet -,
so kann ich voller Überzeugung sagen, dass mit Blick auf Performance, Stabilität, Administrations-Aufwand und Benutzerfreundlichkeit,
Forgejo das beste System ist, das zur Verfügung steht.
Das ausschlaggebende Kriterium ist hier allerdings nicht meine persönliche Einschätzung.
Die Migration sollte weitestgehend nahtlos erfolgen und kein Schulung erfordern.
Aus diesem Grund sollte ein System gewählt werden,
dessen Abläufe kongruent zu Githubs Abläufen sind.
Forgejo erfüllt diese Anforderungen wie folgt:
Benutzer Oberfläche
Die Benutzer Oberfläche gestaltet sich nahezu identisch zu Github.




Integrationen
Wir haben bereits einige Integrationen im Einsatz.
Neben der Möglichkeit composite Actions direkt aus Github.com zu beziehen,
Können auch die meisten Integrationen in Forgejo genutzt werden,
Wie zB Claude-Code PR Reviews
CI-CD Pipelines
Den grössten Vorteil liefert hier die Tatsache, dass die Forgejo-Actions
nahezu die identische Syntax zu den Github Actions haben.
Der Migrationsaufwand ist damit sehr minimal.und ist weitestgehend gewollte Veränderungen, um für eine bessere Performance zu sorgen.
API Kompatibilität
Der Grund, warum Integrationen usw. so gut funktionieren ist der,
dass sich forgejo hier sehr stark an die Vorgaben der Github API hält.
Forgejo besitzt einen Swagger gegenüber dem sich die aktuell verwendeten Abfragen
verifizieren lassen.
Migration
Forgejo hat eine Migration direkt verbaut.
Hierdurch verlieren wir keine Releases, Pull Requests oder Milestones.

Cli
Neben den Actions verwenden auch einige Entwickler die Github cli aufgrund ihrer bequemlichkeit.
Für forgejo existieren fgj und fj,
die die gleiche Funktionalität bei (fast) gleicher Syntax erlaubt.
claude-code ist übrigens ebenfalls sehr gut in der Lage, mit seinen Toolcalls mit fgj umzugehen.
6. CI-Lastanalyse (Basis der Server-Dimensionierung)
6.1 Datengrundlage
Auswertung des CI-Abrechnungs-Logs der WarpBuilds (2 207 Job-Läufe, 1.–31. Mai 2026, ~30 Tage).
Das Log enthält pro Lauf:
- einen Startzeitpunkt (
timestamp) - Die Laufzeit (
execution_time) - Den Runner-Typ.
Wichtige Erkenntnis: 100 % der gemessenen Last sind Windows-Runner (
warp-windows-*). Der .NET-Framework-Stack erzwingt Windows. Linux-CI existiert, ist aber sehr klein (s. u.).
6.2 Runner-Typen (WarpBuild Cloud)
| Runner-Label | vCPU | RAM | Läufe (Mai) |
|---|---|---|---|
warp-windows-latest-x64-2x | 2 | 7 GB | 678 |
warp-windows-latest-x64-8x | 8 | 32 GB | 1 122 |
warp-windows-latest-x64-16x | 16 | 64 GB | 407 |
(„Nx” = Anzahl vCPU; 2x ist bei WarpBuild abgekündigt und fällt auf 4x/16 GB zurück.)
6.3 Maximal gleichzeitig laufende Agents (gemessen)
| Kategorie | Läufe | Spitze gleichzeitig | Zeitpunkt |
|---|---|---|---|
…-8x (8 vCPU) | 1 122 | 13 | 19. Mai, 13:54 |
…-2x (2 vCPU) | 678 | 4 | 21. Mai, 08:23 |
…-16x (16 vCPU) | 407 | 3 | 19. Mai, 13:41 |
| Gesamt (alle Typen) | 2 207 | 13 | 19. Mai, 13:54 |
Nach Job-Art:
| Job | Läufe | Peaks gleichzeitig |
|---|---|---|
ci-server / ci_build | 844 | 5 |
Execute bdd tests / bdd-tests | 699 | 5 |
integration-large-runner (CMIAXIOMARechte) | 332 | 4 |
integration-large-runner (MEHRMANDANTEN_2) | 332 | 4 |
6.4 Ressourcen-Peaks (das, was der Server tragen muss)
Da ein 16x-Agent das Achtfache eines 2x-Agents an CPU braucht, zählt nicht die reine Anzahl, sondern die gewichtete Spitze:
| Metrik | Gemessene Spitze | Zeitpunkt |
|---|---|---|
| Gleichzeitige Agents | 13 | 19. Mai, 13:54 |
| vCPU-Bedarf | 104 vCPU | 19. Mai, 13:54 |
| RAM-Bedarf | 416 GB | 19. Mai, 13:54 |
| Theoretisches Worst-Case (alle Kategorie-Spitzen gleichzeitig – nie beobachtet) | 160 vCPU / 636 GB | – |
Zur Spitze waren faktisch alle 13 gleichzeitigen Agents 8x-Runner (13 × 8 vCPU = 104,
13 × 32 GB = 416 GB).
Zudem ist der aktuell teilweise aktivierte 16x-Agent nur testweise aktiv und liefert einen marginalen Performanceboost.
Zweite Erkenntnis aus dem Job-Report: Die CPU-Auslastung der 16x-Agents war moderat::
- ci_build -> 67 %,
- tests 18–45 % Der RAM lief jedoch heiss (92–96 %). ⇒ RAM ist die harte Grenze
Zahlen können allerdings durch SqlServer etc. verfälscht sein
7. Server-Dimensionierung
7.1 Modell und Annahmen
| Annahme | Wert | Begründung |
|---|---|---|
| Dimensionierungsziel | Reale Spitze + Reserve | Heutige Last soll nie in die Warteschlange laufen |
| CPU-Überbuchung | 1,2 : 1 (vCPU : Kern) | Agents lasten selten alle Kerne gleichzeitig voll aus. Ggf ist hier durch selfhost noch Optimierung zu erzielen |
| RAM-Überbuchung | 1 : 1 (keine) | RAM ist die harte Grenze (92–96 % gemessen) |
| Windows-Runner | KVM/QEMU, Pool + Burst | Firecracker kann kein Windows (siehe Kapitel 8) |
| Linux-Runner | Firecracker-microVMs | Sehr klein: ~6 vCPU / 40 GB Spitze |
7.2 Ableitung des Grundbedarfs
| Komponente | vCPU/Kerne | RAM |
|---|---|---|
| Windows-Runner | ~72 Kerne | 432 GB |
| Linux-Firecracker | ~10 Kerne | 40 GB |
| Zwischensumme Runner-Last | ~82 Kerne | 472 GB |
7.3 Die drei Dimensionierungs-Stufen
Auf die Runner-Last kommt eine Reserve für Forgejo + Datenbank + einige Microservices + OS. Wir zeigen bewusst drei Stufen für die Argumentation:
| Stufe | Zweck | + Reserve | Total Kerne | Total RAM |
|---|---|---|---|---|
| A – „Was wir wirklich brauchen” | Heutiger Betrieb | 8 C / 32 GB | ~84 Kerne | ~488 GB |
| B – „Für geplante Erweiterungen” | Mehr Microservices/Wachstum | 12 C / 56 GB | ~88 Kerne | ~512 GB |
| C – „Sicherheitspuffer” | Grosszügig, sorgenfrei | 24 C / 128 GB | ~100 Kerne | ~584 GB |
- Stufe A genügt möglicherweise heute.
- Stufe B deckt absehbare Erweiterungen,
- Stufe C ist reiner Komfortpuffer.
8. Architektur
┌──────────────────────────────────────────────────────────────┐
│ Bare-Metal-Server (Linux-Host) │
│ │
│ ┌──────────────┐ ┌───────────────────────────────────┐ │
│ │ Forgejo + │ │ Windows-Runner (KVM/QEMU) │ │
│ │ DB + │ │ • kleiner Warm-Pool (~6-8 VMs) │ │
│ │ Microservices│ │ • Burst aus Golden-Snapshot │ │
│ │ │ │ • Snapshot-Revert nach jedem Job │ │
│ └──────────────┘ └───────────────────────────────────┘ │
│ ┌───────────────────────────────────┐ │
│ │ Linux-Runner (Firecracker microVM)│ ← klein, ephemer │
│ └───────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
8.1 Linux-Runner: Firecracker
Linux-Runner müssen nicht “warmgehalten” werden.
Mittels Firecracker können sekundenschnell ephemere microVMs gestartet werden.
Dies liefert saubere Umgebung pro Job.
Bedarf heute minimal (~6 vCPU / 40 GB). Kapazität wird vorgehalten, aber nur klein reserviert.
Mit der dotnet Migration sollten fast Alle Windows Runner in den nächsten Jahren abgeschafft werden können.
8.2 Windows-Runner: KVM/QEMU
Firecracker unterstützt kein Windows (minimaler VMM ohne ACPI/PCI-Gerätemodell, nur
Linux-Gäste).
Windows-Gäste laufen daher unter KVM/QEMU (oder Cloud Hypervisor).
Ein vollständig automatisiertes Setup inklusive Compilerchain steht hier schon bereit.
Es werden hier also 6 VMs warm gehalten.
Weitere VMs können ebenfalls on-demand gestartet werden.
9. Server-Empfehlungen & Preise
CPU
Vergleicht man etwa einen 128-Kern-9754 (Zen 4c, langsame 2,25/3,1 GHz) mit dem schnelleren 64-Kern 9555P (Zen 5, 3,2/4,4 GHz),
sieht man genau, warum hier auf weniger, allerdings schneller Kerne gesetzt wird.
Die Last ist nicht CPU-, sondern RAM-gebunden, und
64 schnelle Kerne/128 Threads decken die 104-vCPU-Spitze – schnelle Kerne verkürzen die langen
Build-/Test-Jobs (BDD ~27 min).
Ein grösserer Prozessor wurde ausserdem aufgrund des höheren Strombezugs und der damit verbundenen Abwärme und Lautstärke nicht gewählt.
Zusätzlich würde dieser höhere Kosten mit sich bringen, während nur ein marginaler Vorteil zu erwarten wäre.
Als gutes Mittelmass wurde hier der Epyc 9555P gewählt:
- 64 Kerne (128 Threads)
- 3,2 GHz Basistakt
- 4,4 GHz Maximale Boost-Taktung
- 4,2 GHz Maximale Boot-Taktung auf allen Kernen
- 256Mb L3 Cache
- 320-360W TDP
RAM
Aufgrund des AI Booms, in dem Sam Altman 25% des weltweit verfügbaren Speichers erwirbt,
liefert der Arbeitsspeicher den mit Abstand grössten Kostenpunkt in der Beschaffung (siehe Preisliste)
Ebenfalls bleibt die Auswahl hier sehr eingeschränkt,
da es Server Prozessoren nur wenige Arbeitsspeicher unterstützen.
Für die GC-/bandbreitenlastige C#-Last (Roslyn/MSBuild + viele vstest-Hosts) ist die volle 12-Kanal-Bestückung empfohlen!
Genaueres dazu findet sich im Kapitel 10: GC-Tuning. Das 768-GB-Sparpaket
bleibt möglich (−€ 9 600), gibt aber ~⅓ Speicherbandbreite auf. (Volle 12 Kanäle gibt es bei TK
nur als 12×96 = 1,15 TB; 768 GB at 12 Kanälen wäre das 12×64-Samsung-Modul für ~€ 34 000 – nicht
sinnvoll.)
9.1 Lärm & leise Kühlung
Das Thema Lärm und Kühlung betrifft lediglich die selbst gebauten/refurbishten Optionen (1/4/5).
Die gewählte Option wird vom Hersteller leise gekühlt (< 30 dB) – dort entfällt dieses Thema.
Ein 1U/2U-Rackserver ist laut („Düsentriebwerk”).
Der naheliegende Gedanke - die Lüfter gegen leise Noctua-Lüfter tausche - scheitert beim 1U-Refurb an mehreren Punkten:
| Hürde beim 1U-Rack-Mod | Konsequenz |
|---|---|
| 1U bietet nur Platz für 40-mm-Hochdrehzahl-Lüfter | Kein Platz für leise 80/120-mm-Lüfter |
| ~360W Abwärme | Hoher Luftdurchsatz zwingend nötig |
| iDRAC9 sperrt in neueren Firmware die manuelle Lüftersteuerung | Nur per Firmware-Downgrade umgehbar – Garantie erlischt mglw. |
| Netzteillüfter sind nicht regelbar | Laufen immer auf Maximum und sind dementsprechend laut |
| Proprietärer Dell-Lüfterstecker | Jeder Lüfter muss umgelötet werden; Garantie erlischt |
Bekannte „Silent-Dell”-Umbauten gelingen – aber stets an grösseren, kühleren Geräten (z. B. 2U/4U mit Niedrig-TDP-CPU), nicht an einem 1U. Fanmod Beispiele:
Damit Schwerzenbach nicht zum Flughafengelände wird, bestehen folgende Optionen:
-
Weg A – Leiser Tower-Eigenbau (Option 4): Sockel SP3 (EPYC 7763) wird von Noctua direkt unterstützt – NH-U14S / NH-U12S TR4-SP3 (von Phoronix auf EPYC getestet). Standard-PWM, keine Firmware-Tricks, kein lautes 1U-Netzteil. Der ältere 7763 ist hier sogar im Vorteil: Für SP5 (9654) gibt es keinen Noctua-Kühler.
-
Weg B – Rack behalten, Lärm über den Standort lösen: Refurb-Rack unangetastet in einen separaten Technikraum oder ein schallgedämmtes Akustik-Rack stellen. Günstigste Hardware, kein Thermo-Risiko, Garantie bleibt.
10. Performance-Tuning: .NET & Garbage Collector (Runner)
Build (MSBuild/Roslyn) und Tests (vstest.console / testhost) laufen bei .NET Framework 4.8 auf der .NET-Framework-CLR.
Deren GC wird über app.config/machine.config (<runtime>) bzw. COMPlus_*-Umgebungsvariablen konfiguriert –
nicht über die DOTNET_*/runtimeconfig-Knobs von .NET 5+.
Da die Last allokations- und GC-lastig ist (Roslyn erzeugt enorme Gen0-Churn, dazu viele parallele Testhosts),
beeinflusst die GC-Konfiguration Build-/Testzeiten und den Speicherbandbreitenbedarf direkt.
Pro Windows-Runner-VM empfohlen:
- Server GC aktivieren –
<runtime><gcServer enabled="true"/></runtime>(bzw.COMPlus_gcServer=1). Sammelt parallel über mehrere Heaps → höherer Durchsatz unter Last. GCHeapCount= vCPUs der VM –<runtime><GCHeapCount>N</GCHeapCount>(oderCOMPlus_GCHeapCount=0xN, Hex). Server GC legt sonst ein Heap + GC-Thread pro logischem Kern an; in der VM auf die vCPU-Zahl fixieren, damit die GC-Parallelität der VM-Größe entspricht und nicht „über-threadet” – spart Bandbreite und Kontextwechsel.- Concurrent/Background GC bewusst wählen –
<gcConcurrent enabled="false"/>(COMPlus_gcConcurrent=0) erhöht bei reinen Batch-Läufen oft den Gesamtdurchsatz (keine Hintergrund-GC-Threads, die Bandbreite kosten); für latenz-/interaktiv eher an lassen. Pro Job-Typ messen. - Heap-Obergrenze: Ein hartes
GCHeapHardLimitgibt es nur in .NET 5+/Core, nicht in .NET Framework. Für die Framework-Hosts ist daher die pro-VM zugeteilte RAM-Menge die effektive Obergrenze – Runner-VMs streng nach Größe (2x/8x/16x) dimensionieren, damit ein „Ausreißer”-Testlauf nicht den Host gefährdet. (Künftige .NET-5+/Linux-Runner:DOTNET_GCHeapHardLimit.) - Test-Parallelität dosieren –
vstest.console … /Parallelstartet je Test-Assembly einentesthost-Prozess (jeder mit eigener GC). Parallelität bzw.RunSettings→MaxCpuCountso wählen, dass Hosts × Threads die VM-vCPUs nicht massiv überbuchen. - MSBuild-Parallelität –
msbuild /m:<n>an die VM-vCPUs koppeln; den Roslyn-Compilerserver (VBCSCompiler.exe) je VM wiederverwenden, bei Snapshot-Revert aber sauber beenden.
Warum das hier zählt: Diese Stellschrauben begrenzen und glätten den Speicherverkehr je VM. Zusammen mit der vollen 12-Kanal-RAM-Bestückung (Kapitel 9) sind sie der entscheidende Hebel gegen GC-bedingte Bandbreiten-Engpässe, wenn ~13 C#-Build-/Test-VMs gleichzeitig sammeln.
11. On-Prem-Readiness-Checkliste
Der Standort im Haus ist noch offen. Vor der Inbetriebnahme zu klären:
- Strom: Gewählter Single-Socket-Server (EPYC 9555P, 360 W TDP) zieht ~400–650 W
Ein eigener 230V/16A Stromkreis (3,6 kW) sollte für Server und Netzwerk bereitgestellt werden.
Grosszügig geschätzt sollten wir in richtung 1.15 kVA kommen - Kühlung: ~1500–2500 BTU/h Abwärme falls einer der 1U Server gewählt wird.
Der Silent-Tower (empfohlen) ist bürotauglich und kann in einen leeren Raum gestellt werden. Die Rack-Alternativen brauchen einen eigenen Technikraum. - Lärm: (siehe Kühlung)
- Netzwerk: Gigabit/10G ins LAN;
Reverse-Proxy + TLS für externen Zugriff wird von Ops verwaltet. - Storage: Forgejo-Daten + Artefakte + Caches auf RAID (Ausfallsicherheit); schnelles NVMe-Scratch für Runner. Wachstum einplanen.
- Backups: Tägliche, off-box gesicherte Backups (Forgejo-DB + Repos + Konfiguration);
Backup auf S3 möglich.
Forgejo liefert mittelsforgejo dump -c /etc/forgejo/app.iniein zip.
Postgresql lässt sich überpg_dumpsichern.
Optional Mirror auf Backup Instanz - Cold-Spare: Ersatzteile bzw. dokumentierter Wiederaufbau-Pfad (Infrastructure-as-Code), damit ein Hardware-Defekt nicht zum mehrtägigen Ausfall wird.
- Hardware-Monitoring: IPMI/BMC, Temperatur-, Strom- und Dienst-Überwachung mit Alarmierung.
- Software-Monitoring: Grafana Dashboard Einbindung
12. Risiken
| Thema | Risiko | Massnahme |
|---|---|---|
| Windows-Lizenzierung | Windows Server wird pro Kern lizenziert; viele Windows-VMs könnten sonst teuer werden. | Windows VMs können ggf. Reduziert werden (mglw. Laufen Tests auch unter Linux) |
| Einzelner Server | Hardware-Defekt = Ausfall der Dev-Plattform | Redundante PSU (konfigurierbar), RAID, ECC; off-box-Backups; Cold-Spare; späteres HA-Upgrade möglich |
| Migrationsaufwand | GitHub Actions → Forgejo Actions, Repos/PRs/Issues importieren | Forgejo-Migrationstools nutzen; Workflows sind weitgehend kompatibel; Pilot mit einem Repo |
| .NET-Framework-Bindung | Erzwingt Windows-Runner dauerhaft | Bewusst eingeplant (KVM-Pool); Linux/Firecracker für Neues vorbereitet |
| Betriebsverantwortung | Wir betreiben jetzt selbst (Updates, Verfügbarkeit) | Monitoring, Wartungsfenster, dokumentierte Runbooks |
13. Fazit mit retrospektiv betrachteten, administrativen Aufwand
Ein Cloudprovider wie Github mag auf den ersten Blick sehr attraktiv wirrken.
Allerdings ist der administrative Aufwand damit nicht vollständig abgedeckt.
Wir befinden uns erst seit 8 Jahren auf Github.
Trotzdem sind wir sehr oft zu irgendwelchen - eigentlich überflüssigen - Workarounds gezwungen.
Beispiele sind hierbei:
- Tricks in Actions, weil ein Job nicht “korrekt funktioniert”
- Custom CodeOwners action, da nicht feingranular auf Dateiebene konfigurierbar. Zusätzlich E-Mail Flood.
- Hunderte Stunden an Analysearbeit, um der Ursache von Ausfällen, fehlenden Triggern,
abgebrochenen Github Action usw. nachzugehen
Retrospektiv betrachtet ist der administrative Aufwand für unser Github höher, als für alle anderen ALM Systeme, die ich betreue, zusammengenommen(!).