Rate Limiting a Public VPS Application Without Blocking Normal Users
Different endpoints need different limits. Protect expensive actions while accounting for shared addresses, retries, and real user behavior.
Rate limiting controls how quickly callers can consume an application's resources. A single global number is rarely a good fit for every endpoint. Loading cached articles, submitting passwords, running searches, and exporting reports have different costs and failure consequences. Start with the action you want to protect and observe legitimate demand before turning that understanding into an enforced policy.
Choose the resource and identity being limited
Decide whether a limit applies per account, API key, source address, or another trustworthy identity. Unauthenticated endpoints may need address-based controls, but many users can share one address behind a workplace or mobile network. Authenticated account limits can be more precise, yet they still need protections against abusive requests made before authentication completes.
Do not derive the source address from arbitrary caller-supplied forwarding headers. If the application sits behind a proxy, establish the trusted client-address handling first. Otherwise a caller may evade a limit by changing a header, or every visitor may appear to be the proxy and share one unintended bucket.
Separate sustained rates from short bursts
A real page load can generate several requests nearly at once. A deployment agent may also make a brief batch of valid API calls. Decide what sustained demand is acceptable and what short burst the service can tolerate. Use the limiter's documented algorithm and units rather than translating a desired policy into guessed configuration values.
For example, an expensive report endpoint may permit only a small number of concurrent or repeated jobs per account while static assets remain broadly cacheable. That policy protects the resource that actually causes pressure. Applying the report's strict limit to every image request would create a poor browsing experience without addressing the important distinction.
Make rejection understandable to clients
Return the documented HTTP status for the limit and a safe explanation of when a caller can retry. Where appropriate, provide Retry-After guidance. API clients should back off rather than retry immediately in a tight loop. Avoid responses that expose whether an unknown account exists when limiting sign-in or recovery operations.
Test how the front end handles a rejected request. A spinner that never stops can turn a protective control into an apparent outage. Keep queued work and accepted work distinct so the client does not create duplicates while trying to recover from a rate-limited response.
Observe, tune, and retain other controls
Use staging or a supported observation mode to compare the proposed policy with normal traffic. Include shared-network users, legitimate bursts, and an intentionally excessive test within your own environment. Monitor rejection counts and endpoint cost after enforcement. Rate limiting does not replace authorization, safe input handling, or capacity planning, and a request-level control cannot guarantee protection from every network-level attack.
The nginx request-limiting module documents one implementation. See our client API guide for API context and LayerOne pricing when evaluating the application's underlying resource needs.