Install dependencies
Cloud installs your application’s dependencies automatically during the build. To decide how, it looks for the following files in order and uses the first one it finds:
You should list your production server, such as Gunicorn or Uvicorn, among these dependencies. When Cloud exports dependencies from a lockfile, it leaves out your development groups, so only what your application needs in production is installed. Packages are installed into a shared Python user directory, and their executables are added to your
PATH, so you can call gunicorn or uvicorn directly from your start command.
Run a production server
Django and Flask applications use the Web Server Gateway Interface (WSGI) by default, while FastAPI applications use the Asynchronous Server Gateway Interface (ASGI). Cloud discovers your application’s entrypoint and pre-fills a start command using a compatible server from your dependencies. Cloud knows how to generate commands for each of the following servers:
Cloud also recognizes Django projects that are configured for ASGI, as well as application factories in Flask and FastAPI projects.
If none of these servers appear in your dependencies, Cloud falls back to Gunicorn for WSGI applications or Uvicorn for ASGI applications and pre-fills a
pip install --user step in your build command to install it. That said, we recommend adding the server to your own dependencies so you stay in control of which version is installed.
Your start command should always use a production server. Django’s runserver, flask run, and reload modes such as fastapi dev or uvicorn --reload are great for development, but they shouldn’t be used to run your application in production.
Bind to the right interface
Your server must listen on the port set by thePORT environment variable, which is 3000 by default. It must also accept IPv6 connections, since that is how Cloud’s proxy and startup probes reach your application. The pre-filled Gunicorn command already takes care of this with --bind [::]:$PORT. If you are using Uvicorn, your start command should look like this:
main:app with your own application’s entrypoint. If your application is created by a factory, be sure to keep the --factory flag.
Cloud may pre-fill Uvicorn’s host as
--host ''. When Uvicorn runs multiple workers, it uses an IPv4 socket for this value, which Cloud can’t reach. Change it to --host :: so your application stays reachable as your worker count grows.Worker count
Cloud sets theWEB_CONCURRENCY environment variable based on the resources allocated to your app instance. Django and Flask applications receive (2 × whole CPU cores) + 1 workers, capped so that each worker has a 150 MiB memory budget. FastAPI applications receive one worker per whole CPU core. Either way, your application always receives at least one worker.
Gunicorn and Uvicorn read WEB_CONCURRENCY automatically. If you are using another server, you will need to set its worker count option yourself. To change the number of workers, you may override WEB_CONCURRENCY in your environment variables or pass your server’s worker count flag directly. If your application uses a lot of memory per worker, you may want to lower the count.
Shut down gracefully
When an instance stops, whether during a deployment or while scaling down, Cloud sends aSIGTERM signal to your server. Gunicorn and Uvicorn both handle this signal gracefully by letting active requests finish before exiting.
You should keep your server’s shutdown deadline shorter than your environment’s graceful shutdown timeout so the rest of the instance has time to stop cleanly. Gunicorn’s --graceful-timeout option defaults to 30 seconds, while Uvicorn provides a --timeout-graceful-shutdown option. If your requests need more time to complete, adjust both your server’s deadline and your environment’s timeout.
Running behind the proxy
Cloud handles TLS for you before forwarding requests to your application, so your server only needs to speak plain HTTP. Along the way, Cloud’s proxy passes along the original request scheme in theX-Forwarded-Proto header and the client’s address chain in the X-Forwarded-For header. Before relying on these headers, you should configure your server’s or framework’s trusted proxy settings.
For Django, add the following to your settings.py file so that request.is_secure() correctly recognizes HTTPS requests that arrive through Cloud’s proxy:
Django environment variables
New Django environments include a securely generatedSECRET_KEY, which you are free to edit. If Cloud can discover your settings module in your repository, it will also set DJANGO_SETTINGS_MODULE for you.
In addition, Cloud provides DEBUG=false, along with comma-separated ALLOWED_HOSTS and CSRF_TRUSTED_ORIGINS values based on your environment’s active domains. However, Django doesn’t read these variables on its own, so you will need to add the following to your settings.py file:
ALLOWED_HOSTS contains plain hostnames, while CSRF_TRUSTED_ORIGINS includes the https:// scheme. You may override any of these variables in your environment settings, but you should always keep debug mode disabled in production.
Databases and caches
When you attach a database or cache from the infrastructure canvas, Cloud injects aDATABASE_URL (postgresql://... or mysql://...) or REDIS_URL (rediss://...) variable into your application’s environment. You may read these values from os.environ.
Django doesn’t read DATABASE_URL on its own, but the dj-database-url package makes it easy. Add it to your dependencies along with the appropriate database driver, then configure your database like so:
rediss:// scheme:
Migrations
Database migrations belong in your environment’s deploy commands. Cloud runs these commands just before your new deployment goes live. If one of them fails, Cloud cancels the rollout. New Django environments start with a migration command that is commented out. When you connect a database, Cloud enables it for you automatically, as long as you haven’t customized your deploy commands. If you have, simply add the migration step yourself:alembic upgrade head or flask db upgrade, respectively.
Static files
Django
Cloud provides the following environment variables to Django applications, both during the build and while your application is running:settings.py file, using your project’s existing BASE_DIR:
collectstatic command to your build commands so your assets are collected into STATIC_ROOT:
STATIC_ROOT setting or a WhiteNoise dependency. If your build commands don’t include it, simply add it alongside your existing commands. Running it during the build ensures the collected files are included in your deployment.
With these defaults in place, Cloud’s Nginx server serves your collected files under /static/ on your application’s domain, as long as you are using Django’s local static file storage. For example, css/app.css will be available at https://your-app.laravel.cloud/static/css/app.css. There’s no need for object storage with this setup.
If you would like to change either value, you may override these variables in your environment’s environment variables. Since Cloud serves files from /var/www/html/public, a different URL prefix needs to match the directory layout. For example, you could use STATIC_ROOT=/var/www/html/public/assets with STATIC_URL=/assets/.
To serve files from outside the public directory, you may configure WhiteNoise to serve them through your application, or use a Django storage backend for object storage. Keep in mind that changing these environment variables won’t reconfigure Nginx or upload your files to object storage for you.
Flask and FastAPI
The environment variables described in the previous section only apply to Django. Flask serves itsstatic directory at /static by default, while FastAPI requires you to mount a directory using StaticFiles. Neither framework needs any additional environment variables to serve static files.
