• Servers and Tools

Add an Upstream Application

From the class:  Getting Started with NGINX

You're probably wondering at this point, when are we actually going to serve up our application? So let's get started with that now.

First, I'm going to add a new location for the root path. So anything that is a root path, that starts with the root path, so that's going to be any path in our application, is going to come here unless it starts with the assets path. So what NGINX will do, a quick rule on how it selects these location blocks, is it will choose the longest one that matches. So if we have something that starts with assets, then it'll use this. Anything else, it'll go here first.

Inside of this new location, I'm going to use a new directive called try_files. We needed to tell NGINX that it needs to differentiate between files we want to serve directly from the public folder and paths that we want to send back to our application.

So we can use the try_files directive for that. And what we're going to say is first try a file in the public directory, anything that's here in the root. So try that first. If there's no file that matches the URL, next we're going to send it somewhere else. We're going to send the request to a different location. In this case, I'm going to name that location with an at symbol, and I'm just going to call it at.

Down at the bottom, I'm going to create another location called app. So this is a named location. It's a little bit different than having a path. And in this location, we're going to proxy back to our application that's running on a different port. In order to proxy in NGINX, proxy again just means to send the request to a different server, so we're going to proxy requests back to that server.

We can use the ProxyPass directive. Then give it the protocol that we want to use. In this case, it's HTTP. And then the name of an upstream server which we're going to create a directive for in a second. And I'm just going to call it app.

Now what we need to do is to declare this application somewhere. We can do that up at the top. And I'm going to call it upstream. So the directive that we're going to use is called upstream, and I'm going to call that app. This allows us to declare an area that we can proxy to.

And inside of this block, we can specify all the servers, all the back-end servers, the app servers that we want to proxy to. And the way we do that is we use a directive inside this block called Server. We can have a couple of these. And the Server option is going to be the IP address of the server. So it could be local host or it could be, whatever the IP address is of the Application Server. It could be running on this machine. It could be on a different machine.

In this case, the App Server is running on this machine, so I can go ahead and just say local host. And it's running on port 3,000, so I'm going to give that as the port option here. By the way, a quick introduction to load balancing. If we wanted to have multiple of these servers, I could do that. So I might have a bunch, and they might all have different IP addresses or different ports, like one, two, three, four. And this is how load balancing gets done in NGINX. We're not going to do that in this class, but I wanted to give you a sneak preview of how that actually works.

So now this is going to be a simple upstream app that's listening on local host. And we're going to send requests to it down here in this location block by using the ProxyPass directive. But I want to do one more thing before we leave this file. I want to include some new headers. And the headers will tell the application, our Application Server, a little bit about the request.

Now there's some standard headers that you should include when you do a ProxyPass, and we can just go ahead and include them using the include directive. They're called proxy perams. We're going to take a look at that on the server in a second.

This is going to include a file which is going to inject the content of that file directly into here. So it's just like if we added a bunch of lines manually ourselves. Let's go ahead and Save this file, and then head over to the server.

Change into the Et Cetera NGINX folder, and take a look at the proxy perams file. Notice that it's just a file. And if I open up that file in Vim on the server, it's not going to be a very nice Vim because I haven't configured it nicely, but notice there's just a bunch of lines filled with these directives. And the directives that it's using is called Proxy Set Headers. So it's going to set a header specifically for the proxy.

So our app server is going to see these headers, and these are the header values. Actually these are the Header Keys, and then the value comes after. So it's using the key, the header that it wants to use, and then values are mostly these variables that get provided to us by NGINX automatically. So all of these are going to be brought in to our location block there automatically just by using the Include directive.

I'll Restart or Reload NGINX so that the changes take effect, and now we should be able to curl for our, and we should get our application back. Let's see. Looks to be working correctly. This HTML that gets returned now is the Boom application, not the NGINX standard file or any of the assets in the public directory.

But this time, if I request the robots.txt file, NGINX knows how to differentiate between this and the regular application server because it goes and it looks in the public folder to see whether or not there's a file in there called robots.txt. And if there is one, it'll just serve it up directly. And press Enter, and you see that that happened. So this is also working correctly.

It tries the files. Remember that try_files directive? That's what that's doing. It's going to try this file first. If it finds it, it'll serve it up. If not, it'll send it back, send the request back to our upstream server, which is our application listening on port 3,000.

And the same is true for the assets location. Let's say that we are looking for the bill.css file under the assets path. Again, we get back the proper content here because it knows to treat this path specially because there's a location block that says if the path starts with assets, treat it specially. Go into the public folder and return the files, but also add these special headers.

Now let me show you a special case. Now I'm requesting the path app.js, and that file does not exist in the public folder. There's no static file called app.js. But if you recall from our application, there is a route to handle this app.js path.

In case you forgot, let's go ahead and take a look at it. Let's switch over to the other tab here. Notice inside the app folder, there is an app.js file. And if you look at the server, here's our little janky router here. There's just a switch statement that says, if you request app.js, go ahead and read the app.js file and send it back to the client.

So now in this case NGINX is first going to go and see, does this file exist in the public folder? If not, then proxy back the request to our app. And then our app, the router in our application, actually handles this route, finds the app.js file, loads it up, and sends it back in the response. And here it is.