1. Overview
Nginx is a popular web server that we can also use as a load balancer, forward proxy, or reverse proxy. Reverse proxies are applications that stand between clients and internal servers. They accept network traffic from clients and forward it to the internal network. As a result, clients can’t directly access internal servers. Instead, they can reach them only through the reverse proxy.
In this tutorial, we’ll learn how we can configure Nginx to serve multiple endpoints under the same location. To that end, we’ll use the reverse proxy settings of the Nginx server.
2. Nginx Configuration
Nginx uses configuration files where we can define how the server processes HTTP requests. The main Nginx configuration file is nginx.conf. On Ubuntu systems, we can find it under the /etc/nginx directory. We can enter Nginx directives into this file.
Furthermore, directives can be grouped into blocks. These blocks are called contexts.
2.1. The server Block Directive
The server block defines a virtual server. To set a listening port and a hostname or IP address, we use the listen directive:
server {
listen 127.0.0.1:8080;
}
Here, we created a virtual server that listens on port 8080 on the localhost address (127.0.0.1).
2.2. The location Block Directive
A location block contains configuration for how the server should handle a set of matched HTTP requests. We define a location with either a prefix string or a regular expression. So, Nginx tries to match the URL of an incoming HTTP request to the string prefix or the regular expression of a location block. If there’s a match, it selects this location block to process the HTTP request.
Also, we can use the root directive to set a filesystem directory to serve the content:
server {
listen 127.0.0.1:8080;
location /books {
root /data/categories;
}
}
In the above example, we added a location that returns files from the /data/categories directory of the local filesystem. Moreover, we set the prefix string /books to location. Consequently, we’ll match URLs starting with /books.
Notably, the Nginx root directive appends the whole HTTP request’s URL path to the local directory path. For example, the URL path /books/echo.json will be translated to the /data/categories/books/echo.json path of the local filesystem.
An alternative to the root directive is the alias directive. The alias directive appends the HTTP request’s URL to the local directory path, but omits the string prefix:
location /books {
alias /data/categories;
}
So, the above block translates the URL path /books/echo.json to /data/categories/echo.json.
2.3. Nginx Configuration Reloading
A nice feature of the Nginx server is that we can reload the configuration without restarting the server:
$ sudo nginx -s reload
Here, we use the -s option to send a reload signal to the Nginx server. Thus, we reload the configuration files. So, we can use this option instead of restarting the server, avoiding downtime.
3. Serving Multiple Proxy Endpoints
In this example, first, we’ll create two virtual servers that simulate two endpoints. Then, we configure the Nginx server to proxy requests to the endpoints under the same URL path.
3.1. Creating the Endpoints
Let’s create the two dummy endpoints:
server {
listen 8081;
location /client1 {
alias /data/client1;
}
}
server {
listen 8082;
location /client2 {
alias /data/client2;
}
}
As we can see, we defined two virtual servers. Each server block contains a location:
- the first listens on port 8081, serves content from the /data/client directory, matching requests with the /client1 prefix string
- the second listens on port 8082, serves content from the /data/client2 directory, matching requests with the /client2 prefix string
Now, we can set the forwarding.
3.2. The proxy_pass Directive
To set up forwarding, we insert the proxy_pass directive inside a location block. The proxy_pass directive forwards HTTP requests to a specified network address. The latter can be an IP address or a domain name:
server {
listen 8000;
location /api {
proxy_pass http://127.0.0.1:8081/client1;
}
location /api/client2 {
proxy_pass http://127.0.0.1:8082/client2;
}
}
Here, we created a virtual server that listens on port 8000. Moreover, we created two locations inside the virtual server:
- location /api forwards requests to the first endpoint (http://127.0.0.1:8081/client1)
- location /api/client2 forwards requests to the second endpoint (http://127.0.0.1/8082/client2)
Another key point is how proxy_pass forwards URL paths. There are two cases:
- proxy_pass references a URL with a URL path, like http://127.0.0.1:8081/client1
- proxy_pass references a URL with a hostname a port and no path, like http://127.0.0.1:8081
In the first case, the request URL path is appended to the proxy_pass address without the location prefix string. So, /api/echo.json will be forwarded to http://127.0.0.1:8081/client1/echo.json. In other words, /api is replaced by /client1.
In the second case, the request URL path is appended to the proxy_pass address with the location prefix string:
location /api {
proxy_pass http://127.0.0.1:8081;
}
Here, a request URL path /api/echo.json will be proxied to http://127.0.0.1:8081/api/echo.json.
3.3. Sample Data Creation
Before we test our settings, we should create some test files in the /data/client1 and /data/client2 directories:
$ sudo echo { 'message' : 'Hello from client1' } | sudo tee /data/client1/echo.json
{ message : Hello from client1 }
$ sudo echo { 'message' : 'Hello from client2' } | sudo tee /data/client2/echo.json
{ message : Hello from client2 }
It’s worth noting that we should have sudo rights to create files or sub-directories in the /data directory.
3.4. Testing
Now we’re ready to test:
$ curl http://127.0.0.1:8000/api/echo.json
{ message : Hello from client1 }
$ curl http://127.0.0.1:8000/api/client2/echo.json
{ message : Hello from client2 }
As expected, the requested JSON files were printed to the output. To sum up, let’s look at the processing of the first HTTP request:
- The server forwarded the request URL http://127.0.0.1:8000/api/echo.json to http://127.0.0.1:8081/client1/echo.json
- The server processed the request http://127.0.0.1:8081/client1/echo.json and returned the filesystem resource /data/client1/echo.json
Moreover, the second message had similar processing. In fact, the only difference is that the HTTP request path /api/client2/echo.json is translated to /client2/echo.json.
4. Conclusion
In this article, we learned how we can use the Nginx server as a reverse proxy. Also, we saw an example where we proxied two endpoints under a single location path.