Dockerized .NET Core 2 app in Linux

I have an ASP.NET Core 2.0 app that uses the Hangfire Dashboard. When running it in my localhost (IIS Express), everything works fine but when it is deployed live as a Dockerized app the Hangfire Dashboard page just returns a β€œ403” error.
Is there a specific configuration I need to do when deploying it as a Dockerized app?

image

This is from my Startup

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseBrowserLink();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }

        app.UseStaticFiles();
        app.UseAuthentication();
        app.UseMvcWithDefaultRoute();
        
        app.UseHangfireServer();
        UseHangfireDashboardCustom(app);

        RecurringJob.AddOrUpdate<IFacebookAdsCronJobService>("FacebookAdsInsights", c =>
            c.Execute(),
            Cron.Daily);
    }

    private static IApplicationBuilder UseHangfireDashboardCustom(
        IApplicationBuilder app,
        string pathMatch = "/romi/data-integration",
        DashboardOptions options = null,
        JobStorage storage = null)
    {
        var services = app.ApplicationServices;
        storage = storage ?? services.GetRequiredService<JobStorage>();
        options = options ?? services.GetService<DashboardOptions>() ?? new DashboardOptions();
        var routes = app.ApplicationServices.GetRequiredService<RouteCollection>();

        // Use our custom middleware.
        app.Map(new PathString(pathMatch), x =>
            x.UseMiddleware<HangfireDashboardMiddleware>(storage, options, routes)
        );
        
        return app;
    }

This is the Middleware

using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Hangfire;
using Hangfire.Dashboard;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;

namespace ROMI.DataIntegration.Web.Facebook.Ads.Auth
{
public class HangfireDashboardMiddleware
{
private readonly DashboardOptions _dashboardOptions;
private readonly JobStorage _jobStorage;
private readonly RequestDelegate _nextRequestDelegate;
private readonly RouteCollection _routeCollection;

    public HangfireDashboardMiddleware(
        RequestDelegate nextRequestDelegate,
        JobStorage storage,
        DashboardOptions options,
        RouteCollection routes)
    {
        _nextRequestDelegate = nextRequestDelegate;
        _jobStorage = storage;
        _dashboardOptions = options;
        _routeCollection = routes;
    }

    public async Task Invoke(HttpContext httpContext)
    {
        var aspNetCoreDashboardContext =
            new AspNetCoreDashboardContext(_jobStorage, _dashboardOptions, httpContext);

        var findResult = _routeCollection.FindDispatcher(httpContext.Request.Path.Value);
        if (findResult == null)
        {
            await _nextRequestDelegate.Invoke(httpContext);
            return;
        }

        // attempt to authenticate against default auth scheme (this will attempt to authenticate using data in request, but doesn't send challenge)
        var result = await httpContext.AuthenticateAsync();

        if (!httpContext.User.Identity.IsAuthenticated)
        {
            // request was not authenticated, send challenge and do not continue processing this request
            await httpContext.ChallengeAsync();
        }

        if (_dashboardOptions
            .Authorization
            .Any(filter =>
                     filter.Authorize(aspNetCoreDashboardContext) == false))
        {
            var isAuthenticated = httpContext.User?.Identity?.IsAuthenticated;
            httpContext.Response.StatusCode = isAuthenticated == true
                                                  ? (int) HttpStatusCode.Forbidden
                                                  : (int) HttpStatusCode.Unauthorized;
            return;
        }

        aspNetCoreDashboardContext.UriMatch = findResult.Item2;
        await findResult.Item1.Dispatch(aspNetCoreDashboardContext);
    }
}

}

There is no specific configuration required for a docker host. We have our hangfire server running inside docker on Linux as well. Check your config one more time and also make sure that hangfire dashboard uses proper authorization filter http://docs.hangfire.io/en/latest/configuration/using-dashboard.html.

Looks like you haven’t specified a dashboard authorization filter to allow remote requests. By default, it only allows dashboard access from localhost.

1 Like

Got it working now. Thanks!