Skip to content

Instantly share code, notes, and snippets.

@blueskychan-dev
Last active July 19, 2025 09:05
Show Gist options
  • Save blueskychan-dev/b2ea76805229b5d9a0b52629658c502f to your computer and use it in GitHub Desktop.
Save blueskychan-dev/b2ea76805229b5d9a0b52629658c502f to your computer and use it in GitHub Desktop.
How to protect your bancho.py production server from being attacked

Comprehensive Protection Guide for bancho.py Production Servers

Introduction

Many new osu! private servers using bancho.py are being listed on https://osu-server-list.com without proper security measures. This guide provides detailed steps to protect your server from common attacks.

image

Table of Contents

  1. Server Exposure Risks
  2. Firewall Configuration
  3. Rate Limiting Implementation
  4. Command Security
  5. Additional Protection Measures

Server Exposure Risks

How Attackers Find Your Server

  • SSL Certificate Scanning: Services like Censys/Shodan scan port 443/80 and extract domain info from SSL certificates
  • Direct IP Exposure: Unprotected bancho.py servers expose ports (10000/tcp) directly
  • DNS Vulnerabilities: Unprotected DNS (port 53/udp) can be DDoSed and get blackhole

Common Vulnerabilities in New Servers

  1. Inadequate firewall rules
  2. Missing rate limiting
  3. Dangerous production commands left enabled
  4. Exposed database ports
  5. No DDoS protection

Firewall Configuration

Initial UFW Setup

# Always allow SSH first to prevent lockout
sudo ufw allow 22/tcp

# Block known malicious IP ranges and scanners
sudo ufw deny from 162.142.125.0/24
sudo ufw deny from 167.94.138.0/24
sudo ufw deny from 198.20.69.72
sudo ufw deny from 198.20.69.96
sudo ufw deny from 93.120.27.62
sudo ufw deny from 66.240.236.119
sudo ufw deny from 71.6.135.131
sudo ufw deny from 82.221.105.6
sudo ufw deny from 82.221.105.7
sudo ufw deny from 188.138.9.50
sudo ufw deny from 85.25.103.50
sudo ufw deny from 198.20.69.72/29
sudo ufw deny from 198.20.69.96/29
sudo ufw deny from 198.20.70.104/29
sudo ufw deny from 198.20.99.128/29
sudo ufw deny from 198.20.87.96/29
sudo ufw deny from 66.240.192.138
sudo ufw deny from 71.6.167.142
sudo ufw deny from 71.6.165.200
sudo ufw deny from 85.25.43.94
sudo ufw deny from 71.6.146.185
sudo ufw deny from 71.6.146.186
sudo ufw deny from 71.6.158.166
sudo ufw deny from 66.240.219.146
sudo ufw deny from 209.126.110.38
sudo ufw deny from 104.236.198.48
sudo ufw deny from 104.131.0.69
sudo ufw deny from 162.159.244.38
sudo ufw deny from 159.203.176.62
sudo ufw deny from 188.138.1.119
sudo ufw deny from 80.82.77.33
sudo ufw deny from 80.82.77.139
sudo ufw deny from 71.6.146.130
sudo ufw deny from 66.240.205.34
sudo ufw deny from 216.117.2.180
sudo ufw deny from 93.174.95.106
sudo ufw deny from 89.248.172.16
sudo ufw deny from 185.163.109.66
sudo ufw deny from 89.248.167.131
sudo ufw deny from 94.102.49.190
sudo ufw deny from 94.102.49.193
sudo ufw deny from 185.181.102.18
sudo ufw deny from 167.94.145.0/24
sudo ufw deny from 167.94.146.0/24
sudo ufw deny from 167.248.133.0/24
sudo ufw deny from 199.45.154.0/24
sudo ufw deny from 199.45.155.0/24
sudo ufw deny from 206.168.34.0/24
sudo ufw deny from 198.20.69.72 to 198.20.69.79
sudo ufw deny from 198.20.69.96 to 198.20.69.103
sudo ufw deny from 198.20.70.111 to 198.20.70.119
sudo ufw deny from 198.20.99.128 to 198.20.99.135
sudo ufw deny from 198.20.87.96 to 198.20.87.103
sudo ufw deny from 176.124.204.0/24
sudo ufw deny from ::/0 to 2602:80d:1000:b0cc:e::/80
sudo ufw deny from ::/0 to 2620:96:e000:b0cc:e::/80
sudo ufw deny from ::/0 to 2602:80d:1003::/112
sudo ufw deny from ::/0 to 2602:80d:1004::/112

# Essential port configuration
sudo ufw allow 443/tcp   # HTTPS
sudo ufw deny 10000/tcp  # Bancho port
# Any port do you want to allow or deny
# Example: sudo ufw allow 25565/tcp (Allow MC TCP)
# Example 2: sudo ufw deny 19132/udp (Deny MC UDP)

# Enable firewall
sudo ufw enable
sudo ufw reload
sudo systemctl enable ufw

Important Notes

  • MySQL/Redis should only listen on 127.0.0.1 (If you are deploy by using docker, nothing need to changes!)
  • For development access (Access MySQL/Redis/etc), use ZeroTier or Tailscale instead of exposing ports
  • Server IPs should disappear from scanners like Censys within 48 hours after these changes

Rate Limiting Implementation

Cloudflare WAF Configuration

  1. Navigate to: Security → WAF → Rate limiting rules
  2. Create new rule with these recommended settings:

image

Recommended Settings:

  • Requests: 150-250 per 10 seconds (lower may cause issues, higher reduces protection) (Up to your frontend and etc)

Command Security

1. Securing the !server Command

Location: app/commands.py

Option A: Restrict Access

# Change from UNRESTRICTED to ADMIN/DEVELOPER
@command(Privileges.ADMIN)
async def server(ctx: Context) -> str | None:
    [existing implementation]

Option B: Add Caching (Recommended)

# Add a global cache for the !server command
_server_cache = {"data": None, "timestamp": 0}

@command(Privileges.UNRESTRICTED)
async def server(ctx: Context) -> str | None:
    """Retrieve performance data about the server."""
    global _server_cache

    # Define cache duration (e.g., 10 seconds)
    CACHE_DURATION = 10

    # Check if the cache is still valid
    current_time = time.time()
    if _server_cache["data"] and current_time - _server_cache["timestamp"] < CACHE_DURATION:
        return _server_cache["data"]

    # If cache is expired or empty, recalculate the server info
    build_str = f"bancho.py v{app.settings.VERSION} ({app.settings.DOMAIN})"

    # get info about this process
    proc = psutil.Process(os.getpid())
    uptime = int(time.time() - proc.create_time())

    # get info about our cpu
    cpu_info = cpuinfo.get_cpu_info()

    # list of all cpus installed with thread count
    thread_count = cpu_info["count"]
    cpu_name = cpu_info["brand_raw"]

    cpu_info_str = f"{thread_count}x {cpu_name}"

    # get system-wide ram usage
    sys_ram = psutil.virtual_memory()

    # output ram usage as `{bancho_used}MB / {sys_used}MB / {sys_total}MB`
    bancho_ram = proc.memory_info()[0]
    ram_values = (bancho_ram, sys_ram.used, sys_ram.total)
    ram_info = " / ".join([f"{v // 1024 ** 2}MB" for v in ram_values])

    # current state of settings
    mirror_search_url = urlparse(app.settings.MIRROR_SEARCH_ENDPOINT).netloc
    mirror_download_url = urlparse(app.settings.MIRROR_DOWNLOAD_ENDPOINT).netloc
    using_osuapi = bool(app.settings.OSU_API_KEY)
    advanced_mode = app.settings.DEVELOPER_MODE
    auto_logging = app.settings.AUTOMATICALLY_REPORT_PROBLEMS

    # package versioning info
    # divide up pkg versions, 3 displayed per line, e.g.
    # aiohttp v3.6.3 | aiomysql v0.0.21 | bcrypt v3.2.0
    # cmyui v1.7.3 | datadog v0.40.1 | geoip2 v4.1.0
    # maniera v1.0.0 | mysql-connector-python v8.0.23 | orjson v3.5.1
    # psutil v5.8.0 | py3rijndael v0.3.3 | uvloop v0.15.2
    requirements = []

    for dist in importlib.metadata.distributions():
        requirements.append(f"{dist.name} v{dist.version}")
    requirements.sort(key=lambda x: x.casefold())

    requirements_info = "\n".join(
        " | ".join(section)
        for section in (requirements[i : i + 3] for i in range(0, len(requirements), 3))
    )

    result = "\n".join(
        (
            f"{build_str} | uptime: {timedelta(seconds=uptime)}",
            f"cpu: {cpu_info_str}",
            f"ram: {ram_info}",
            f"search mirror: {mirror_search_url} | download mirror: {mirror_download_url}",
            f"osu!api connection: {using_osuapi}",
            f"advanced mode: {advanced_mode} | auto logging: {auto_logging}",
            "",
            "requirements",
            requirements_info,
        ),
    )

    # Update the cache
    _server_cache["data"] = result
    _server_cache["timestamp"] = current_time

    return result

2. Securing API Key Generation (Recommended)

@command(Privileges.DEVELOPER)  # Changed from UNRESTRICTED
async def apikey(ctx: Context) -> str | None:
    [existing implementation]

Additional Protection Measures

DDoS Protection Options

  1. Cloudflare Paid Plans (If you are rich):

    • Business/Enterprise plans offer better DDoS protection
    • Enable "Under Attack" mode during attacks
  2. Server Providers (Better plan if you can earn money from this project but how?):

    • OVH: Built-in DDoS protection (Only this thing in my brain)

Monitoring Recommendations

  1. Set up alerts for:

    • High CPU usage
    • Unusual traffic patterns
  2. Recommended tools:

    • fail2ban for SSH protection
    • Datadog for performance monitoring
    • Cloudflare Analytics for traffic insights

Credits:

  • @blueskychan-dev
  • Notmycode Foundation (@notmycode-labs)
  • osu!somtum (@osu-somtum)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment