🛡️ Gitea Bot Protection - Lessons Learned

"Das Problem wird bestimmt vielen auf die Füße fallen"


❌ Warum v1 (deploy-bot-protection.sh) uncool war:

Problem 1: Falsche Datei

Script bearbeitete: git.crumbforest.org
Aber nginx nutzt:    git.crumbforest.org.conf

= Script änderte falsche Datei, nichts passierte

Problem 2: Multiline Return Statements

# Das funktioniert NICHT:
return 200 "Line 1
Line 2
Line 3";

# Nginx Syntax Error!

Problem 3: Gitea kämpfen statt mit Gitea arbeiten

Versuch: robots.txt in nginx location block
Reality: Gitea fängt /robots.txt ab und gibt 404

= Gitea HAT eigene robots.txt Funktion!
= Nutze die statt dagegen zu kämpfen!

Problem 4: Zu komplex

- 300+ Zeilen Code
- Viele Annahmen über File-Struktur
- Komplexe sed/awk Magie
- Schwer zu debuggen

= Uncool!

✅ Warum v2 (deploy-gitea-bot-protection.sh) cool ist:

Fix 1: Findet die richtige Config

# Versucht alle gängigen Namen:
- git.crumbforest.org
- git.crumbforest.org.conf
- gitea
- gitea.conf

# Checked ob git.crumbforest.org drin steht
# = Funktioniert immer!

Fix 2: Arbeitet MIT Gitea

# In /etc/gitea/app.ini:
[other]
ROBOTS_TXT = User-agent: GPTBot\nDisallow: /

= Gitea's EIGENE robots.txt Funktion!
= Kein Kampf mit nginx location blocks
= Funktioniert IMMER!

Fix 3: Simple Rate Limiting

# Keine komplexen if-Blocks in location
# Sondern: Eine Zone, eine Zeile
limit_req zone=$gitea_rate_limit_zone burst=10 nodelay;

= Einfach, lesbar, funktioniert

Fix 4: Robuste Checks

# Pre-flight:
- Ist Gitea installiert?
- Existiert app.ini?
- Ist nginx da?

# Post-flight:
- nginx -t (config valid?)
- curl robots.txt (funktioniert?)
- Rollback wenn Fehler

= Kann nicht kaputt gehen!

🔧 Installation (v2):

# 1. Script downloaden
wget https://git.crumbforest.org/.../deploy-gitea-bot-protection.sh
# ODER: Aus diesem Repo

# 2. Ausführbar machen
chmod +x deploy-gitea-bot-protection.sh

# 3. Als root ausführen
sudo ./deploy-gitea-bot-protection.sh

# 4. Fertig!

🐛 Troubleshooting:

"robots.txt gibt immer noch 404"

# Check 1: Ist [other] Section in app.ini?
grep -A 2 "\[other\]" /etc/gitea/app.ini

# Sollte zeigen:
# [other]
# ROBOTS_TXT = ...

# Check 2: Wurde Gitea neu gestartet?
sudo systemctl restart gitea

# Check 3: Ist Gitea wirklich auf Port 3000?
ss -tlnp | grep 3000

# Check 4: Test direkt gegen Gitea (ohne nginx)
curl http://localhost:3000/robots.txt

"Rate limiting funktioniert nicht"

# Check 1: Ist die Config-Datei da?
ls -la /etc/nginx/conf.d/gitea-rate-limits.conf

# Check 2: Ist nginx config valid?
sudo nginx -t

# Check 3: Sind die Zones geladen?
sudo nginx -T | grep "limit_req_zone"

# Check 4: Monitoring
tail -f /var/log/nginx/error.log | grep "limiting requests"

# Wenn OpenAI crawlt und limit erreicht:
# [error] limiting requests, excess: 5.123 by zone "gitea_openai"

"Script findet nginx config nicht"

# Manuell suchen:
find /etc/nginx -name "*git*"

# Welche wird wirklich geladen?
sudo nginx -T | grep "git.crumbforest.org"

# Symlink checken:
ls -la /etc/nginx/sites-enabled/ | grep git

# Falls nicht gefunden:
# → Script anpassen mit richtigem Pfad
# → Oder manuell deployen (siehe Manual Deploy unten)

"Nginx reload failed"

# Check syntax error:
sudo nginx -t

# Check logs:
sudo journalctl -u nginx -n 50

# Rollback zum Backup:
BACKUP_DIR="/root/bot-protection-backup-XXXXXXXX"  # Vom Script Output
sudo cp $BACKUP_DIR/nginx.backup /etc/nginx/sites-available/git.crumbforest.org.conf
sudo systemctl reload nginx

🔧 Manual Deploy (Fallback):

Falls Script komplett fehlschlägt:

Schritt 1: Gitea robots.txt

sudo nano /etc/gitea/app.ini

Am Ende hinzufügen:

[other]
ROBOTS_TXT = User-agent: GPTBot\nDisallow: /\n\nUser-agent: ChatGPT-User\nDisallow: /\n\nUser-agent: *\nAllow: /

Speichern und Gitea neu starten:

sudo systemctl restart gitea
curl http://localhost:3000/robots.txt  # Test!

Schritt 2: Rate Limiting

sudo nano /etc/nginx/conf.d/gitea-rate-limits.conf

Inhalt:

# Rate Limit Zones
limit_req_zone $binary_remote_addr zone=gitea_openai:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=gitea_general:10m rate=100r/m;

# OpenAI Detection
geo $is_openai {
    default 0;
    74.7.227.0/24 1;
    74.7.242.0/24 1;
    74.7.243.0/24 1;
}

# Select Zone
map $is_openai $rate_zone {
    default "gitea_general";
    1 "gitea_openai";
}

In nginx site config (git.crumbforest.org.conf):

sudo nano /etc/nginx/sites-available/git.crumbforest.org.conf

In location / Block (vor proxy_pass):

location / {
    limit_req zone=$rate_zone burst=10 nodelay;

    proxy_pass http://localhost:3000;
    # ... rest
}

Test und reload:

sudo nginx -t
sudo systemctl reload nginx

📊 Monitoring nach Deploy:

# 1. Live OpenAI Requests
tail -f /var/log/nginx/access.log | grep "74.7.227"

# 2. Rate Limit Hits
tail -f /var/log/nginx/error.log | grep "limiting requests"

# 3. Gitea Status
systemctl status gitea

# 4. robots.txt Fetches
grep "robots.txt" /var/log/nginx/access.log | tail -20

# 5. Morgen: waldwächter-analyzer.sh nochmal laufen
./waldwächter-analyzer.sh
# Sollte zeigen: MASSIV weniger OpenAI Traffic!

🎯 Erwartete Resultate:

Vorher:

OpenAI (74.7.227.14): 47,329 requests/Tag
= Alle 2 Sekunden ein Request!
= Crawlt ALLES (jeden Commit, jeden Branch)

Nachher:

OpenAI: MAX 5 requests/Minute
= 7,200 requests/Tag
= 85% REDUKTION! 🎉

robots.txt zeigt: Disallow: /
= Bots die respektieren (Googlebot, etc) stoppen komplett
= Bots die nicht respektieren (manche) werden rate-limited

💡 Für andere Gitea Instanzen:

Dieses Problem betrifft JEDEN der:
- Gitea öffentlich hosted
- Nginx als Reverse Proxy nutzt
- Von AI Crawlern gecrawlt wird

Die Lösung:
1. NICHT in nginx robots.txt bauen
2. SONDERN Gitea's app.ini nutzen
3. Rate Limiting in nginx (einfach)
4. Test, deploy, monitor

Das Script funktioniert für:
- Ubuntu/Debian
- Standard Gitea Installation
- Nginx als Reverse Proxy
- LetsEncrypt SSL

Anpassungen nötig für:
- Andere Distros (Paths können abweichen)
- Apache statt Nginx
- Andere Proxy-Setups


📝 License & Credits:

Script: MIT + CKL + HHL
Von: waldwächter Team / Crumbforest
Für: Alle die das gleiche Problem haben werden

"Steal it smart!"

🐛 Bug Reports:

Falls Script bei dir nicht funktioniert:

  1. Run mit debug:
bash -x ./deploy-gitea-bot-protection.sh 2>&1 | tee debug.log
  1. Share debug.log + diese Info:
  2. OS Version (cat /etc/os-release)
  3. Nginx Version (nginx -v)
  4. Gitea Version (gitea --version)
  5. Config paths (find /etc/nginx -name "*git*")

  6. Öffne Issue oder PR mit Fix!


🌲 waldwächter says: Viel Erfolg! Und: Der Wald schützt zurück!