Skip to main content

On This Page

How I Cut My Cloud Run Bill by 96% by Stopping a Polish Botnet

2 min read
Share

These articles are AI-generated summaries. Please check the original sources for full details.

The Painful Statistics

A developer deployed a “Knowledge Graph CV” app on Cloud Run, intended as a small demo, but quickly faced unexpectedly high costs due to a botnet exploiting persistent WebSocket connections, reaching a peak of €42/month. Standard serverless architectures are vulnerable to abuse via long-lived connections, resulting in significant, and often unforeseen, costs.

Key Insights

  • Streamlit WebSockets: Streamlit’s reliance on persistent WebSocket connections makes applications susceptible to abuse, as bots can maintain open connections and accrue costs.
  • Caddy Reverse Proxy: Utilizing Caddy as a reverse proxy before the application allows for blocking malicious traffic before it reaches the Python code, preventing unnecessary billing.
  • IPv6 Blacklisting Challenges: The proliferation of IPv6 addresses makes traditional IP-based blacklisting less effective, necessitating more sophisticated approaches.

Working Example

{
admin off
auto_https off
servers {
trusted_proxies static 169.254.0.0/16
}
}
:8080 {
# Grouped matcher for all banned IPs
@denylist {
header X-Forwarded-For *185.136.92.*
header X-Forwarded-For *115.98.235.*
header X-Forwarded-For *119.111.248.*
header X-Forwarded-For *115.96.83.*
header X-Forwarded-For *2601:600:cb80:*
header X-Forwarded-For *57.151.128.*
header X-Forwarded-For *2402:3a80:*
}
# Respond 403 to any of these matches
handle @denylist {
respond "Access Denied" 403
}
# Everything else goes to Streamlit
handle {
reverse_proxy localhost:8501 {
header_up X-Real-IP {http.request.header.X-Forwarded-For}
header_up X-Forwarded-For {http.request.header.X-Forwarded-For}
}
}
log {
output stdout
format console
}
}
FROM python:3.11-slim
WORKDIR /app
# Install Caddy (single binary, 15MB)
ADD https://caddyserver.com/api/download?os=linux&arch=amd64 /usr/bin/caddy
RUN chmod +x /usr/bin/caddy
# Install Python dependencies
COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv
COPY pyproject.toml .
COPY . .
RUN uv pip install --system -e .
# Config & startup
COPY Caddyfile start.sh ./
RUN chmod +x start.sh
EXPOSE 8080
CMD ["./start.sh"]
#!/bin/bash
# Launch Streamlit in background (internal only)
streamlit run app.py --server.port=8501 --server.address=127.0.0.1 &
# Launch Caddy in foreground (public-facing)
caddy run --config /app/Caddyfile

Practical Applications

  • E-commerce Platform: Protecting API endpoints with a reverse proxy to mitigate DDoS attacks and bot traffic, ensuring service availability for legitimate users.
  • Pitfall: Relying solely on application-level rate limiting without a reverse proxy can still result in substantial costs if bots maintain persistent connections before rate limits are applied.

References:

Continue reading

Next article

How to Set Content-Length Header in ResponseEntity in Spring MVC

Related Content