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
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.
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:
#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"]
heroku login
heroku container:login
heroku container:push web --app your-app & heroku container:release web --app your-app
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"]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With