Chapter 37 · Python Appservice Deploy
Subchapter 37.7
references/startup-commands.mdMarkdown4 KBView on GitHub
Linux App Service (Oryx) auto-detects Flask and Django — no startup command is needed for these. FastAPI does NOT rely on Oryx auto-detection in this skill: we always set an explicit uvicorn startup command so the behavior is identical on every supported Python runtime (3.12, 3.13, 3.14, …). This skill also sets a startup command (or emits a manual hint) for non-Flask/Django/FastAPI frameworks.
Azure App Service (Oryx) auto-detects Flask and starts it correctly. Do not run az webapp config set --startup-file for Flask apps.
Azure App Service (Oryx) auto-detects Django by finding wsgi.py and starts gunicorn against <project>.wsgi:application automatically. Do not run az webapp config set --startup-file for Django apps.
Make sure the project has:
requirements.txt containing django (and ideally gunicorn; Oryx provides one if missing)<project>/wsgi.py at a path Oryx can discover (the default Django layout works out of the box)ALLOWED_HOSTS includes <app>.azurewebsites.net (or * for first-deploy validation — tighten later)The skill sets the startup command unconditionally for FastAPI, regardless of the Python runtime version. Oryx FastAPI auto-detection is not relied on — an explicit startup command always works and avoids version-dependent surprises:
az webapp config set -n <app> -g <rg> \
--startup-file "python -m uvicorn main:app --host 0.0.0.0"az webapp config set -n <app> -g <rg> `
--startup-file "python -m uvicorn main:app --host 0.0.0.0"Replace main:app with the discovered entry point if different (e.g., app.main:app, src.api:app). The --host 0.0.0.0 flag is mandatory — uvicorn defaults to 127.0.0.1, which causes App Service container-ping timeouts.
Make sure requirements.txt contains both fastapi and uvicorn (or uvicorn[standard]).
When the detected framework is wsgi-generic, asgi-generic, or unknown, deploy the code without setting a startup command and surface this message to the user:
⚠️ This skill auto-configures Flask, Django, and FastAPI only. The app has been deployed, but App Service may not start it until you set a startup command. Choose the matching example below and run it:
az webapp config set -n <app> -g <rg> \
--startup-file "gunicorn --bind=0.0.0.0 --timeout 600 <module>:<callable>"az webapp config set -n <app> -g <rg> `
--startup-file "gunicorn --bind=0.0.0.0 --timeout 600 <module>:<callable>"az webapp config set -n <app> -g <rg> \
--startup-file "python -m uvicorn <module>:<callable> --host 0.0.0.0 --port 8000"az webapp config set -n <app> -g <rg> `
--startup-file "python -m uvicorn <module>:<callable> --host 0.0.0.0 --port 8000"Oryx auto-detection covers the standard Django layout. Set this manually only if the project uses a non-standard layout and the auto-detected startup doesn’t find your WSGI app:
az webapp config set -n <app> -g <rg> \
--startup-file "gunicorn --bind=0.0.0.0 --timeout 600 <project>.wsgi"az webapp config set -n <app> -g <rg> `
--startup-file "gunicorn --bind=0.0.0.0 --timeout 600 <project>.wsgi"# Current value
az webapp config show -n <app> -g <rg> --query linuxFxVersion -o tsv
az webapp config show -n <app> -g <rg> --query appCommandLine -o tsv
# Live logs
az webapp log tail -n <app> -g <rg>Look for:
Container <app>_<...> didn't respond to HTTP pings on port: 8000 → app didn’t bind to 0.0.0.0 (or 0.0.0.0:8000)ModuleNotFoundError → wrong <module>:<callable> in startup command, or build didn’t install depsgunicorn: command not found / uvicorn: command not found → add gunicorn / uvicorn to requirements.txtApp Service forwards traffic to the container on the port the runtime listens on (8000 by default). The startup command must bind to 0.0.0.0 so the platform’s ping reaches it — binding to 127.0.0.1 causes ping timeouts.