Defense & Protection Measures
We have witnessed the historic attacks on the Codeberg infrastructure, primarily through DDOS attacks (on the technical side) and user spam (on the moderation side). DDOS is hard to prevent in the first place, even with active support rails from the underlying cloud provider. It highly depends on the magnitude of the attack whether it will be classified as “DDOS” or just as “heavy traffic”.
We want to be frank and open here: we can’t say what will happen until the first attack has landed ;)
In general, there are many ways one can attack a public service. We are trying our best to put practices in place that prevent unauthorized access, resource abuse and other known risk factors, such as SQL injection attacks and cross-site scripting (XSS) attacks. This goes in line with a clear and transparent RBAC-system for all satellite-services in place which can eventually have an influence on the primary instance and its data.
Multi-Layered Defense System
Section titled “Multi-Layered Defense System”Following HAProxy’s bot protection guidelines, we have implemented a multi-layered defense system with the following measures:
Rate Limiting & Traffic Control
Section titled “Rate Limiting & Traffic Control”- General rate limiting per IP address: 10,000 requests per 30 minutes (~5.5 requests/second sustained)
- Per IP+URL rate limiting over a 24-hour window to prevent targeted resource abuse
- Path-specific rate limiting with different thresholds:
- Static assets (
/assets,/avatars): 4000 requests per 30 minutes - Large repositories (containing linux, bsd, kernel): 1200 requests per 30 minutes
- Git operations (commit, branch, compare): 2000 requests per 30 minutes
- Static assets (
- /16 subnet rate limiting: 150 requests per minute per /16 subnet, catching distributed bot swarms that evade per-IP limits by spreading requests across thousands of IPs in the same subnet
- Error-based rate limiting blocking IPs with >10 error responses over 5 minutes
- Brute force protection: 10 POST requests to /login per 3 minutes
Attack-Specific Protection
Section titled “Attack-Specific Protection”- Brute force attack prevention for login endpoints (>10 POST requests to
/loginwithin 3 minutes) - WordPress/CMS attack blocking for common attack vectors (
/wp-admin/,/wordpress/) - Bot persistence tracking that tags and continues blocking suspected bots until stick-table expiration
Bot Detection & Blocking
Section titled “Bot Detection & Blocking”- User-Agent based detection blocking known malicious bots (
semrus,AhrefsBot,MJ12bot,ZoominfoBot,DotBot,MauiBot,BacklinksExtendedBot,BLEXBot,Barkrowler,SeznamBot,DataForSeoBot,IbouBot,serpstatbot,facebookexternalhit,l9explore,PerplexityBot,meta-webindexer,meta-externalagent,AwarioBot,NRC Audio,CensysInspect,NexusSearchBot,Scrapy, among others) - Outdated browser blocking for Chrome, Edge, Chrome on iOS, and Firefox versions older than about three months (see Outdated Browsers)
- Current Firefox ESR releases and the Android System WebView are exempt from the version check
- Discontinued browser engines (Internet Explorer/Trident and Presto-based Opera) are blocked outright
- IP-based blocking using curated lists from the Ultimate Hosts Blacklist project
Security Headers & Request Sanitization
Section titled “Security Headers & Request Sanitization”- HSTS enforcement with 2-year max-age, subdomain inclusion, and preload directive
- Anti-clickjacking protection via X-Frame-Options
- MIME type sniffing prevention through X-Content-Type-Options
- Secure cookie enforcement with Secure and SameSite=Lax attributes
- Privacy protection including FLoC opt-out
- Request header sanitization removing client-provided IP headers to prevent spoofing
Allowlist for Good Bots
Section titled “Allowlist for Good Bots”On top, we also have a dedicated allowlist for “good bots”. These are helpful to let projects be found by search engines and alikes. We are using a curated list from “AnTheMaker/GoodBots” for that.
Outdated Browsers
Section titled “Outdated Browsers”If your browser reports an old version, CodeFloe answers with a 403 Browser Update Required page instead of the page you asked for.
This is not because CodeFloe is vulnerable to old browsers.
It is one of the most effective defences we have against scrapers.
Most of the abusive crawling traffic we see sends a User-Agent header claiming to be a Chrome release that is several months old.
These crawlers rotate through thousands of IP addresses, often from residential proxy pools, so rate limits per IP cannot catch them.
The browser version they claim, however, stays the same across all of those addresses.
Real browsers update themselves automatically within days to a few weeks, so almost no person is still on a release that old.
In our traffic analysis, the requests below the threshold were nearly all single requests from addresses we never saw again, while the requests from current versions looked like normal browsing sessions.
What is accepted
Section titled “What is accepted”- Chrome, Edge, Chrome on iOS, and other Chromium-based browsers (Brave, Vivaldi, Opera, …) are accepted if their major version was already the stable release about three months ago or is newer.
- Firefox follows the same three-month rule.
- The Firefox ESR lines Mozilla currently supports are always accepted.
- Android System WebView, the in-app browser many Android apps open links in, is not checked, because it updates separately from Chrome and often lags behind it.
- Safari and other browsers that do not identify as Chrome or Firefox are not checked.
- Internet Explorer and the old Presto-based Opera are always blocked.
The thresholds are recalculated from Google’s and Mozilla’s release feeds on every deploy, and the error page shows the minimum versions currently in effect.
If you see the page with an up-to-date browser
Section titled “If you see the page with an up-to-date browser”The check only looks at the version your browser sends in its User-Agent header.
If you are sure your browser is current, something is probably changing that header:
- Privacy extensions and user-agent switchers often send a fixed, older browser version.
Turn them off for
codefloe.com, or set them to report your real version. - Some corporate proxies and security products rewrite the header.
- Browsers that are no longer updated on your operating system (for example Chrome on Windows 7 or old macOS versions) are blocked by design. Switching to Firefox ESR is usually the easiest way out.
If none of this applies, please report it on the forum and include the User-Agent your browser sends, which you can see on sites such as https://www.whatismybrowser.com.
SSH Brute-Force Protection
Section titled “SSH Brute-Force Protection”Git over SSH is reached on port 22 (proxied by HAProxy to OpenSSH sshd, which also accepts shell connections directly on port 2222).
The SSH transport is hardened on two layers:
- OpenSSH hardening —
MaxAuthTries 20per connection andLoginGraceTime 60scap how much a single attacker can extract from one handshake. - fail2ban watching the systemd
sshdjournal with four layered jails, all banning at the firewall via firewalld rich rules:sshd— 5 failed auths in 10 min → 1 h ban (everyday brute-force)sshd-aggressive— 10 in 5 min → 24 h ban (active scanners)sshd-ddos— 20 in 1 min → 2 h ban (connection floods)sshd-long-term— 15 in 1 h → 24 h ban (slow persistent attackers)
Bans persist across reboots via a sqlite-backed state file, and internal subnets plus known-good IPs are allowlisted so CI agents and internal tooling are never affected.
Legitimate users with several SSH keys loaded in their ssh-agent can accidentally trip the sshd jail, because OpenSSH offers every loaded key in turn and each one the server does not recognise counts as a failed attempt.
See SSH Access for the recommended client configuration that avoids this.