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 | |
|---|---|
| Dev server port | 5000 |
| On your Wi-Fi | flask run --host=0.0.0.0 |
| Host check | None as it comes |
| Through the link | What it takes |
|---|---|
| The page | Works, nothing to change |
| Hot reload | Nothing to test |
| A form POST | Works, 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:
RuntimeError: boom // Werkzeug DebuggerThe 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.”
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:
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 5000If 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 --passwordWerkzeug'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.”
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.
- Quickstart, Flask docs. Checked .
- debug/tbtools.py, Werkzeug on GitHub. Checked .
- Debugging Applications, Werkzeug docs. Checked .
- Tell Flask it is Behind a Proxy, Flask docs. Checked .