Skip to the page

Share a Flask app without exposing the debugger

flask run shares as it is, forms and all. With --debug, ouicu keeps Werkzeug's console back, but error pages show your code, so leave it off or lock it.

Updated

flask run shares through ouicu as it is: pages load and forms post. The thing to watch is --debug. ouicu keeps Werkzeug's debugger console from visitors, so nobody runs Python on your laptop through the link, but an error still shows them its traceback page, with your code. Share without --debug, or put a password on the link.

Flask at a glance
Flask
Dev server port5000
On your Wi-Fiflask run --host=0.0.0.0
Host checkNone as it comes
Flask through a ouicu link
Through the linkWhat it takes
The pageWorks, nothing to change
Hot reloadNothing to test
A form POSTWorks, nothing to change

The debugger, through a link

Run with --debug, raise an error, and open the page through the link. The visitor gets this, with your code around the line that failed:

The page's title
RuntimeError: boom // Werkzeug Debugger

The debugger guards its console by host: “The debug console will only be served if the request comes from a trusted host.” “By default, localhost, any .localhost subdomain, and 127.0.0.1 are trusted.” ouicu hands Flask Host: localhost:5000, so the check passes for every visitor, and the page comes with its console turned on. Through a tunnel that keeps the public name in Host, the console was off.

Left to Werkzeug, what would stand between a visitor and a Python prompt on your laptop is the PIN. “The first time a console is opened, a dialog will prompt for a PIN that is printed to the command line.” Werkzeug is plain about it: “This feature is not meant to entirely secure the debugger.” And Flask's quickstart:

“The debugger allows executing arbitrary Python code from the browser. It is protected by a pin, but still represents a major security risk.”

Flask docs, Quickstart

ouicu keeps the console back

So ouicu doesn't pass the console on. Every request the debugger answers itself carries __debugger__=yes in its address: its script and styles, the PIN prompt, and the code typed into it. ouicu answers each one with its own 403 page before it reaches Flask, and the debugger's /console page too. A PIN guess through the link got A debugger console isn't shared through a link, and Flask's log never showed it. ouicu share says so once:

What ouicu share prints
Not passed to visitors: Werkzeug's debugger (flask run --debug), whose console runs Python on this computer. Its error pages still show to anyone with the link, with your code: share without --debug, or with --password or --allow.

The traceback page itself still shows, without the debugger's styles: the error, your file names and the code around each line it went through, to anyone with the link. That much is up to you.

Share it without the debugger, or behind a password

Leave --debug off while the link is out. An error is then a plain 500 Internal Server Error, which is all a client should see:

flask --app app run# in a second terminalouicu share 5000

If you need the debugger while someone looks, ask for a password, on Hobby and Pro, or name the people allowed in, on Pro. ouicu asks at the door, before a request reaches Flask, so strangers never see your tracebacks at all:

ouicu share 5000 --password

Werkzeug's own rule still holds: “The debugger must never be used on production machines.” A shared dev server is a step towards production, so treat the link the same way (passwords and invited people).

Share flask run with ouicu

flask run listens on your computer alone and says so: Running on http://127.0.0.1:5000. That's all ouicu needs. A request with the public name as Host was answered too, so there is no host check to pass as it comes, and a form posted through the link with nothing to set. On Free, a share runs for up to 2 hours. Getting started has the install.

For a phone on your Wi-Fi without a link, Flask needs flask run --host=0.0.0.0, and Flask's docs say why it's off by default: “in debugging mode a user of the application can execute arbitrary Python code on your computer.” The QR code ouicu prints needs no such flag (QR codes).

url_for says localhost

Through the link, url_for('where', _external=True) gave http://localhost:5000/where. Flask's deployment docs explain:

“From the WSGI server and Flask application’s perspectives, requests are now coming from the HTTP server to the local address, rather than from the remote address to the external server address.”

Flask docs, Tell Flask it is Behind a Proxy

Wrap the app in Werkzeug's ProxyFix, trusting the one proxy in front of it, and the same call gives https://calm-otter-4821.ouicu.app/where:

from werkzeug.middleware.proxy_fix import ProxyFix app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1)

The docs add a warning worth heeding: “Remember, only apply this middleware if you are behind a proxy, and set the correct number of proxies that set each header.” Keep it to the times you share, as a setting you turn on.

Why not upload it

Flask builds each page on the server, and ouicu deploy uploads static files only, so a Flask app is shared live, from your laptop. To show a client, share it while you talk them through; see show a client a website before it goes live.

Tested with Flask 3.1.3 on , with Python 3.12.3: a small Flask app with a form, a url_for page and an error, in a fresh virtualenv with Werkzeug 3.1.9, run by flask run with and without --debug and ProxyFix, shared with ouicu share through ouicu's edge and opened in Chromium at its https link, and through a tunnel that keeps the public host.

Sources

Prices, defaults and quotes about other products, and the day each was last checked at its source.

  1. Quickstart, Flask docs. Checked .
  2. debug/tbtools.py, Werkzeug on GitHub. Checked .
  3. Debugging Applications, Werkzeug docs. Checked .
  4. Tell Flask it is Behind a Proxy, Flask docs. Checked .