PHP Rate Limiting Using Redis featured image

Implementing PHP Rate Limiting Using Redis on Ubuntu 20.04: A Tutorial

Redis, also called Remote Dictionary Server, is an open-sourced in-memory database. It is a data-structured storage system that runs on a server’s RAM, which is much quicker than the fastest Solid State Drive (SSD). As a result, Redis is very responsive and an excellent fit for rate limiting.

Rate limiting restricts the number of times a user may request a resource from a server. Many services use rate limits to stop service abuse, like when a user tries to overrun a server with too much load. For example, when using PHP to develop a public API (Application Programming Interface) for your web application, rate restrictions are required. That’s because when you expose an API to the public, you’ll want to limit how many times an individual may repeat an activity in a certain amount of time. Users that have no authority over your system may put it to a standstill.

Rate limiting allows your application to function smoothly by rejecting user requests that exceed a set limit. If you have a large number of clients, rate limitation imposes a fair-use policy that permits each user to access your application at fast speeds. Rate limiting may also help you save money on bandwidth by lowering congestion on your server.

By tracking user activity in a database like MySQL, it would be possible to create a rate-limiting program. However, since such data should be downloaded from disk and evaluated against the defined limit, the final result may not be scalable when multiple people contact the system. Not only is this inefficient, but relational database management solutions were not built for this.

Redis is a good choice for making a rate limiter because it works as an in-memory database and has been proven to be reliable for this. In this tutorial, we’ll walk you through the steps of implementing PHP rate limiting using Redis on Ubuntu 20.04.

Let’s start!

Prerequisites

To follow along with this tutorial, you’ll need the following:

Step 1: Install Redis Extension for PHP

Before we begin, let’s update the repositories to avoid package conflicts:

Next, install the php-redis extension, a package that makes it possible to use Redis in PHP programs. Run the following sudo command to install php-redis:

After that, restart the Apache server to load the php-redis library:

The next step is to update the information in your software index and install the Redis library for PHP. Then, we’ll create a PHP resource that restricts access based on a user’s IP address.

Step 2: Create a PHP Web Resource for Rate Limiting

In this step, you’ll create a demo.php file in your web server’s root directory ( /var/www/html/). This file will be open to the public, and users will be able to launch the URL in their preferred web browser. Later, we’ll be using the curl command to verify the accessibility of the resource we want to use. Users can access the sample resource file three times in a 15-second span. An attempt exceeding the maximum limit will throw an error message.

This file’s primary functionality is strongly dependent on the Redis server. The PHP code in the file creates a key on the Redis server depending on the user’s IP address when the user accesses the resource for the first time. The code will attempt to match the user’s IP address with the keys saved in the Redis server and increase the value by one if the key exists when the user returns to the resource. The PHP code will keep checking to see if the new value has reached the maximum amount.

After 15 seconds, the Redis key, which is based on the user’s IP address, will expire, and tracking the user’s visits to the web resource will begin again. Open the /var/www/html/demo.php file in the nano text editor:

Then, fill out all the fields to initialise the Redis class. Don’t forget to set the REDIS_PASSWORD to the correct value:

Redis->auth supports Redis server plain text authentication. This works well if you’re working locally (through localhost), but if you’re dealing with a distant Redis server, SSL authentication is recommended.

Next, in the same file, set the following variables to their default values:

Let’s understand these statements in detail:

  • $max_calls_limit: A user cannot access the resource to this maximum call limit.

  • $time_period: This is used as a time frame and is counted in seconds. Here, the user is permitted to access the resource as per the limits set in the $max_calls_limit .

  • $total_user_calls: Sums up the number of times a user has requested access to the calls limit in a given time period.

Then, add the following code to get the IP address of the requested asking to access the web page:

As a demonstration, this code logs users’ actions by their IP addresses. If you have a protected resource on the server that needs authentication, you can track users’ actions using their usernames or access tokens.

In our guide, each user that logs into your system will be assigned a unique identification (for example, a customer ID, developer ID, vendor ID, or even a user ID). Remember to use these IDs instead of the $user_ip address if you are following along with our tutorial.

Here, the user’s IP address is sufficient to demonstrate the notion. Add the following code block to your file once you have the user’s IP address from the preceding code snippet:

Here is an overview of these statements:

  • if...else: The statement verifies whether there is a key defined with the IP address on the Redis server.

    • If the key is not found, if (!$redis->exists($user_ip_address)) {...}, you can set the key and define its value to 1 using $redis->set($user_ip_address, 1).

  • $redis->expire($user_ip_address, $time_period): Reminds the key to expire at a specified time. Here in this tutorial, we have set it to 15 seconds.

  • If the user’s IP address is not found in the Redis key, set the variable $total_user_calls value as 1.

  • else {...}: The statement block uses the $redis->INCR($user_ip_address); command to step up the value of the Redis key by 1. This will be applied to each IP address aligned with the key.

    • Note: You can achieve this only when the key is already set in the Redis server and counted as a repetitive request.

  • $total_user_calls = $redis->get($user_ip_address): This statement retrieves the total requests by verifying their respective IP address-based key on the Redis server.

  • if ($total_user_calls > $max_calls_limit) {... }..: This if statement is used to verify the exceeded limit. If yes, you notify the user with echo "User" . $user_ip_address . " limit exceeded.";.

Finally, you’re notifying the user about their number of visits in a specified period using the echo "Welcome" . $user_ip_address . "total calls made" . $total_user_calls . "in" . $time_period . "seconds"; statement.

After that, add the following lines of code in your /var/www/html/demo.php file:

Save and close the /var/www/html/demo.php file after you’ve done modifying it. On the demo.php web page, you’ve now created the logic required to rate limit users. Let’s test our script in the following step.

Step 3: Run the Redis Rate Limiting Test

You’ll use the curl command in this step to request the web resource that you wrote in Step 2. To thoroughly test the script, issue a single command that requests the resource five times. This may be accomplished by adding a placeholder URL argument to the demo.php file’s end. To perform the curl instructions five times, use the value ?[1-5] at the end of your request.

Execute the following curl command below:

When you execute the code, you should get something like this:

The first three requests, as you can see, went off without a hitch. The fourth and fifth queries, however, were rate-capped by your script. There is a good chance the Redis server is slowing down the speed at which people can make queries.

You have specified low values for the two variables listed below in this guide:

When you make your app in a production setting, you might want to think about using bigger numbers, depending on how often you think people will use it.

It’s a good idea to examine real-time statistics before adjusting these numbers. In this example, if your server logs show that an average user visits your application 1,000 times every 60 seconds, you can use that number as an example of how much throttling to use.

Conclusion

In this guide, you learned how to utilize a Redis server with PHP on Ubuntu 20.04. While this post demonstrates how rate limiting works with Redis, you may customize it to meet the demands of your web application. We encourage you to explore real-world examples like Twitter’s maximum request limit, Google’s Custom Search JSON API, and other similar documentation to enhance your knowledge on rate limiting and try experimenting yourself using different time limits.

Furthermore, there are many other learning materials on Redis and PHP that you can access from our blogs:

Happy Computing!