In Part I of this tutorial, we created a self-contained ASP.NET Core web application using the new dotnet CLI tools, configured PuTTY and PSCP to SSH and transfer files, and then finally transfer the self-contained app from a Windows environment to the Ubuntu VM. Part II discussed setting up Docker, creating a Docker Image, and running your application from a Docker container.
Now, to properly secure our application we shall issue a self-signed certificate using Windows Powershell and configure Nginx to use that certificate to do SSL Termination. SSL Termination is a simple concept, the client connection to the Nginx load balancer is over HTTPS, and the Nginx load balancer retrieves the data from a private network over HTTP. Load balancing is when you distribute the web requests among many servers to improve performance. The following diagram illustrates Nginx SSL Termination:
Let’s install and configure Nginx to do SSL Termination!
Step 1: Create an entry in your host file and Install Nginx
Add an entry in your host file to make life easier.
cd /etc/
sudo nano hosts
Add the following to the bottom (replace with your Ubuntu host IP!)
192.168.xxx.xxx MyNetCoreApp
Install Nginx
sudo apt-get update
sudo apt-get install nginx
Adjust Nginx firewall settings
View firewall registered applications:
sudo ufw app list
Register Nginx as a firewall app if it is not displayed
sudo ufw allow ‘Nginx Full’
Check the status of the Web Server
systemctl status nginx
Step 2: Create and export a self-signed SSL certificate
Before creating the certificate, let’s create a temporary folder to hold the SSL files.
mkdir ~/temp-ssl/
Now launch powershell with administrative priveledges on your Windows machine.
Enter the following command:
New-SelfSigned-Certificate -DnsName <AD FS Machine IP> -CertStoreLocation Cert:LocalMachinemy -FriendlyName “UbuntuCert”
Export the .pfx certificate via running mmc.exe.
- File -> Add or Remove Snap-ins
- Select “Certificates” and hit “Add >”
- Select the “Computer Account” radio button and hit “Next”
- Select “Local Computer” and hit “Finish”
- Browse to the Personal -> Certificates directory, locate the Machine IP named certificate
- Right click -> All Tasks… -> Export. IMPORTANT: Select “Yes, export the private key”
- Add a password in the security window and hit next
Use PSCP to copy the certificate from your windows machine to your Ubuntu temp-ssl folder
pscp C:<path to cert><cert>.pfx <username>@192.168.xxx.xxx:/home/<username>/temp-ssl
Step 3: Use OpenSSL to extract the public and private key
Install OpenSSL on your Ubuntu Machine
sudo apt-get install openssl
Extract the public key
openssl pkcs12 -in [yourfile.pfx] -clcerts -nokeys -out [cert.crt]
Extract the private key
openssl pkcs12 -in [yourfile.pfx] -nocerts -out [keyfile-encrypted.key]
Get rid of the password protection on the private key
openssl rsa -in [keyfile.key] -out [keyfile-decrypted.key]
Create the folder to hold the SSL certs: /etc/nginx/ssl
sudo mkdir /etc/nginx ssl
Copy the decrypted private key as well as the public key to /etc/nginx/ssl
sudo cp ~/temp-ssl/<filename> /etc/nginx/ssl
Now that we have a public and private key ready, we may configure Nginx for SSL Termination!
Step 4: Create a server block to configure SSL Termination
Nginx server blocks are the equivalent to virtual hosts in Apache. They contain configuration details and enable us to do things such as host more than one domain off a single server, do load balancing, as well as redirect HTTP to HTTPS traffic (enable SSL).
Let’s create the server block
cd /etc/nginx/sites-available
sudo nano myTestServer
Begin inputting the contents of the server block as follows
http { upstream http-backend { server MyNetCoreApp:8081 } server { listen MyNetCoreApp:80; return 301 https://$host:443$request_uri; } server { listen MyNetCoreApp:443 ssl http2; root /etc/netcore/mySecureApp/; server_name MyNetCoreApp; ssl on; ssl_certificate /etc/nginx/ssl/cert.crt ssl_certificate_key /etc/nginx/ssl/keyfile-decrypted.key location / { try_files $uri $uri/ =404; 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_pass http://http-backend; proxy_read_timeout 90; } } }
Let’s review the contents of the server block
Load balancing
upstream http-backend { server MyNetCoreApp:8080 }
Here, we may add several other servers if we wish to achieve load balancing. This block is what the nginx web server will serve content from with a label “http-backend” that will always select he most available resource host. Port 8080 shall be mapped to 5001 (HTTPS). You may also map 8080 to 443, but then all the traffic between the Nginx load balancer and private networks becomes secured, resulting in wasted performance and improper SSL Termination. Again, the following diagram illustrates the goal of SSL Termination; use a load balancer to handle HTTPS traffic from the client while accessing content over HTTP from the most available resource in the private network.
HTTP redirect to HTTPS Server block
server { listen MyNetCoreApp:80; return 301 https://$host:443$request_uri; }
This server block listens to all connections on the default HTTP port 80 and 301 redirect them to an HTTPS connection over port 443. The $host
and the $request_uri
variables are obtained from the header values.
Main server block for serving content
server { listen MyNetCoreApp:443 ssl http2; root /etc/netcore/mySecureApp/; server_name MyNetCoreApp; ssl on; ssl_certificate /etc/nginx/ssl/cert.crt ssl_certificate_key /etc/nginx/ssl/keyfile-decrypted.key location / { try_files $uri $uri/ =404; 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_pass http://http-backend; proxy_read_timeout 90; }
This server block listens to all connections over the 443 HTTPS port on MyNetCoreApp (which we added in our host file)
The root for my content is specified as /etc/netcore/mySecureApp/
The server_name is specified as MyNetCoreApp
The ssl_certificate and ssl_certificate_key are the locations of the ssl certificates that we moved earlier.
The location block here provides a 404 error if the file is not found, sets the$host
, $remote_addr
, and forwarding data in the header. The proxy_pass is important as it tells nginx to load the data from the load balancer into an http:// connection, this should ring a bell, the SSL Termination is over HTTP when accessing files from the network.
Now that we’ve configured SSL Termination, let’s reload the nginx service.
sudo services nginx reload
To enable the website, create a link in /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/myTestServer /etc/nginx/sites-enabled
If you desire to disable a website, you can simply remove the link in sites-enabled.
Step 5: Build and run the Docker container!
Navigate to the self-contained app directory
cd /etc/netcore/mySecureApp
Build the docker image
sudo docker build -t mydemos: HelloWorld .
Note: -t adds a tag (mydemos:…) and the trailing period tells docker to look in the current directory for the Dockerfile to build from.
Run the docker image
sudo docker run -p 8080:5001 -t mydemos:mySecureApp
Note: -p specifies what port on the local machine we wish to map onto the container. Port 8080 will be mapped to 5001 because our nginx load balancer is expecting to serve content from 8080, and we wish to load the content over HTTP.
Now you have a working, secure, dockerized ASP.NET Core HelloWorld web application hosted on Ubuntu with Nginx SSL Termination.
It’s important to note that this blog is being posted in the pre-release days of ASP.NET Core, and many of these things are subject to change or break as Microsoft finishes revising ASP.NET Core for its final release. I will make it my duty to update this, but if I fall behind feel free to leave a comment or reach me at my LinkdIn posted above.