Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET Core Docker with Automated SSL

I am currently working on deploying a .NET Core web api on a server. I wanted to do it using docker compose for easy management. In my Startup.cs I have this code:

public class Startup
{
    public Startup (IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices (IServiceCollection services)
    {
        var databaseHost = Configuration["DB_HOST"] ?? "localhost";
        // ........
    }
    // ........
}

My Dockerfile is pretty standard, as Microsoft's documentation states it should be:

FROM microsoft/dotnet:sdk AS build-env
WORKDIR /app

# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore

# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -o out

# Build runtime image
FROM microsoft/dotnet:aspnetcore-runtime
WORKDIR /app
COPY --from=build-env /app/out .
EXPOSE 80/tcp
ENTRYPOINT ["dotnet", "ApiProject.dll"]

I define my environment variables in my docker-compose.yml file:

version: '3'
services:
restapi:
    build:
    context: ./ApiProject
    dockerfile: Dockerfile
    depends_on:
    - db
    ports:
    - "5000:80"
    restart: always
    environment:
    - DB_HOST=db
db:
image: postgres
ports:
    - "5432:5432"
restart: always
environment:
    POSTGRES_USER: "root"
    POSTGRES_PASSWORD: "root"

This docker-compose.yml file works just fine on my local machine. The issue comes when I want to deploy it on the server. Someone online have made a docker-compose file which runs an nginx proxy and containers for automatically retrieving valid SSL certificates using Let's Encrypt (jwilder/nginx-proxy).

It is pretty easy to get it working. When starting a new docker container, you just have to assign it to the correct external docker network (in this case: nginx-proxy), and then give it the following environment variables:

  • VIRTUAL_HOST: example.com
  • LETSENCRYPT_HOST: example.com
  • LETSENCRYPT_EMAIL: [email protected]

Furthermore, instead of mapping ports, you just have to expose port 80. Then when the container starts up, the other containers will automatically get the SSL certificates and make a proxy to the newly started container.

The issue here is the way Microsoft's containers works with environment variables. The container for my web api has a few environment variables of itself, such as DB_HOST=mydbhost.com. It then automatically gets imported in the code. That means I can't add the environment variables (i.e. VIRTUAL_HOST: example.com) needed for the proxy containers to work properly.

I tried out with the following docker-compose.yml configuration:

  version: '3'
  services:
    restapi:
      build:
        context: ./EffortlessApi
        dockerfile: Dockerfile
      depends_on:
        - db
      expose:
        - 80
      restart: always
      environment:
        - DB_HOST=db
        - VIRTUAL_HOST: my_domain.com
        - LETSENCRYPT_HOST: my_domain.com
        - LETSENCRYPT_EMAIL: [email protected]
    db:
    image: postgres
    ports:
      - "5432:5432"
    restart: always
    environment:
      POSTGRES_USER: "root"
      POSTGRES_PASSWORD: "root"
  networks:
    default:
      external:
        name: nginx-proxy

But that resolved in the following error when running docker-compose up:

ERROR: The Compose file './docker-compose.yml' is invalid because: services.restapi.environment contains {"VIRTUAL_HOST": "api.effortless.dk"}, which is an invalid type, it should be a string

I'm quite lost on how I should solve this issue. I want to easily deploy and manage multiple containers with valid SSL certificates, and this setup is pretty cool, if just it worked with the .NET project as well.

like image 645
Algorythm Avatar asked Oct 16 '22 10:10

Algorythm


1 Answers

I figured it all out, the solution was luckily pretty simple. I don't know why, but Microsoft for some reason simply chose to format their environment wrong. To fix this, simply use = rather than : without the space:

(...)
environment:
   - DB_HOST=db
   - VIRTUAL_HOST=my_domain.com
   - LETSENCRYPT_HOST=my_domain.com
   - [email protected]
(...)
like image 166
Algorythm Avatar answered Oct 20 '22 16:10

Algorythm