NewSchokr 13 is here. A whole new UI, seven locations, snapshots and more. Read more →

How to deploy a Flask app with gunicorn or waitress

Run a Flask app in production on Schokr using gunicorn or waitress instead of the dev server, bound to 0.0.0.0 and your allocated port.

Updated · 2 min read

Do not run Flask's built-in development server in production. On Schokr, serve your Flask app with a production WSGI server such as gunicorn or waitress, bound to 0.0.0.0 and the port shown in your server's Network section.

1. Your Flask app

app.py:

from flask import Flask, jsonify

app = Flask(__name__)

@app.get("/")
def index():
    return jsonify(status="ok")

requirements.txt:

flask==3.0.3
gunicorn==23.0.0

2. Option A: gunicorn

gunicorn is the most common choice on Linux:

gunicorn --bind 0.0.0.0:25571 --workers 2 app:app

app:app means "the app object inside app.py". Replace 25571 with your port. Each worker is a separate process with its own memory, so start with 2 workers on a small server and increase only if you have memory to spare.

2. Option B: waitress from a Python file

If your template runs a Python file rather than a custom command, waitress lets you start the server from code. Add waitress to requirements.txt and create main.py:

import os
from waitress import serve
from app import app

port = int(os.environ.get("APP_PORT", "8080"))
serve(app, host="0.0.0.0", port=port, threads=4)

Then set main.py as the file to run.

3. Deploy on Schokr

  1. Create a server with the Python template in the console. 256 to 512 MB is fine for most Flask apps.
  2. Note your port in the Network section.
  3. Upload app.py, requirements.txt and your templates/ and static/ folders with the file manager. Do not upload your local venv.
  4. In your server's Startup settings, set the file to run (for waitress) or the startup command (for gunicorn), depending on what the template exposes.
  5. Start the server. pip installs your requirements, then the server starts.
  6. Visit http://<server-address>:<port>.

Settings and secrets

Set SECRET_KEY from the environment rather than in code:

import os
app.config["SECRET_KEY"] = os.environ["SECRET_KEY"]

See environment variables and secrets for using a .env file.

Behind a proxy

If you put Cloudflare or another proxy in front, use ProxyFix so Flask sees the real scheme and client IP:

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

Troubleshooting

ProblemFix
Running on http://127.0.0.1:5000 in the logYou are running the dev server. Switch to gunicorn or waitress.
ModuleNotFoundError: No module named 'app'The working directory or module path is wrong. See module not found.
Worker killed, SIGKILLOut of memory. Reduce workers or add memory.
Browser cannot connectCheck the bind address and port. See app not reachable.