Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Running flask on a randomly allocated free port #4205

Closed
spanezz opened this issue Jul 20, 2021 · 4 comments
Closed

Running flask on a randomly allocated free port #4205

spanezz opened this issue Jul 20, 2021 · 4 comments

Comments

@spanezz
Copy link

spanezz commented Jul 20, 2021

I'd like to be able to tell flask to run its webserver on a randomly allocated free local port.

Browsing through the code, it's currently possible with this: app.run(host="127.0.0.1", port='0') (note the zero passed as a string), and it works, and the right URL is logged with the port that got allocated.

Ideally there should also be a way to programmatically extract what port was allocated, but I'm sure it won't take much digging to find a way to hook into flask or werkzeug to start a webbrowser once the port is known.

I'm using flask to write a program that uses the browser for its user interface, and I would like to avoid static port allocation so that multiple users on the same machine would be able to run the program, or so that I won't conflict with the port already being in use. In other words, I want to avoid that starting the program needs to involve luck.

While I can currently make flask do that, it does not look like it was intended on the authors' part, so I'm reluctant to build on that solution.

Would it be possible to make this use case official somehow?

@spanezz
Copy link
Author

spanezz commented Jul 20, 2021

This is a possibly less hackish way, I'm still not sure how supported it would be:

    from werkzeug import serving
    app = create_app(args.db)
    server = serving.make_server(
            host='127.0.0.1', 
            port=0, 
            app=app,
            threaded=True)
    port = server.socket.getsockname()[1]
    log.info("Running on http://localhost:%d (Press CTRL+C to quit))", port) 
    server.serve_forever()

@RonnyPfannschmidt
Copy link
Contributor

@spanezz a general suggestion is not to use the builtin server for production workloads

i would recommend to use a more dedicated lib for serving and startup/teardown (like waitress/gunicorn/uwsgi(

@spanezz
Copy link
Author

spanezz commented Jul 20, 2021

@RonnyPfannschmidt Ok. Thank you for the quick reply, although to be honest I feel like I got dismissed with a boilerplate reply.

I did look at using proper WSGI servers:

  • gunicorn requires to be started as a command line wrapper, so the startup instructions for the program would be "run gunicorn --something --somethingelse module:appname --etcetera", which is not how one would expect to run a GUI program.
  • same with uwsgi
  • gevent doesn't support automatically allocating a free port
  • I didn't know waitress, and thank you for the pointer. It does look interesting for this case, but using it would still mean introducing an extra dependency.

Let's define what "production workload" means in this case then.

We are talking about a user running both the server and the browser, and a load of maximum one client ever hitting the server at the same time (though a web browser might decide to do a few concurrent connections to get assets for a page). The builtin server does scale to one concurrent user pretty well, and it is its standard intended workload.

Once other users are prevented to reach the listening port, the server is run by the user themselves. Being run by the same user that runs the browser is pretty much the builtin server's standard security model.

Running the builtin server for such a program-with-a-browser-for-UI on the other hand does reduce the amount of dependencies.

It's fine if you are not interested in supporting this use case. It would be sad, because Flask is otherwise pretty good for this kind of embedding, and the only bit that I find missing is explicitly supporting running on an automatically allocated free port.

@davidism
Copy link
Member

explicitly supporting running on an automatically allocated free port.

The Werkzeug development server does explicitly support this. We don't explicitly support getting the port, but as you've seen you can build the server (which is also supported) before running it, then introspect it. That server is based on Python's built-in HTTP server, so if you want a port attribute probably better to request it on the python-ideas mailing list.

"Production" means "not development". It has nothing to do with specifically the complexity or locality. The development server is not for production, it is not guaranteed to be efficient, stable, or secure, and if you want to use it despite that we don't consider it a missing feature from Flask or Werkzeug.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 4, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants