Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP .NET Core gives System.Net.Sockets.SocketException error on Heroku

I am trying to deploy .NET core web API to Heroku.

Below is my Dockerfile:

FROM mcr.microsoft.com/dotnet/core/aspnet:2.1 AS runtime
WORKDIR /app
COPY /out ./
CMD ASPNETCORE_URLS=http://*:$PORT dotnet dotnetcoreapi.dll

This Dockerfile works fine on Heroku, but when I tried to deploy with

FROM mcr.microsoft.com/dotnet/core/aspnet:2.1 AS runtime
WORKDIR /app
COPY /out ./
ENTRYPOINT ["dotnet","dotnetcoreapi.dll"]

Heroku gives me this error:

Unable to start Kestrel. System.Net.Sockets.SocketException (13): Permission denied

Why doesn't ENTRYPOINT ["dotnet","dotnetcoreapi.dll"] work on Heroku? Both versions work fine on my local machine

like image 650
Baala Srinivas K Avatar asked Dec 06 '22 09:12

Baala Srinivas K


2 Answers

I've just solved this problem thanks to Chis' answer and this blogpost.

It turns out that Heroku really wants to take care of the ports for you (probably for security reasons).

With boilerplate asp core template, with docker suport added you start with:

Program.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace TestWebApp
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}

Dockerfile:

#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["TestWebApp/TestWebApp.csproj", "TestWebApp/"]
RUN dotnet restore "TestWebApp/TestWebApp.csproj"
COPY . .
WORKDIR "/src/TestWebApp"
RUN dotnet build "TestWebApp.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "TestWebApp.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "TestWebApp.dll"]

Heroku expects your app to run on the port Heroku gives you in PORT environment variable. It'll expose 80 (HTTP) and 443 (HTTPS) ports for you. So what you have to do is:

Remove these lines form your Dockerfile:

EXPOSE 80
EXPOSE 443

Then you have to make your application listen on that port. To make it work, you have to change your Program.cs file:

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    var port = Environment.GetEnvironmentVariable("PORT");

                    webBuilder.UseStartup<Startup>()
                    .UseUrls("http://*:" + port);
                });

Then Heroku does it's magic and your app still gets HTTPS support.

Hint:

The default Dockerfile won't work out of the box with Heroku CLI. The generated Dockerfile is supposed to be ran from the solution level (not project level). I was unable to force heroku CLI to use a Dockerfile form a nested direcotry. The way I made id work was:

  1. Go to your solution directory
  2. Create Dockerfile
  3. Paste modified content:
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["TestWebApp/TestWebApp.csproj", "TestWebApp/"]
RUN dotnet restore "TestWebApp/TestWebApp.csproj"
COPY ./TestWebApp ./TestWebApp
WORKDIR "/src/TestWebApp"
RUN dotnet build "TestWebApp.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "TestWebApp.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "TestWebApp.dll"]
  1. heroku login
  2. heroku container:login
  3. heroku container:push web --app your-app & heroku container:release web --app your-app
like image 194
Andrzej Gis Avatar answered Jan 11 '23 22:01

Andrzej Gis


This probably isn't really about your ENTRYPOINT, but rather the ASPNETCORE_URLS environment variable that you use with CMD:

CMD ASPNETCORE_URLS=http://*:$PORT dotnet dotnetcoreapi.dll

Here you run your application setting ASPNETCORE_URLS to a single URL using the PORT given to you by Heroku.

In the second Dockerfile, you don't provide that environment variable and you get a socket error. It's very likely that your application is trying to listen for both HTTP and HTTPS (or maybe just HTTPS) connections.

Heroku provides a single port for you to use, and your application should listen for HTTP (not HTTPS) connections on that Port. Heroku will take care of the HTTPS part.

Try this:

FROM mcr.microsoft.com/dotnet/core/aspnet:2.1 AS runtime
WORKDIR /app
COPY /out ./

ENV ASPNETCORE_URLS http://*:$PORT
ENTRYPOINT ["dotnet","dotnetcoreapi.dll"]
like image 22
Chris Avatar answered Jan 11 '23 22:01

Chris