Skip to main content

Deploy Python Apps

Python installation is powered by pyenv. To install stable (latest - 1) version with deployment script:

features:
- python

Without this, you're using OS-dependent python and pip which the version can't be customized.

Install other version using python latest, python stable, python 3.10, node 3.10.1, etc. To uninstall use python off or python system (the latter leaves pyenv installed). Check the current version using python --version from SSH.

Example

The deployment script below installs the latest python compiler and writes app.py and serves that through WSGI bindings.

https://github.com/domcloud/recipes/blob/master/python.yml
source: clear
features:
- python latest
nginx:
root: public_html/public
passenger:
enabled: "on"
startup_file: app.py
app_type: python
python: .pyenv/shims/python
commands:
- filename: app.py
content: |
import platform

html_text = '''
<!DOCTYPE html>
<html>
<head>
<title>Python App</title>
<link rel="stylesheet" href="%s">
</head>
<body class="p-5 text-center">
<p><img src="%s" class="img-fluid rounded-circle"></p>
<h1 class="mb-3">Hello, world!</h1>
<p>Serving from Python version %s</p>
<p class="text-muted">DOM Cloud</p>
</body>
</html>
''' % (
'//unpkg.com/bootstrap/dist/css/bootstrap.min.css',
'//images.unsplash.com/photo-1465153690352-10c1b29577f8?fit=crop&w=200&h=200',
platform.python_version(),
)

def application(environ, start_response):
status = '200 OK'
response_headers = [('Content-type', 'text/html')]
start_response(status, response_headers)
return [html_text.encode('utf-8')]

Existing Python projects

For existing python apps, use the deployment script below. Note the WGSI file name (app.py). It's recommended to have requirements.txt so you don't have to install depedencies manually.

https://github.com/domcloud/recipes/blob/master/python-wsgi.yml
features:
- python latest
nginx:
root: public_html/public
passenger:
enabled: "on"
startup_file: app.py
app_type: python
python: .pyenv/shims/python
commands:
- test -f requirements.txt && pip install -r $_
https://github.com/domcloud/recipes/blob/master/python-uvicorn.yml
features:
- python latest
nginx:
root: public_html/public
passenger:
enabled: "on"
app_start_command: uvicorn main:app --port $PORT
commands:
- test -f requirements.txt && pip install -r $_ || pip install uvicorn

Other deployment scripts we offer also listed below.

The GLS binding is the basic for any custom web server either for Python and other code languages. The requirement to use this is your app must listen to given PORT env/args (either python ... --port=$PORT or env PORT=$PORT python ...)

https://github.com/domcloud/recipes/blob/master/python-gls.yml
features:
- python latest
nginx:
root: public_html/public
passenger:
enabled: "on"
app_start_command: python app.py
commands:
- test -f requirements.txt && pip install -r $_

Installing depedencies

Installing python depedencies can be tricky and easily overlooked. We have system-wide installation of pip and pipenv. When python feature is installed, pyenv will be available to shim python and pip to your terminal profile. When changing python version using pyenv, the python interpreter will be installed to .pyenv/shims/python.

When installing with pipenv all depedencies are installed within a custom virtualenv. You shouldn't have to use python feature at all because pipenv already does it for you. To run the customized python and it's pip installation in NGINX use env PORT=$PORT pipenv run python app.py in app_start_command.

App Management

Your app do not restarted automatically after file changes. To restart, run restart via SSH.

Environment variables can be set either using NGINX's env_var_list or ~/.bashrc. Usually your language framework also reads .env files.

See NGINX and App Daemon for more information about NGINX and App managements including restarting, environment variables, and other global limitations.

App Logging

You can see app log from Check -> Check Process Logs tab. Only startup problems displayed in the browser.

You might want to use a proper logging mechanism such as the standard logging library then write it to a log file, or any other solution that suits you.

NGINX errors and traffic logs can be examined via Webmin or Check -> Check Process Logs tab.

Troubleshooting

ldpython: -lpython3.x not found during installing Pip Packages

We use prebuilt python binaries where it doesn't have libpython3.x.a, which is a library for statically linking python. This is known for some packages like uwsgi.

The solution is try reinstalling python, but with exact version down to three digits:

features:
- python 3.12.1

This way your python will be compiled from source by pyenv and libpython3.x.a will be available.

Code won't update unless __pycache__ files gone

We recommend setting PYTHONDONTWRITEBYTECODE=1 to avoid this problem.

nginx:
root: public_html/app/static
passenger:
enabled: "on"
app_env: development
app_root: public_html
app_type: python
startup_file: server.py
python: .pyenv/shims/python
env_var_list:
- PYTHONDONTWRITEBYTECODE=1

Delete all __pycache__ folders with this command and do restart.

find ~/public_html -name "__pycache__" -type d -exec rm -r {} +

502 Bad Gateway

This is NGINX freshly restart and it seems too expensive to start your process in time. Please use Proxfix NOHUP to solve this issue.