Nginx Reverse Proxy to ASP.NET Core – Same Container

February 24, 2017
SEP hex pattern overlay of person working on laptop

As mentioned in the previous post, it is recommended to use something other than Kestrel as the front-line web server. In this example, I’m going to show how to use Nginx as a reverse proxy to the ASP.NET Core application.

Reverse-proxy architecture options

In terms of architecture setup for reverse proxying for ASP.NET Core in Docker there are a couple of options.

The first option is to run Nginx within the same container as the ASP.NET Core application. This is the option shown in this post.

The other option is to run Nginx as a separate Docker container. In that setup, the communication would be proxied over a network bridge between the Nginx container and the containers hosting the application. This second approach will be shown in the next post.

Creating the application

Again for this example, I’ll just be using the default web application generated by the .NET Core CLI.

To create that application, run the following commands:

mkdir app
cd app
dotnet new -t web
dotnet restore
dotnet build

And the publish the application (to package it up for the Docker container):

dotnet publish

Building the image

The Docker image will be based on the microsoft/aspnetcore:1.0 image used previously. It will be modified to include Nginx. That will allow Nginx to use a fairly standard reverse proxy configuration while also running the Kestrel process.

Dockerfile configuration

Create a Dockerfile and include the following contents:

FROM microsoft/aspnetcore:1.0
RUN apt-get update
RUN apt-get install -y nginx
COPY bin/Debug/netcoreapp1.0/publish .
COPY ./ .
RUN chmod 755 /app/
RUN rm /etc/nginx/nginx.conf
COPY nginx.conf /etc/nginx
EXPOSE 5000 80
CMD ["sh", "/app/"]

Let’s deconstruct what’s going on there…

Line 1 specifies that the image will use the same microsoft/aspnetcore:1.0 base as previous examples.

Lines 3-4 install the nginx package (and all of its dependencies) from the Debian package management store.

Lines 6-7 setup the /app directory and place the ASP.NET Core application within that directory.

Lines 9-10 setup a start-up script (explained in greater detail below).

Lines 12-13 replace the out-of-the-box Nginx configuration file with a custom configuration.

Line 15 configures Kestrel to listen to port 5000.

Line 16 exposes port 80 to the outside world.

Line 18 invokes the start-up script that we’ll define shortly.

Nginx configuration

Now we need to create the nginx.conf file referenced in the Dockerfile. In the same directory, create nginx.conf and place the following contents into it:

worker_processes 4;
events {
    worker_connections 1024;
http {
    sendfile on;
    upstream app_servers {
    server {
        listen 80;
        location / {
            proxy_pass http://app_servers;
            proxy_redirect off;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Host $server_name;

Once again, let’s deconstruct a few parts of the file.

Lines 8-10 define a group of servers (in this case one). This named resource (app_servers) can be used elsewhere in the file for proxying.

Line 13 tells Nginx to listen on port 80.

Lines 15-22 indicate that all traffic should be proxied to app_servers.

In summary, this file configures Nginx to listen on port 80 and then redirect all traffic to port 5000 on the same box. Given the ASPNETCORE_URLS variable specified in the Dockerfile, this means that the traffic will be proxied from Nginx to Kestrel.

Start-up script

There can only be a single CMD used (or ENTRYPOINT defined) for a Docker container. But this reverse proxy configuration needs both to start Nginx and Kestrel. To do this, we’ll use a shell script to perform both tasks.

Create a file in the same directory with the following contents:

#!/bin/bashservice nginx startdotnet /app/app.dll

Building the image

Build the image with the following command:

docker build -t example/aspnetcore-nginx .

As you watch the output, you’ll see that Nginx is being installed:

Step 3/7 : RUN apt-get install -y nginx
---> Running in ca67ca6606e8
Reading package lists...
Building dependency tree...
Reading state information...
The following extra packages will be installed: fontconfig-config fonts-dejavu-core geoip-database init-system-helpers libalgorithm-c3-perl libarchive-extract-perl libcgi-fast-perl libcgi-pm-perl

Running the image

To test the image, run an instance of it:

docker run --name test -d -p 8080:80 example/aspnetcore-nginx

You should now be able to reach the application at http://localhost:8080.

You can verify that it’s running the Nginx service through curl:

$ curl -s -D - localhost:8080 -o /dev/null
HTTP/1.1 200 OK
Server: nginx/1.6.2
Date: Fri, 24 Feb 2017 14:39:51 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding

If you open a shell on the box itself, you can look at both the Nginx and Kestrel services individually.

docker exec -it test bash
# curl -s -D - localhost:80 -o /dev/null
HTTP/1.1 200 OK
Server: nginx/1.6.2
Date: Fri, 24 Feb 2017 14:45:03 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
# curl -s -D - localhost:5000 -o /dev/null
HTTP/1.1 200 OK
Date: Fri, 24 Feb 2017 14:45:53 GMT
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8
Server: Kestrel

Other options?

As I mentioned above, there are two main ways to setup a reverse proxy architecture for ASP.NET Core applications. In the next post, I’ll show the alternate setup that keeps Nginx and ASP.NET Core in separate Docker containers.

Build awesome things for fun.

Check out our current openings for your chance to make awesome things with creative, curious people.

Explore SEP Careers »

You Might Also Like