A Story of .Net Core and Docker with HTTPS
So this one stumped me a bit. I have my app in a built in .net core running in a docker container and was trying to get the reverse proxy to talk to the container over HTTPS.
So in this post I'll walk through a few steps I've used to take an SSL cert and use it in the reverse proxy to secure the connection and then use the docker container over HTTPS.
What I'll cover in this post.
- Using Lets encrypt for SSL Cert
- Updating the NGINX Proxy to use the SSL cert
- .NET Core and Docker running on the SSL Port
Installing SSL Certs
Lets Encrypt is an SSL Certificate Authority, it's free and automated. I'm not going to go into super detail on installing Lets Encrypt or adding certs to your system.
This is a good step by step from Linode on installing lets encrypt and setting up the certificates.
NGINX Reverse Proxy
I've covered using a reverse proxy in NGINX before here
Our proxy file will look something like this
server {
listen 80;
listen [::]:80;
server_name demoweb.app www.demoweb.app;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name demoweb.app www.demoweb.app;
set $upstream 127.0.0.1:8199;
access_log /var/log/nginx/demoweb_access.log;
error_log /var/log/nginx/demoweb_error.log;
ssl_certificate /etc/letsencrypt/live/demoweb.app/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/demoweb.app/privkey.pem;
location /.well-known {
root /var/www/demoweb.app/;
}
location / {
proxy_pass_header Authorization;
proxy_pass https://$upstream;
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_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering off;
client_max_body_size 0;
proxy_read_timeout 36000s;
proxy_redirect off;
}
}
So there is a bit there lets break it down.
HTTPS Redirect
First bit we have is to set a HTTPS redirect on our reverse proxy
server {
listen 80;
listen [::]:80;
server_name demoweb.app www.demoweb.app;
return 301 https://$server_name$request_uri;
}
What the above code is doing is telling our NGINX server to listen for port 80 traffic. Everything on port 80 is HTTP. So this code tells NGINX to create a 301 redirect for that traffic to the https:// version of the domain name.
HTTPS Listening
For NGINX to listen on HTTPS we use the following code.
listen 443 ssl;
listen [::]:443 ssl;
This tells NGINX to listen on the HTTPS port and that SSL is expected.
SSL Cert Keys
The next bit we're interested in is
ssl_certificate /etc/letsencrypt/live/demoweb.app/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/demoweb.app/privkey.pem;
This will tell NGINX where it can find the SSL cert information the keys it needs.
HTTPS well known
HTTPS validation needs a .well-known folder available for your web site. This is used when the SSL cert is installed to control and configure some information to validate the certificates.
location /.well-known {
root /var/www/demoweb.app/;
}
Proxy Pass
Because we're using a reverse proxy we are sending the traffic upstream in this examples case the IP for up stream is itself and a port that will be our docker container.
But we make one change here we use https to send on the traffic which means we're expecting our docker container to be listening on a HTTPS Port.
proxy_pass https://$upstream;
.NET Core HTTPS
So this is the bit that is interesting. .NET Core has the ability to allow me to override the listening port and set it to only listen for HTTPS traffic. This means I don't have to mess around inside of a docker container too much.
We do this in our Program.cs class. This is valid in .NET Core 2.1 (I'll dig into .NET Core 2.2 and 3 later and make posts for them)
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseKestrel(options =>
options.Listen(IPAddress.Any, 8050, listenOptions =>
listenOptions.UseHttps("demowebapp.pfx", "XXXX")))
.UseStartup<Startup>()
.Build();
}
Ok so the above code is what our program.cs will look like, the part we are looking for is the .UseKestrel code. Kestrel is a part of .net core and it allows it to run without IIS and more importantly for us inside docker containers. Lets take a look at the code here.
.UseKestrel(options =>
options.Listen(IPAddress.Any, 8050, listenOptions =>
listenOptions.UseHttps("demowebapp.pfx", "XXXX")))
What this code is doing is telling Kestrel to listen on any IP address available. On port 8050 and it should listen for HTTPS traffic only.
The next bit ".UseHttps("demowebapp.pfx", "XXXX")" we are passing it a PFX certificate this is an SSL cert. I'm not going to go into creating a pfx cert for this post but I will in the future as it should be a post of it's own.
The Docker bit
In our docker file we need to set
EXPOSE 8050
This will set the docker container to be listening on the same port as our .net core application.
That's it, the above post gives an outline of how to use SSL in a reverse proxy to a .net Core application in docker.
Check out my post on HTTPS - Lets talk about HTTPS
I'll be following this up with a couple more posts.
- Creating the pfx cert we use in the .net core file.
- Using SSL in .NET Core 2.2 and 3.0.
- Cloudflare and how it works in this scenario.