sanic-org / sanic

Accelerate your web app development | Build fast. Run fast.

Home Page:https://sanic.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Sanic should bind all IP addresses of a hostname (not only one)

Tronic opened this issue · comments

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

sanic --host example.com using a domain with multiple A/AAAA records, the server only binds to one of them.

Code snippet

No response

Expected Behavior

Sanic should bind to each IPv4 and IPv6 address that the DNS name resolves into.

How do you run Sanic?

Sanic CLI

Operating System

Linux

Sanic Version

22.12

Additional context

Some way to bind both 0.0.0.0 and :: together would also be useful. * would possibly be the most standard way to denote it but on CLI that needs quotes or bad things happen, so something like @ could be a safer way to say "bind to everything".

Have an idea of what that would look like?

In server code? No, that has always been black magic to me.

But sanic --host example.com leads to gethostbyname somewhere, that returns a list of IPs, and Sanic needs to run a separate server for each. Currently it presumably takes the first one and only runs one server.

IIRC, it was at some point relying on uvloop create_server(?) to do what I said in the previous paragraph, which led to actually having this functionality at least on some cases (such as localhost binding to IPv4 and IPv6). By my test right now, on a public DNS name with A and AAAA records, Sanic bound only to IPv4.

I meant the CLI command if we want to allow it to distinguish.

The main topic of this issue (and why I labeled it a bug) would not change app.run or CLI interfaces at all, but simply bind to all matching IPs of the given hostname, as is reasonable to expect. But it does go along well with the other things that you are working with and discussed in #2656 that go far beyond fixing that long-standing binding bug on a single hostname with multiple IPs.

Steps:

  1. Allow running multiple servers in one (app.run and/or CLI command)
  2. Resolve hostnames to all their IPs and do the above
  3. Add support for binding to multiple hosts and/or ports (including a wildcard host for 0.0.0.0 and :: together), app.run/CLI to take multiple host:port arguments
  4. Allow running different apps at different host/port/vhost/path
  5. ??? (snx, --public?)

Mainly I would consider points 1-3 covered by this issue, while the others are additional work building on top of them.

Still not a bug. This is 💯 a new feature.

  1. Not in app.run. The correct way to bind multiple is app.prepare and then Sanic.serve. The new feature is to allow for multiple app.prepare from the CLI
  2. Also this is a new feature. I am not sure if Sanic is involved at all in resolution right now. DNS in Python is.... 😒 sometimes rather difficult. But, we should be able to accomplish this. This can probably be added in the upcoming release. Unless I am way off-base I think this could be done rather easily. I will look at this tomorrow.
  3. Yeah. I still think there should be something explicit for this.
  4. From the CLI? I do not see this coming into Sanic CLI any time soon. snx ... for sure.
sanic path.to.server:app --host=example.com --public ...

What does --public do?

  1. Binds both 80 and 443. It should fail if no certs are supplied.
  2. Adds a redirect app from 80 to 443.
  3. If host is not an ip address, then attempts to resolve ipv4 and ipv6 as you suggest

I think this is the extent of what we can reasonably expect to handle from the sanic CLI. Anything further would require more hands-on dropdown into Python, and/or wait for snx --config.

Now the discussion in randomly scattered among the two issues. Bummers. But yes, I concur in general with your points.

What does --public do?

EDIT: redacted previous things. I believe certbot can also run its own server when port 80 is free, and could be used to obtain the initial certs, avoiding the bootstrap problem.