This was filed as
https://code.djangoproject.com/ticket/27537 , but moving here for discussion.
We have the following use case:
* An app uses a VM for the local development environment (eg via Vagrant).
* It's required to be accessible from the VM host (either on it's own IP, or on localhost via eg Virtualbox port forwarding) to allow development to occur using editors/browsers on the host. (The configuration is such that connections are only allowed from the VM host and not other machines on the network, so this is still secure.)
* The app has no need for nginx/apache, since production is Heroku (where that's discouraged) and so it uses gunicorn + WhiteNoise.
* During development, devs want to use runserver rather than gunicorn for convenience (and familiarity for existing Django devs).
* However `./manage.py runserver` doesn't work, since that binds to the loopback adapter of the VM guest OS only (127.0.0.1) and not 0.0.0.0. (This is a sensible default.)
* Therefore `./manage.py runserver 0.0.0.0:8000` must be used, which:
- is not immediately obvious to devs new to the project (which is open source, so we often have new contributors). Docs are great, but not everyone reads them fully - defaults that work out of the box are best.
- means even once they realise the need for the explicit binding address, they have to type it out every time.
Current workarounds are:
a) Add an nginx/apache/varnish service to the VM to reverse proxy from 0.0.0.0:X to
127.0.0.0:8000, increasing bootstrap time and boilerplate.
b) Not use runserver, and use gunicorn instead (where the `PORT` environment variable can be set, making it bind to `
0.0.0.0:<PORT>` [1]).
c) Add bash aliases to the development environment (but then they're not immediately discoverable either, and break muscle memory for existing Django users).
d) Write a custom runserver command that overrides the inbuilt one (but this requires overriding the `handle()` method, since `127.0.0.1` is hardcoded [2], so even more boilerplate).
Possible changes that would make this easier:
1) Allow overriding runserver default IP/port using Django settings.
2) Allow overriding runserver default IP/port using environment variables (like `PORT` already supported by gunicorn, that defaults the IP to `0.0.0.0` too).
3) Move the hardcoded `127.0.0.1` string [2] to an attribute on the `Command`, like `default_port` is, to at least reduce the boilerplate for overriding using a custom runserver command.
I can imagine (3) would be more likely to be accepted, however it would still mean we have to override runserver, so (1) or (2) would be preferred.
I'm happy to implement this - it would just be helpful to know people's thoughts before I open a PR.
Many thanks :-)
Ed
[1]
https://github.com/benoitc/gunicorn/blob/6eb01409da42a81b7020cd78c52613d8ec868e94/gunicorn/config.py#L543-L544[2]
https://github.com/django/django/blob/eb42d8d5d9b0968ce12d09760afff684bee56a3a/django/core/management/commands/runserver.py#L95