How to host a Python app or script

To host a Python app, you need a server with the right Python version, your dependencies installed and a start command. The port and secrets should come from environment variables.

Updated 5 min read

Learning objectives

After reading this article you will be able to:

  • Prepare a Python project to run outside your machine
  • Write a script and an API that read config from the environment and shut down cleanly
  • Verify the deploy and fix the most common errors
On this page

A Python app works on your machine because that machine has the right Python, the installed libraries and the variables you configured. Hosting means reproducing that environment on a server that stays on all the time.

There are two common cases. A script does work without receiving visitors: a bot, a data collector, a scheduled task. An API listens on a port and answers requests. The steps are the same for both, with one difference: only the API needs a port. For the big picture, see what is deployment.

1Local projectmain.pyrequirements.txt.gitignoreUpload to the serverno .venv or .env2Dependencies in a venvpip install -rrequirements.txt3Python process0.0.0.0 on the port in PORT4os.environenvironment variables
Upload the code and requirements.txt, rebuild the venv on the server and start Python reading its config from the environment.

What do you need before hosting?#

  • A defined Python version. Use the same one locally and in production.
  • A requirements.txt with your dependencies and their versions.
  • A main file (here, main.py) that starts everything.
  • A place to run it: a VPS, a container or a hosting platform. The difference is covered in VPS vs cloud platform.

Which version? For a new project, prefer a Python version in bugfix status, as long as all your dependencies already publish packages for it. Older versions move to security fixes only and then reach end of life. The official release schedule shows the status of each version.

How do you set up the project with a venv?#

A venv is an isolated environment for this project only, which keeps one app's libraries from clashing with another's.

bash
mkdir my-app && cd my-app
python -m venv .venv
source .venv/bin/activate        # Windows (PowerShell): .venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install fastapi uvicorn
python -m pip freeze > requirements.txt

pip freeze writes the installed versions to requirements.txt. On the server, python -m pip install -r requirements.txt recreates the same environment. That is why the .venv folder is not uploaded: it holds absolute paths and is not portable. Add .venv/ and .env to .gitignore.

How do you write a script that runs non-stop?#

A long-running script has to read its config from the environment, survive an isolated error and stop cleanly when the server asks. That request arrives as the SIGTERM signal, on restarts and deploys.

python
import os
import signal
import sys
import time
import urllib.request

stopping = False


def handle_stop(signum, frame):
    global stopping
    stopping = True


signal.signal(signal.SIGTERM, handle_stop)
signal.signal(signal.SIGINT, handle_stop)

API_URL = os.environ.get("API_URL")
if not API_URL:
    sys.exit("API_URL is not set")
INTERVAL = int(os.environ.get("INTERVAL_SECONDS", "60"))


def job():
    with urllib.request.urlopen(API_URL, timeout=10) as response:
        print(f"status {response.status}", flush=True)


while not stopping:
    try:
        job()
    except Exception as exc:  # an isolated error does not kill the process
        print(f"job failed: {exc}", flush=True)
    for _ in range(INTERVAL):  # sleep in 1-second steps to notice SIGTERM quickly
        if stopping:
            break
        time.sleep(1)

print("shutting down", flush=True)

What each part does:

  • os.environ: the URL and interval come from the environment, not the code. If API_URL is missing, the script fails immediately with a clear message.
  • stopping: the handler only flips a variable, and the main loop does the shutdown. The wait runs in 1-second steps, so the script notices SIGTERM within a second, even with a long interval.
  • flush=True: when output is not a terminal, Python buffers print and logs arrive late. Running with python -u or setting PYTHONUNBUFFERED=1 has the same effect.

Test locally with API_URL=https://example.com python main.py. For tasks that run at fixed times, see what is a cron job.

How do you host a Python API?#

An API needs an ASGI server. The most common one with FastAPI is Uvicorn. The minimal app:

python
from fastapi import FastAPI

app = FastAPI()


@app.get("/health")
def health():
    return {"status": "ok"}

Start it with:

bash
uvicorn main:app --host 0.0.0.0 --port "${PORT:-8000}"

Two details matter in production. First, --host 0.0.0.0: the default listens only on 127.0.0.1, so nothing outside the container or machine can reach the app. Second, the port comes from the PORT variable when the platform sets it, with 8000 as the development default.

To compare the frameworks, see how to host FastAPI, Flask and Django. What to review before going public is in the API production checklist.

How do you handle environment variables and secrets?#

Tokens, database passwords and API keys live in environment variables, never in the repository. Locally, use a .env file kept out of Git and export the variables before running, or use python-dotenv. In production, set each one in your provider's dashboard. The full pattern is in what are environment variables.

How do you check that it worked?#

  1. Logs: they should show the script starting or Uvicorn listening, with no traceback after it.
  2. Request: call /health on the public address and expect {"status":"ok"}.
  3. Restart: restart the app and confirm it comes back on its own and that SIGTERM prints the "shutting down" line.

What are the most common errors?#

  • ModuleNotFoundError: No module named 'fastapi': the dependency was not installed or is not in requirements.txt. Run pip freeze again with the venv active.
  • Error installing or compiling a package: the server's Python version differs from your local one, and the library has no prebuilt package for it yet. Align the versions.
  • App starts but the site won't open: the server listens on 127.0.0.1 or on a fixed port. Use 0.0.0.0 and the port from the environment.
  • Empty or delayed logs: output buffering. Use flush=True or PYTHONUNBUFFERED=1.
  • Works locally, crashes in production: a missing environment variable or not enough memory. Compare the two environments. For memory, see RAM and CPU sizing.
  • The script dies and stays dead: nothing restarts it. Use a server or container with a restart policy. To package it, see how to dockerize an app.

How to do this on Square Cloud#

The two cases in this guide become two kinds of application on Square Cloud. You upload the project as a ZIP in the dashboard, with the CLI, through GitHub (a push triggers the deploy) or with the VS Code extension, and at start the platform runs pip install -r requirements.txt, the same file you generated in the venv. The install output shows up in the logs, so a ModuleNotFoundError tells you right away which package is missing. The squarecloud.app file is optional: the dashboard generates it on deploy.

The script runs as a background application, with no subdomain: the deploy form detects main.py, and the process uses from 256 MB of the plan's RAM and receives no inbound traffic. The API is a web application, with at least 512 MB and a *.squareweb.app subdomain with HTTPS. Since a FastAPI main.py only defines app, fill in the start command with uvicorn main:app --host 0.0.0.0 --port $PORT; the platform sets the PORT variable.

API_URL and INTERVAL_SECONDS go in as the application's environment variables in the dashboard, which also imports a .env; they already exist during the install and apply on the next restart. The container stays on, and automatic restart, on by default for dashboard deploys, brings the process back when it exits with an error. Running out of memory, by contrast, stops the app until you raise its RAM. Keep flush=True or PYTHONUNBUFFERED=1 so every line reaches the real-time logs.

The plan's RAM is a shared pool: on Hobby, which starts at R$12.49 per month with 1 GB, a script with 256 MB and an API with 512 MB fit together. Python is one of several runtimes, alongside Node.js, Go and Java: see the runtimes available today on Runtimes and the details of the Python runtime.

API hosting

APIs in always-on containers, with no cold starts

Learn more

FAQs

Which Python version should I use in production?

Use a Python version in bugfix status that your libraries accept. The official Python release schedule shows the status of each version; check it before you pin one in your project.

Should I upload my venv folder with the code?

No. A venv stores absolute paths and depends on the operating system. Upload the code and requirements.txt and let the server recreate the environment with pip install -r requirements.txt.

How do I keep a Python script running 24/7?

Put the script in a loop that waits between runs and run it on a server or container that restarts the process if it crashes. If it depends on your computer, it stops when the computer turns off.

Do I need a web server to host a script?

No. A script that only does work, such as a bot or a data collector, does not need to open a port. Only APIs and sites need to listen on one.

Next articleWhat is a cron job? Syntax and examplesA cron job is a task that runs on its own at times set by a five-field expression. Learn the syntax, examples, common mistakes and how to schedule jobs in Node.js.