You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Here, `FRONTEND_DIR`, to build a path to where a build tool like yarn is run. You can again use an environment variable and App Setting as desired.
158
+
Here, `FRONTEND_DIR` is used to build a path to where a build tool like yarn is run. You can again use an environment variable and App Setting as desired.
159
159
160
160
1. Add `whitenoise` to your *requirements.txt* file. [Whitenoise](http://whitenoise.evans.io/en/stable/) (whitenoise.evans.io) is a Python package that makes it simple for a production Django app to serve its own static files. Whitenoise specifically serves those files that are found in the folder specified by the Django `STATIC_ROOT` variable.
161
161
@@ -204,7 +204,7 @@ This container has the following characteristics:
204
204
- Apps are run using the [Gunicorn WSGI HTTP Server](https://gunicorn.org/), using the extra arguments `--bind=0.0.0.0 --timeout 600`.
205
205
- You can provide configuration settings for Gunicorn by [customizing the startup command](#customize-startup-command).
206
206
207
-
- To protect your web app from accidental or deliberate DDOS attacks, Gunicorn is run behind an Nginx reverse proxy as described on[Deploying Gunicorn](https://docs.gunicorn.org/en/latest/deploy.html) (docs.gunicorn.org).
207
+
- To protect your web app from accidental or deliberate DDOS attacks, Gunicorn is run behind an Nginx reverse proxy as described in[Deploying Gunicorn](https://docs.gunicorn.org/en/latest/deploy.html).
208
208
209
209
- By default, the base container image includes only the Flask web framework, but the container supports other frameworks that are WSGI-compliant and compatible with Python 3.6+, such as Django.
210
210
@@ -220,10 +220,10 @@ This container has the following characteristics:
220
220
221
221
During startup, the App Service on Linux container runs the following steps:
222
222
223
-
1. Use a [custom startup command](#customize-startup-command), if provided.
224
-
2. Check for the existence of a [Django app](#django-app), and launch Gunicorn for it if detected.
225
-
3. Check for the existence of a [Flask app](#flask-app), and launch Gunicorn for it if detected.
226
-
4. If no other app is found, start a default app that's built into the container.
223
+
1. Use a [custom startup command](#customize-startup-command), if one is provided.
224
+
1. Check for the existence of a [Django app](#django-app), and launch Gunicorn for it if one is detected.
225
+
1. Check for the existence of a [Flask app](#flask-app), and launch Gunicorn for it if one is detected.
226
+
1. If no other app is found, start a default app that's built into the container.
227
227
228
228
The following sections provide extra details for each option.
If your main app module is contained in a different file, use a different name for the app object, or you want to provide other arguments to Gunicorn, use a [custom startup command](#customize-startup-command).
255
+
If your main app module is contained in a different file, use a different name for the app object. If you want to provide other arguments to Gunicorn, use a [custom startup command](#customize-startup-command).
256
256
257
257
### Default behavior
258
258
@@ -262,8 +262,6 @@ If you deployed code and still see the default app, see [Troubleshooting - App d
262
262
263
263
:::image type="content" source="media/configure-language-python/default-python-app.png" alt-text="Screenshot of the default App Service on Linux web page." link="#app-doesnt-appear":::
264
264
265
-
Again, if you expect to see a deployed app instead of the default app, see [Troubleshooting - App doesn't appear](#app-doesnt-appear).
266
-
267
265
## Customize startup command
268
266
269
267
You can control the container's startup behavior by providing either a custom startup command or multiple commands in a startup command file. A startup command file can use whatever name you choose, such as *startup.sh*, *startup.cmd*, *startup.txt*, and so on.
@@ -286,15 +284,15 @@ App Service ignores any errors that occur when processing a custom startup comma
286
284
287
285
### Example startup commands
288
286
289
-
- **Added Gunicorn arguments**: The following example adds the `--workers=4` to a Gunicorn command line for starting a Django app:
287
+
- **Added Gunicorn arguments**: The following example adds the `--workers=4` argument to a Gunicorn command line for starting a Django app:
290
288
291
289
```bash
292
290
# <module-path> is the relative path to the folder that contains the module
293
291
# that contains wsgi.py; <module> is the name of the folder containing wsgi.py.
For more information, see [Running Gunicorn](https://docs.gunicorn.org/en/stable/run.html) (docs.gunicorn.org). If you're using auto-scale rules to scale your web app up and down, you should also dynamically set the number of gunicorn workers using the `NUM_CORES` environment variable in your startup command, for example: `--workers $((($NUM_CORES*2)+1))`. For more information on setting the recommended number of gunicorn workers, see [the Gunicorn FAQ](https://docs.gunicorn.org/en/stable/design.html#how-many-workers)
295
+
For more information, see [Running Gunicorn](https://docs.gunicorn.org/en/stable/run.html). If you're using auto-scale rules to scale your web app up and down, you should also dynamically set the number of Gunicorn workers using the `NUM_CORES` environment variable in your startup command, for example: `--workers $((($NUM_CORES*2)+1))`. For more information on setting the recommended number of Gunicorn workers, see [the Gunicorn FAQ](https://docs.gunicorn.org/en/stable/design.html#how-many-workers)
298
296
299
297
- **Enable production logging for Django**: Add the `--access-logfile '-'` and `--error-logfile '-'` arguments to the command line:
300
298
@@ -305,7 +303,7 @@ App Service ignores any errors that occur when processing a custom startup comma
305
303
306
304
These logs will appear in the [App Service log stream](#access-diagnostic-logs).
307
305
308
-
For more information, see [Gunicorn logging](https://docs.gunicorn.org/en/stable/settings.html#logging) (docs.gunicorn.org).
306
+
For more information, see [Gunicorn logging](https://docs.gunicorn.org/en/stable/settings.html#logging).
309
307
310
308
- **Custom Flask main module**: By default, App Service assumes that a Flask app's main module is *application.py* or *app.py*. If your main module uses a different name, then you must customize the startup command. For example, if you have a Flask app whose main module is *hello.py* and the Flask app object in that file is named `myapp`, then the command is as follows:
311
309
@@ -327,24 +325,24 @@ App Service ignores any errors that occur when processing a custom startup comma
327
325
328
326
## Access app settings as environment variables
329
327
330
-
App settings are values stored in the cloud specifically for your app as described on [Configure app settings](configure-common.md#configure-app-settings). These settings are available to your app code as environment variables and accessed using the standard [os.environ](https://docs.python.org/3/library/os.html#os.environ) pattern.
328
+
App settings are values stored in the cloud specifically for your app, as described in [Configure app settings](configure-common.md#configure-app-settings). These settings are available to your app code as environment variables and accessed using the standard [os.environ](https://docs.python.org/3/library/os.html#os.environ) pattern.
331
329
332
-
For example, if you've created app setting called `DATABASE_SERVER`, the following code retrieves that setting's value:
330
+
For example, if you've created an app setting called `DATABASE_SERVER`, the following code retrieves that setting's value:
333
331
334
332
```python
335
333
db_server = os.environ['DATABASE_SERVER']
336
334
```
337
335
338
336
## Detect HTTPS session
339
337
340
-
In App Service, [TLS/SSL termination](https://wikipedia.org/wiki/TLS_termination_proxy)(wikipedia.org) happens at the network load balancers, so all HTTPS requests reach your app as unencrypted HTTP requests. If your app logic needs to check if the user requests are encrypted or not, inspect the `X-Forwarded-Proto` header.
338
+
In App Service, [TLS/SSL termination](https://wikipedia.org/wiki/TLS_termination_proxy) happens at the network load balancers, so all HTTPS requests reach your app as unencrypted HTTP requests. If your app logic needs to check if the user requests are encrypted or not, inspect the `X-Forwarded-Proto` header.
341
339
342
340
```python
343
341
if'X-Forwarded-Proto'in request.headers and request.headers['X-Forwarded-Proto'] =='https':
344
342
# Do something when HTTPS is used
345
343
```
346
344
347
-
Popular web frameworks let you access the `X-Forwarded-*` information in your standard app pattern. For example in Django, you can use the [SECURE_PROXY_SSL_HEADER](https://docs.djangoproject.com/en/4.1/ref/settings/#secure-proxy-ssl-header) to tell Django to use the `X-Forwarded-Proto` header.
345
+
Popular web frameworks let you access the `X-Forwarded-*` information in your standard app pattern. For example, in Django you can use the [SECURE_PROXY_SSL_HEADER](https://docs.djangoproject.com/en/4.1/ref/settings/#secure-proxy-ssl-header) to tell Django to use the `X-Forwarded-Proto` header.
348
346
349
347
## Access diagnostic logs
350
348
@@ -360,23 +358,23 @@ Use the following steps to access the deployment logs:
360
358
361
359
1. On the Azure portal for your web app, select **Deployment** > **Deployment Center** on the left menu.
362
360
1. On the **Logs** tab, select the **Commit ID** for the most recent commit.
363
-
1. On the **Log details** page that appears, select the **Show Logs...** link that appears next to "Running oryx build...".
361
+
1. On the **Log details** page that appears, select the **Show Logs** link that appears next to "Running oryx build...".
364
362
365
-
Build issues such as incorrect dependencies in *requirements.txt* and errors in pre- or post-build scripts will appear in these logs. Errors also appear if your requirements file isn't exactly named *requirements.txt* or doesn't appear in the root folder of your project.
363
+
Build issues such as incorrect dependencies in *requirements.txt* and errors in pre- or post-build scripts will appear in these logs. Errors also appear if your requirements file isn't named *requirements.txt* or doesn't appear in the root folder of your project.
366
364
367
365
## Open SSH session in browser
368
366
369
367
[!INCLUDE [Open SSH session in browser](../../includes/app-service-web-ssh-connect-builtin-no-h.md)]
370
368
371
-
When you're successfully connected to the SSH session, you should see the message "SSH CONNECTION ESTABLISHED" at the bottom of the window. If you see errors such as "SSH_CONNECTION_CLOSED" or a message that the container is restarting, an error may be preventing the app container from starting. See [Troubleshooting](#troubleshooting) for steps to investigate possible issues.
369
+
When you're successfully connected to the SSH session, you should see the message "SSH CONNECTION ESTABLISHED" at the bottom of the window. If you see errors such as "SSH_CONNECTION_CLOSED" or a message that the container is restarting, an error might be preventing the app container from starting. See [Troubleshooting](#troubleshooting) for steps to investigate possible issues.
372
370
373
371
## URL rewrites
374
372
375
-
When deploying Python applications on Azure App Service for Linux, you may need to handle URL rewrites within your application. This is particularly useful for ensuring specific URL patterns are redirected to the correct endpoints without relying on external web server configurations. For Flask applications, [URL processors](https://flask.palletsprojects.com/patterns/urlprocessors/) and custom middleware can be used to achieve this. In Django applications, the robust [URL dispatcher](https://docs.djangoproject.com/en/5.0/topics/http/urls/) allows for efficient management of URL rewrites.
373
+
When deploying Python applications on Azure App Service for Linux, you might need to handle URL rewrites within your application. This is particularly useful for ensuring specific URL patterns are redirected to the correct endpoints without relying on external web server configurations. For Flask applications, [URL processors](https://flask.palletsprojects.com/patterns/urlprocessors/) and custom middleware can be used to achieve this. In Django applications, the robust [URL dispatcher](https://docs.djangoproject.com/en/5.0/topics/http/urls/) allows for efficient management of URL rewrites.
376
374
377
375
## Troubleshooting
378
376
379
-
In general, the first step in troubleshooting is to use App Service Diagnostics:
377
+
In general, the first step in troubleshooting is to use App Service diagnostics:
380
378
381
379
1. In the Azure portal for your web app, select **Diagnose and solve problems** from the left menu.
382
380
1. Select **Availability and Performance**.
@@ -410,7 +408,7 @@ The following sections provide guidance for specific issues.
410
408
411
409
- <aname="service-unavailable"></a>**You see the message "Service Unavailable" in the browser.** The browser has timed out waiting for a response from App Service, which indicates that App Service started the Gunicorn server, but the app itself didn't start. This condition could indicate that the Gunicorn arguments are incorrect, or that there's an error in the app code.
412
410
413
-
- Refresh the browser, especially if you're using the lowest pricing tiers in your App Service Plan. The app may take longer to start up when using free tiers, for example, and becomes responsive after you refresh the browser.
411
+
- Refresh the browser, especially if you're using the lowest pricing tiers in your App Service plan. The app might take longer to start up when you use free tiers, for example, and becomes responsive after you refresh the browser.
414
412
415
413
- Check that your app is structured as App Service expects for [Django](#django-app) or [Flask](#flask-app), or use a [custom startup command](#customize-startup-command).
416
414
@@ -420,31 +418,31 @@ The following sections provide guidance for specific issues.
420
418
421
419
-**The log stream shows "Could not find setup.py or requirements.txt; Not running pip install."**: The Oryx build process failed to find your *requirements.txt* file.
422
420
423
-
- Connect to the web app's container via [SSH](#open-ssh-session-in-browser) and verify that *requirements.txt* is named correctly and exists directly under *site/wwwroot*. If it doesn't exist, make site the file exists in your repository and is included in your deployment. If it exists in a separate folder, move it to the root.
421
+
- Connect to the web app's container via [SSH](#open-ssh-session-in-browser) and verify that *requirements.txt* is named correctly and exists directly under *site/wwwroot*. If it doesn't exist, make sure the file exists in your repository and is included in your deployment. If it exists in a separate folder, move it to the root.
424
422
425
423
#### ModuleNotFoundError when app starts
426
424
427
-
If you see an error like `ModuleNotFoundError: No module named 'example'`, then Python couldn't find one or more of your modules when the application started. This error most often occurs if you deploy your virtual environment with your code. Virtual environments aren't portable, so a virtual environment shouldn't be deployed with your application code. Instead, let Oryx create a virtual environment and install your packages on the web app by creating an app setting, `SCM_DO_BUILD_DURING_DEPLOYMENT`, and setting it to `1`. This setting will force Oryx to install your packages whenever you deploy to App Service. For more information, please see [this article on virtual environment portability](https://azure.github.io/AppService/2020/12/11/cicd-for-python-apps.html).
425
+
If you see an error like `ModuleNotFoundError: No module named 'example'`, then Python couldn't find one or more of your modules when the application started. This error most often occurs if you deploy your virtual environment with your code. Virtual environments aren't portable, so a virtual environment shouldn't be deployed with your application code. Instead, let Oryx create a virtual environment and install your packages on the web app by creating an app setting, `SCM_DO_BUILD_DURING_DEPLOYMENT`, and setting it to `1`. This setting will force Oryx to install your packages whenever you deploy to App Service. For more information, see [this article on virtual environment portability](https://azure.github.io/AppService/2020/12/11/cicd-for-python-apps.html).
428
426
429
427
### Database is locked
430
428
431
-
When attempting to run database migrations with a Django app, you may see "sqlite3. OperationalError: database is locked." The error indicates that your application is using a SQLite database for which Django is configured by default rather than using a cloud database such as PostgreSQL for Azure.
429
+
When attempting to run database migrations with a Django app, you might see "sqlite3. OperationalError: database is locked." The error indicates that your application is using a SQLite database, for which Django is configured by default, rather than using a cloud database such as Azure Database for PostgreSQL.
432
430
433
431
Check the `DATABASES` variable in the app's *settings.py* file to ensure that your app is using a cloud database instead of SQLite.
434
432
435
433
If you're encountering this error with the sample in [Tutorial: Deploy a Django web app with PostgreSQL](tutorial-python-postgresql-app.md), check that you completed the steps in [Verify connection settings](tutorial-python-postgresql-app.md#2-verify-connection-settings).
436
434
437
435
#### Other issues
438
436
439
-
-**Passwords don't appear in the SSH session when typed**: For security reasons, the SSH session keeps your password hidden when you type. The characters are being recorded, however, so type your password as usual and press**Enter** when done.
437
+
-**Passwords don't appear in the SSH session when typed**: For security reasons, the SSH session keeps your password hidden when you type. The characters are being recorded, however, so type your password as usual and select**Enter** when done.
440
438
441
-
-**Commands in the SSH session appear to be cut off**: The editor may not be word-wrapping commands, but they should still run correctly.
439
+
-**Commands in the SSH session appear to be cut off**: The editor might not be word-wrapping commands, but they should still run correctly.
442
440
443
-
-**Static assets don't appear in a Django app**: Ensure that you've enabled the [whitenoise module](http://whitenoise.evans.io/en/stable/django.html)
441
+
-**Static assets don't appear in a Django app**: Ensure that you've enabled the [WhiteNoise module](http://whitenoise.evans.io/en/stable/django.html).
444
442
445
443
-**You see the message, "Fatal SSL Connection is Required"**: Check any usernames and passwords used to access resources (such as databases) from within the app.
446
444
447
-
## More resources
445
+
## Related content
448
446
449
447
-[Tutorial: Python app with PostgreSQL](tutorial-python-postgresql-app.md)
450
448
-[Tutorial: Deploy from private container repository](tutorial-custom-container.md?pivots=container-linux)
0 commit comments