DeployxaDocs Portal
CLI v1.0.4
Deploy Flask App
Framework guide · Flask

Deploy a Flask app

Flask's built-in server is for development. On Deployxa, run the WSGI app with Gunicorn behind HTTPS, with your configuration in environment variables and an optional managed database.

Prerequisites

  • Flask 3 and gunicorn in requirements.txt.
  • An importable WSGI object, for example app = Flask(__name__) in app.py, or a create_app() factory.

How Deployxa detects Flask

requirements.txt marks a Python project. Pick the Flask preset (or Python / Gunicorn) and set the start command; the generic Python default is python app.py, which would run the development server.

SettingValue
Build commandpip install -r requirements.txt
Start commandgunicorn app:app --bind 0.0.0.0:8000 --workers 2
Port8000

Required config

python
# app.py
import os
from flask import Flask, jsonify
from werkzeug.middleware.proxy_fix import ProxyFix

app = Flask(__name__)
app.config["SECRET_KEY"] = os.environ["SECRET_KEY"]
# HTTPS terminates at the proxy: trust one hop of X-Forwarded-* headers
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1)

@app.get("/health")
def health():
    return jsonify(ok=True)

@app.get("/")
def index():
    return jsonify(message="Hello from Flask on Deployxa")

With an application factory, point Gunicorn at it: gunicorn "app:create_app()" --bind 0.0.0.0:8000. If you leave out --bind, Gunicorn listens on 0.0.0.0:$PORT when a PORT variable is set, and on 127.0.0.1:8000 otherwise, so be explicit.

Tip: Two to four workers is a good start for a small instance. For I/O-heavy apps add threads (--threads 4) rather than many workers, and use --timeout 60 if some requests are slow.

Environment variables

KeyPurposeExample
SECRET_KEYSession and CSRF signinga long random string
DATABASE_URLInjected when a database is attachedpostgresql://…
FLASK_DEBUGLeave unset (or 0) in production0

Databases

In the wizard's Configure step, set Database to PostgreSQL. The connection string is injected into the app as DATABASE_URL, so nothing needs to be committed. Choose SQLite only for small apps: it lives on a persistent volume and has no server.

python
# with Flask-SQLAlchemy and psycopg 3
from flask_sqlalchemy import SQLAlchemy

url = os.environ["DATABASE_URL"].replace("postgres://", "postgresql+psycopg://", 1)
url = url.replace("postgresql://", "postgresql+psycopg://", 1)
app.config["SQLALCHEMY_DATABASE_URI"] = url
app.config["SQLALCHEMY_ENGINE_OPTIONS"] = {"pool_pre_ping": True}
db = SQLAlchemy(app)

With Flask-Migrate, upgrade before Gunicorn starts: sh -c 'flask --app app db upgrade && gunicorn app:app --bind 0.0.0.0:8000'.

Deploy

From the dashboard

  1. 1
    Source

    Open Dashboard → Projects → New project (/dashboard/projects/new). Pick the GitHub repository and branch, or upload a .zip archive of the project.

  2. 2
    Configure

    Leave the framework preset on Auto-detect or choose Flask. Check the fields under advanced settings:

    • Build command: pip install -r requirements.txt
    • Root directory: ./, or the sub-folder that holds the app in a monorepo
    • Database: PostgreSQL or MySQL if needed
  3. 3
    Environment

    Add your variables in the table, or paste a whole .env file into the Bulk / .env tab.

  4. 4
    Deploy

    Start the deploy and watch the build log. When the release passes its health check it is served over HTTPS on its Deployxa URL.

  5. 5
    Confirm the start command and port

    Open the project's Environment Canvas tab and select the web service. Set Start Command to gunicorn app:app --bind 0.0.0.0:8000 --workers 2. Set Internal Port to 8000 so it matches the port your app listens on. Save and redeploy if you changed anything.

From the CLI

shell
$ npm install -g @deployxa/cli
$ deployxa login
$ cd my-app
$ deployxa link            # pick an existing project, or skip: deploy creates one
$ deployxa env set SECRET_KEY "change-me"
$ deployxa deploy
$ deployxa logs --live     # stream build and runtime logs
$ deployxa open            # open the live URL

If the folder is not linked, deployxa deploy creates a project named after the folder and links it (the link is saved in .deployxa/config.json). Later runs deploy the linked project. deployxa status shows the latest deployment and deployxa rollback previous returns to the release before it.

Warning: deployxa deploy packages the folder exactly as it is on disk; it does not read .gitignore. Delete local node_modules, virtualenvs, build output and real .env files first, or deploy from a clean clone. Set secrets with deployxa env set instead of shipping them in the archive.

Custom domain

Go to Dashboard → Domains, choose Connect a domain you already own and pick this project. Deployxa then shows the DNS records to create at your DNS provider:

RecordUse it forValue
AAn apex domain such as example.com85.17.244.184 (DNS only on Cloudflare)
CNAMEA subdomain such as www or appcname.deployxa.com (DNS only on Cloudflare)
TXTOnly when a CDN or proxy (for example Cloudflare orange-cloud) hides the origin recordHost _deployxa-challenge.<your-domain>, value deployxa-verification=…

DNS changes can take several minutes to propagate; use Retry verification once they have. A Let's Encrypt certificate is issued after the domain verifies. From a linked folder you can do the same with the CLI:

shell
$ deployxa domains add app.example.com
$ deployxa dns             # Waiting → Verified → SSL Active
$ deployxa domains list

Common errors and fixes

SymptomFix
Health check fails; log shows "Running on http://127.0.0.1:5000"The development server started. Set the start command to Gunicorn with --bind 0.0.0.0:8000.
gunicorn: command not foundAdd gunicorn to requirements.txt.
Failed to find attribute 'app' in 'app'Point Gunicorn at the right object: module:variable or "module:create_app()".
WORKER TIMEOUT in logsA request ran past 30 seconds. Raise --timeout or move the work to a background worker.
url_for builds http:// linksWrap the app in ProxyFix as shown above.

Start with deployxa logs --live (or the deployment's log view in the dashboard): the build log shows dependency and compile failures, the runtime log shows crashes and bind errors. See also Troubleshooting.