loading...

Configuring SSL On An Asp.Net Core Docker Container

herocod3r profile image Jethro Daniel ・4 min read

docker nginx

Asp.Net Core is a great platform to develop applications with. With one of the best runtimes, and a powerful language like C# backing it....and yea the cross-platformness of .Net Core it would only make sense to use it.

So after building that next Billion-Dollar Idea, what next??...It would naturally be to put it up for us to use...well since .Net Core can run anywhere you would have quite a number of options to host your applications. But if you are reading this, chances is you are like me, you want to containerise your app with all the dependencies, Database or even if it is a mirco-services you are deploying. Docker would be a good choice. After getting your VPS, and doing all the necessary docker configurations, you have been able to host that app.But yet in a world where security is everything, you are thinking of throwing in an ssl support to better your odds.

Well then, it is said Talk Is Cheap Show Me The Code lol...lets get started then Asp.Net core by default comes with a default light-weight web-server you can use for asp.net core apps. You can read more about kestrel Here.

While Kestrel is cool, and gets the job done most of the time, it is not adequate enough in production environments, click Here to know more

The solution:

Reverse Proxy!!, we can also host an asp.net core application with a more matured webserver like Nginx...well, not exactly host...more like use the nginx for evrything and mirror the request to the main kestrel, this would allow us configure ssl and enjoy all the awesomeness with Nginx. You can read more about it Here

Configuring The SSL

Well, back to the topic... we would make use of docker, certbot/letsencrypt.

Step 1

SSH into your vm, then run the following commands to install certbot

$ sudo apt-get update
$ sudo apt-get install software-properties-common
$ sudo add-apt-repository universe
$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt-get update
$ sudo apt-get install certbot python-certbot-nginx 

Then run the following and follow the prompt to install letsencrypt certificate for your domain

$ sudo certbot --nginx certonly

Make sure you note down the path to where certificate is stored, we would use this later.

Step 2

Prepare your docker image for the web application

FROM microsoft/dotnet:2.1-aspnetcore-runtime
WORKDIR /app
ENV ASPNETCORE_URLS http://+:5000
EXPOSE 5000
COPY . .
ENTRYPOINT ["dotnet", "ExampleApp.dll"]

The key thing here is exposing port 5000, this is the port with which nginx would route requests to.

Then push the image to a private docker registry. You can get a free one from Treescale

Oh, also please forgive me for this method, i prefer to build the app locally and just push the image to a registry, it allows for much lighter file size. And there is no need to copy the app files to the vm, and for CI/CD i find this useful.

Step 3

Prepare the docker compose file, yea we are going to use docker compose!!...we are going to orchestrate the web application, and any other dependencies like a database etc together with the nginx server.

so you should have a file called docker-compose.yml

version: "3"
services:
    web:
        image: repo.treescale.com/herocod3r/{sampleApp}
        expose:
            - "5000"
        depends_on:
            - mongo
    mongo:
       image: mongo:latest
       ports:
       - "27017:27017"
       volumes:
       - "/home/app/mymongo:/data/db"
       command: mongod --auth
    proxy:
        build:
            context:  ./nginx
            dockerfile: Dockerfile
        ports:
            - "80:80"
            - "443:443"
        volumes:
             - /etc/letsencrypt/:/etc/letsencrypt/
        links:
            - web

Note! in the proxy service we are mounting to the path /etc/letsencrypt/ so we can have access to the certificate files.

Step 4

Prepare your nginx config file and docker image. Create a folder called nginx as seen in the proxy service above. Then create a file called nginx.conf and put into it the following

worker_processes 4;

events { worker_connections 1024; }

http {
    sendfile on;

    upstream app_servers {
        server web:5000;
    }
    server {
        listen 80 default_server;
        listen [::]:80 default_server;
        server_name {url} www.{url};
        return 301 https://www.$server_name$request_uri;
    }

    server {
        listen 443 ssl;
        ssl_certificate /etc/letsencrypt/live/{url}/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/{url}/privkey.pem;

        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;
        }
    }
}

Note!! replace {url} with the registered domain name we did with certbot. So for example if you registered example.com replace {url} with example.com

And lastly your docker file for the proxy

FROM nginx
COPY nginx.conf /etc/nginx/nginx.conf

Step 5

In the end you should have a folder with this structure

MyApp
    - docker-compose.yml
    nginx
      - nginx.conf
      - Dockerfile

In the end you need to copy the MyApp folder to your VM. Also make sure you have installed docker, and docker-compose.

Then SSH into your vm navigate to the MyApp folder and run

docker-compose up

Note if you are using treescale, Make sure you have signed in to your treescale registry to be able to pull the web image

You might also need to append sudo when running commands, depending on your user privilege.

If all goes right, you should have the ssl all setup, congratz!!

Posted on Feb 8 '19 by:

Discussion

markdown guide
 

Hi Jethro, thanks for the awesome post. I'm getting this error: "[emerg] 1#1: directive "server_name" is not terminated by ";" in /etc/nginx/nginx.conf:14"
(I replaced {url} with my domain). Any suggestion?

 

It is self explanatory, make sure your syntax is correct