Open b0l0k opened 6 months ago
I know that Aspire doesn't aim to be a hosting production solution.
It's not that it's not just aiming. The local development orchestrator is not optimized, supported and not secure for deployment scenarios.
Do you have any insights or suggestions on how we might resolve this?
Lots of places currently assume localhost in the product. I'm not sure there's a way for you to work around this currently.
cc @karolz-ms
I understand but assuming that we're not all using a local development environment and having a solution to bind on 0.0.0.0 would be great.
What’s the scenario outside of local development? The orchestrator isn’t supported outside of local development. I’m not just saying that for fun but there’s real security risk in using it outside of that environment (it has not been hardened for that scenario so you run this at your own risk). One thing you can do to circumvent the proxies is to use a proxyless endpoint. In preview 4 that requires excluding the launch profile and adding manual endpoints. Your applicant should be able to listen on 0.0.0.0 directly in that scenario.
Thank you David. 🙏
What’s the scenario outside of local development?
I'm using SSH remote feature from VSCode to develop on a personal computer from my professional one. Therefore when I use 'dotnet run' and I would love to test it from my browser. I'm aware about security risks.
You could use the DevTunnels feature?
I have a slightly different case, but I think it's related to this one.
Before using Aspire I had two services which had to know about each other and use external OAuth2 provider. To avoid rewriting configs every time I've setup Nginx reverse proxy and pointed it to the ports services run on my dev machine.
With Aspire, no matter what do I specify in launchSettings.json
: 0.0.0.0:5000
or mydevbox.lan:5000
, services still bind to localhost
. My Nginx machine can't access the services like that.
Is there a way to use the url from launchSettings.json
instead of mapping it to localhost
?
Aspire is doing some things automatically for you around reading your launch settings and spinning up a reverse proxy of our own. If you want Aspire to get out of this business you can suppress the proxy behavior by doing something like this:
builder.AddProject<Projects.MyApp>("myapp)
.WithEndpoint("http", endpoint => {
endpoint.IsProxied = false;
});
Aspire won't get involved in spinning up a reverse proxy in this case, and whatever is in your launchSettings should be used. Let us know how you go with this!
This is an issue on our side, we hardcode localhost in the ASPNETCORE_URLS generation.
I have a similar issue. I have a Blazor web app. I would like to be able to develop on e.g. iOS Safari on an iPhone, not just the browser on my development machine (Safari is the new Internet Explorer). For this I need to be able to tell Aspire to listen on requests coming from outside localhost. I have successfully been able to configure this for the individual Blazor web app project with the code below. But Aspire does not seem to pickup these changes (which is understandable). I would assume I also have to specify a specific certificate that is valid not just for localhost, but for my internal IP address, e.g. 192.168.1.45.
I would like to get confirmation on:
builder.WebHost.ConfigureKestrel(options =>
{
options.ListenAnyIP(5063);
options.ListenAnyIP(7076, options =>
{
options.UseHttps("certificate.pfx", "YourPassword");
});
});
@mitchdenny maybe I misunderstood the workaround, but it doesn't work for me.
I'm running Aspire NuGet version 8.0.0-preview.5.24201.12
In my Program.cs
I have following definition for the service:
builder.AddProject<Projects.TripstaFileSharing>("tripstaapi")
.WithEndpoint("http", endpoint =>
{
endpoint.IsProxied = false;
});
Aspire http
profile in launchSettings.json
:
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:15192",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19288",
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20230",
"ASPIRE_ALLOW_UNSECURED_TRANSPORT": "true"
}
}
And finally launch profile for the service itself:
"http": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"applicationUrl": "http://0.0.0.0:5297"
}
Despite this configuration changes the service starts up on localhost
and I can't reach it from external machine:
Now listening on: http://localhost:5297
Please let me know if I can try something else.
As @davidfowl mentioned above we by default bind the the listener in ASP.NET Core to localhost/127.0.0.1 which means you can't access it from another machine. We need to do some work on this scenario which will happen post GA at this point.
As a work around you could use DevTunnels and expose the service to the Internet. Here is the steps I took to make this work:
Make the DevTunnel active
Launch the AppHost
Look at the DevTunnels output window for a mapping of internet accessible *.devtunnels.ms
URLs.
Note that DevTunnels will map an internet address to the port that your service exposes, not the reverse proxy that Aspire spins up when it launches your ASP.NET Core app. We've got a bunch of work to do here to make this more intuitive but hopefully this can get you going.
For more information on the DevTunnels feature in VS see here: https://learn.microsoft.com/en-us/aspnet/core/test/dev-tunnels?view=aspnetcore-8.0
There might be a simpler workaround but it’s easier to wait until preview 6 comes out to do it as you’ll be able to mutate the ASPNETCORE_URLS to replace localhost with * or 0.0.0.0
Hi @davidfowl ,
firstly: kudos for aspire, its amazing. We currently have a setup where each GitHub pull request trigger the creation of a virtual machine. On this VM, we run both dotnet Aspire and all our microservices to facilitate API testing.
However, we've encountered an issue. Our API Gateway (Kong), which is running in Docker outside of Aspire, is unable to communicate with the .NET services managed by Aspire. We suspect this might be due to Aspire services binding to localhost rather than to all interfaces (0.0.0.0).
Is there a workaround available that would allow binding to all interfaces, or is waiting for preview 6 the only option?
Thank you.
Here's the workaround for preview 6 (which comes out today):
public static class ProjectExtensions
{
public static IResourceBuilder<ProjectResource> ExposeThePorts(this IResourceBuilder<ProjectResource> builder)
{
return builder.WithEnvironment(async context =>
{
if (context.ExecutionContext.IsRunMode)
{
var urls = context.EnvironmentVariables["ASPNETCORE_URLS"] as ReferenceExpression;
if (urls is null)
{
return;
}
var value = await urls.GetValueAsync(context.CancellationToken);
if (value is null)
{
return;
}
context.EnvironmentVariables["ASPNETCORE_URLS"] = value.Replace("localhost", "*");
}
});
}
}
This won't update the URLs in the dashboard, just the listening URLs for the application itself. I don't know if this will cover all of the cases in this issue but worth a try.
Here's the workaround for preview 6 (which comes out today):
public static class ProjectExtensions { public static IResourceBuilder<ProjectResource> ExposeThePorts(this IResourceBuilder<ProjectResource> builder) { return builder.WithEnvironment(async context => { if (context.ExecutionContext.IsRunMode) { var urls = context.EnvironmentVariables["ASPNETCORE_URLS"] as ReferenceExpression; if (urls is null) { return; } var value = await urls.GetValueAsync(context.CancellationToken); if (value is null) { return; } context.EnvironmentVariables["ASPNETCORE_URLS"] = value.Replace("localhost", "*"); } }); } }
This won't update the URLs in the dashboard, just the listening URLs for the application itself. I don't know if this will cover all of the cases in this issue but worth a try.
Works perfectly for me, thank you!
@davidfowl thank you for the workaround!
Workaround produces interesting side effect:
services doesn't bind to IPv4 0.0.0.0
and port specified in launchSettings.json
, but instead bind to [::]
IPv6 address and random port.
I can access API from outside but I have to dig out the port from the logs every time.
Also setting ASPNETCORE_URL
in launchSettings.json
doesn't have any effect despite this line which I believe should not override them?
After some additional digging I found that most likely endpoint configuration from launchSettings.json
file can't be applied as port name matches port generation expression here.
When I get into the ExposePorts
I can see endpoint definition in the builder:
There's lots of code here and very little docs.
Port = The port used but clients to access a service TargetPort = The port that the service binds to
This is still worthwhile foundational knowledge https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/networking-overview
TL;DR we currently don't take the address into account when binding address in proxied mode or proxyless mode, only the port. This is the issue we need to resolve.
Also setting ASPNETCORE_URL in launchSettings.json doesn't have any effect despite this line which I believe should not override them?
@davidfowl thank you! I figured it out, so to get the target port right I had to still use IsProxied = false
, so that Aspire would set targetPort = port
I have updated to preview 6 but can't get the workaround to work, I am still unable to access my web app from my assigned IP 172.30.1.35 on port 5063 (using http).
I must use port 5063 for http and port 7076 for https.
This is what I have:
Program.cs
var builder = DistributedApplication.CreateBuilder(args);
builder
.AddProject<MyWebApp>("mywebapp")
.WithHttpEndpoint(port: 5063, targetPort: 5063, name: "http-web", env: "Development", isProxied: false)
.WithHttpsEndpoint(port: 7076, targetPort: 7076, name: "https-web", env: "Development", isProxied: false)
.ExposeThePorts();
builder.Build().Run();
launchSettings.json (for my web app project)
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:34641",
"sslPort": 44323
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5117",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7034;http://localhost:5117",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
ProjectExtensions.cs
namespace MyNamespace.AppHost;
public static class ProjectExtensions
{
public static IResourceBuilder<ProjectResource> ExposeThePorts(this IResourceBuilder<ProjectResource> builder)
{
return builder.WithEnvironment(async context =>
{
if (context.ExecutionContext.IsRunMode)
{
if (context.EnvironmentVariables["ASPNETCORE_URLS"] is not ReferenceExpression urls)
{
return;
}
var value = await urls.GetValueAsync(context.CancellationToken);
if (value is null)
{
return;
}
context.EnvironmentVariables["ASPNETCORE_URLS"] = value.Replace("localhost", "*");
}
});
}
}
Remove env: "Development"
.
@davidfowl Thanks, it works!
I think this @davidebbo's change might help here: https://github.com/dotnet/aspire/pull/4679
Its not the complete solution but this would allow us to filter out endpoints being added to ASPNETCORE_URLS
and then we could replace it with our own.
Its not the complete solution but this would allow us to filter out endpoints being added to
ASPNETCORE_URLS
and then we could replace it with our own.
@mitchdenny So you mean you'd append the entire thing yourself to ASPNETCORE_URLS
instead of just replacing localhost
in the existing expression? But wouldn't that mean having to come up with the funky {{- portForServing "apiservice" -}}
syntax in user code?
I might be misunderstanding the suggestion.
Hello,
I've recently found a personal project to test Aspire, and I must say, what you're doing is awesome! The development experience is 👌 ; it took me just a few hours to craft a service that's horizontally scalable built on Kafka and Postgres.
However, as I delved into the deployment aspect, I faced my first challenge. I'm keen on testing the service on a separate laptop within my local network using Aspire to manage it, rather than resorting to Docker Compose or Kubernetes. Essentially, I'm aiming to execute it with a simple
dotnet run
command. I know that Aspire doesn't aim to be a hosting production solution.By default, it seems everything is bound to localhost, restricting access to the loopback interface. I managed to override this behavior by configuring a dedicated setup in
launchProfile.json
:Please note that using 0.0.0.0 as an alternative isn't effective. It appears there's a check in place to monitor the dashboard, leading to a timeout after 1:00.
The good news is that this configuration works seamlessly for the Dashboard part. However, I'm encountering issues accessing the WebAPI project, which seems to be bound to localhost through the proxy, therefore not accessible remotely.
Do you have any insights or suggestions on how we might resolve this?