Python (generic) on CloudMagnus

A bare Python site with a virtualenv and an allocated upstream port. Bring your own framework.

What our scaffold installs

  • A virtualenv at /home/<siteUser>/venv/, owned by your site user
  • A placeholder htdocs/requirements.txt with comments
  • A placeholder htdocs/app.py implementing a minimal WSGI app that returns "Python site ready on port <X>"
  • An allocated port from the 8000-8999 pool, unique per site, shown on the site detail page
  • nginx vhost reverse-proxying your domain to 127.0.0.1:<allocatedPort>
  • No database. Generic Python doesn't get one because we don't know whether you'd want Postgres or MySQL or none. Contact support if you need one.

What you do next

  1. SSH in.
  2. Activate the venv: source ~/venv/bin/activate.
  3. Install your dependencies: edit htdocs/requirements.txt, then pip install -r htdocs/requirements.txt.
  4. Replace app.py with your real WSGI/ASGI app.
  5. Run a server (gunicorn, uvicorn, etc.) listening on 127.0.0.1:<allocatedPort>.

Running gunicorn

For a WSGI app: ~/venv/bin/gunicorn --bind 127.0.0.1:<port> app:app. The port is shown on your site detail page.

For ASGI (async): ~/venv/bin/uvicorn --host 127.0.0.1 --port <port> app:app.

Neither is preinstalled in the venv; install them with pip.

Process management

Same story as Node generic: you keep gunicorn (or uvicorn, or whatever) running. Use nohup for the simplest case, or install a process manager like supervisor per-site.

Python version

The scaffold uses the system python3 (currently 3.12 on our hosts). Other versions aren't currently selectable through the wizard.

Common Python issues

502 Bad Gateway

Gunicorn isn't running, or it's bound to the wrong port. Check the process: ss -tnlp | grep <port>.

"ModuleNotFoundError"

Either you haven't activated the venv, or the package isn't installed in it. ~/venv/bin/pip list shows what's there.

Static files not served

Python web servers don't serve static files by default. Either configure your framework to serve them (Django's collectstatic, Flask's static_folder) or upload static assets to htdocs/static/ and let nginx serve them directly (contact support for the vhost config tweak).