Skip to content

Rate Limiting

Runway provides rate limiting capabilities through Cloudflare to protect your workloads from abuse and control traffic flow. Rate limits are applied at the Cloudflare edge, before traffic reaches your origin servers.

Ensure Cloudflare is enabled in your workload configuration:

default-values.yaml
spec:
load_balancing:
cloudflare:
enabled: true # Must be true for rate limiting to work

Limit requests based on configurable characteristics:

  • Default: 100 requests per 60 seconds
  • Characteristics: The set of parameters that define how Cloudflare tracks the rate for this rule. Each unique combination of these values gets its own separate rate limit counter:
    • Colocation ID (cf.colo.id): Cloudflare data center location where the request was processed
    • Source IP (ip.src): The originating IP address of the request
    • Host name (http.host): The Host header from the original request
    • User identification headers: Default is x-gitlab-global-user-id, but can be customized using the characteristics.headers configuration
  • Configurable per route: Define different limits for each path

Configuration:

Configure rate limiting by updating your workload configuration in provisioner’s config/runtimes/[eks|gke]/workloads.yml as follows:

workloads.yml
cloudflare:
rate_limits:
user:
- path: "/api/v1"
requests_per_period: 1000 # number of requests allowed per period
period: 60 # time window in seconds
characteristics: # optional: customize tracking
headers:
- x-gitlab-global-user-id
- x-custom-user-header

Unmatched Request Handling:

By default, requests to paths not covered by your rate limit rules are allowed through. You can change this behavior using allow_only_rate_limited_paths:

workloads.yml
cloudflare:
rate_limits:
user:
- path: "/api/v1"
requests_per_period: 1000
period: 60
allow_only_rate_limited_paths: true # enable 404 responses

When allow_only_rate_limited_paths: true, requests to paths not in your user rate limit configuration will receive a 404 response.

Rate Limiting All Requests:

To rate limit all requests, use path: "/". This will apply rate limiting to every request and will ignore the allow_only_rate_limited_paths setting:

workloads.yml
cloudflare:
rate_limits:
user:
- path: "/"
requests_per_period: 1000
period: 60

Protect against brute-force attacks by limiting failed authentication attempts:

  • Default: 50 requests per 300 seconds with 300 seconds ban time
  • Triggered on: HTTP 401 responses
  • Characteristics: The set of parameters that define how Cloudflare tracks the rate for this rule. Each unique combination of these values gets its own separate rate limit counter:
    • Colocation ID (cf.colo.id): Cloudflare data center location where the request was processed
    • Source IP (ip.src): The originating IP address of the request
    • Host name (http.host): The Host header from the original request
    • Authorization header: Default is authorization, but can be customized using the characteristics.headers configuration
  • Applies to: All paths on the zone

Configuration:

workloads.yml
cloudflare:
rate_limits:
auth_failure:
requests_per_period: 50 # number of requests allowed per period
period: 300 # time window in seconds
mitigation_timeout: 300 # ban duration in seconds
characteristics: # optional: customize tracking
headers:
- authorization

Serve appropriate error responses for unmatched requests:

  • Return 404s for paths that are not rate limited
  • Applies when allow_only_rate_limited_paths: true

Here’s a complete workload configuration in config/runtimes/[eks|gke]/workloads.yml:

workloads.yml
- runway_service_id: my-service
project_id: 12345678
cloudflare:
enabled: true
rate_limits:
user:
- path: "/api/v1"
requests_per_period: 1000
period: 60
characteristics: # optional: customize tracking headers
headers:
- x-gitlab-global-user-id
- x-custom-user-header
- path: "/api/v2"
requests_per_period: 600
period: 60
auth_failure:
requests_per_period: 50
period: 300
mitigation_timeout: 300
characteristics: # optional: customize tracking headers
headers:
- authorization
allow_only_rate_limited_paths: true

The characteristics.headers configuration allows you to customize which headers are used for rate limit tracking. If not specified, default headers are used (x-gitlab-global-user-id for user rate limits, authorization for auth failure rate limits).

TypePeriodRequestsMitigation TimeoutCharacteristics
User60s1000scf.colo.id, http.host, ip.src, x-gitlab-global-user-id
Auth Failure300s50300scf.colo.id, http.host, ip.src, authorization

Rate limit rules are automatically configured to match host names of staging and production environments:

  • Production: <runway-service-id>.svc.gitlab.net
  • Staging: staging.<runway-service-id>.svc.gitlab.net

Rate limit violations are logged in Cloudflare analytics. Check:

  1. Cloudflare dashboard for your zone
  2. Query Rate limit rule metrics (Mimir - Runway) - Coming Soon!

Issue: Legitimate traffic is being rate limited

  • Increase requests_per_period for the affected path
  • Adjust period to a longer time window
  • Review characteristics to ensure proper user identification

Issue: Auth failures not being limited

  • Verify auth_failure configuration is present
  • Check that your service returns 401 responses correctly
  • Confirm mitigation_timeout is set appropriately

For questions or issues with rate limiting, contact the Runway team in #f_runway