Deploy Python with uv
Overview
uv is a modern package and project manager for Python, built in Rust. Clever Cloud provides native uv deployment support as an alternative to the legacy WSGI-based deployment (uWSGI/Gunicorn + Nginx). With uv, your application manages its own HTTP server.
Activation
Native uv deployment activates when both conditions are met:
- A
uv.lockfile exists at the root of your project - The
CC_PYTHON_UV_RUN_COMMANDenvironment variable is set to a valid command
If either condition is missing, the application deploys with the legacy Python backend.
Build phase
During the build phase, dependencies are installed with:
uv sync --locked --no-progress --no-devTo install development dependencies, set ENVIRONMENT=development. The --no-dev flag is then removed.
The uv cache (~/.cache/uv) is included in the build cache to speed up subsequent deployments.
Run phase
The application starts with the command defined in CC_PYTHON_UV_RUN_COMMAND. It must start an HTTP server listening on 0.0.0.0 and the port provided through PORT. Clever Cloud sets PORT to 8080 by default. Use port 9000 when you enable at least one Request Flow middleware.
CC_PYTHON_UV_RUN_COMMAND is executed directly, without shell variable expansion. If the server does not read PORT itself, use its numeric value in the command, for example uv run uvicorn --host 0.0.0.0 --port 8080 myProject.asgi:application.
CC_RUN_COMMAND takes precedence over CC_PYTHON_UV_RUN_COMMAND if both are set.
| Name | Description | Required | Default |
|---|---|---|---|
CC_PYTHON_UV_RUN_COMMAND | Command to start the application, without shell expansion | Yes | - |
CC_RUN_COMMAND | Overrides CC_PYTHON_UV_RUN_COMMAND if set | No | - |
ENVIRONMENT | Set to development to include dev dependencies during build | No | production |
PORT | Port used by your HTTP server | No | 8080 |
Differences with legacy Python deployment
With native uv deployment:
No Nginx, uWSGI, or Gunicorn is involved
Your application manages its HTTP server and listens on the port provided through
PORTCC_PYTHON_MODULEandCC_PYTHON_BACKENDare ignoredRedirection.io, Varnish and custom proxies are configured through Request Flow, not Nginx
Server configuration settings do not apply
Enable health check during deployment
The healthcheck allows you to limit downtimes. Indeed, you can provide Clever Cloud with paths to check. If these paths don’t return a 2xx response code, the deployment fails.
Add one (or several) environment variable as such:
CC_HEALTH_CHECK_PATH=/my/awesome/pathOr
CC_HEALTH_CHECK_PATH_0=/my/awesome/path
CC_HEALTH_CHECK_PATH_1=/my/other/pathThe deployment process checks all paths. All of them must reply with a 2xx response code, such as 200 OK or 204 No Content. Clever Cloud retries with an increasing delay before it marks the deployment as failed, so an application that needs some time to start isn’t rejected on the first attempt.
When no health check path is configured, Clever Cloud requests the root path / and accepts any response code from 200 to 499: a 404 or a 401 means your application is up and answering. For Java applications, the deploy.pingPaths of the clevercloud/*.json file also count as configured paths.
Before any HTTP request, Clever Cloud checks that a service listens on the public port, 8080, on a public interface. Depending on your configuration, it’s your application, the port Docker maps from CC_DOCKER_EXPOSED_HTTP_PORT, or the first Request Flow middleware. A service on this port bound only to localhost or 127.0.0.1 makes the deployment fail with Your application is listening on localhost instead of publicly: listen on 0.0.0.0 instead.
On runtimes supporting Request Flow, when middleware runs in front of your application, Clever Cloud also checks that each middleware port and your application port are listening. With CC_REQUEST_FLOW="block", Clever Cloud only checks the service answering on the public port, not your application.
Example
With the preceding paths, here are the logs of a failing health check:
Checking public port (8080) is listening as expected
Response from GET /my/awesome/path is 200 (within expected range 200...300)
Response from GET /my/other/path is 500, expected 200...300
Error while checking /my/awesome/path, /my/other/pathIn this example, the first path is OK, but the second one failed. This gives you a hint on what failed in your application.
Best practice for healthcheck endpoints
To make the most of a healthcheck endpoint, have it check your critical dependencies. For example:
- execute
SELECT 1 + 1;on your database - retrieve a specific Cellar file
- ping a specific IP through a VPN
Request Flow: Varnish, Redirection.io, OAuth2 Proxy, custom proxy
Request Flow automatically chains reverse proxies between port 8080 (public) and your application, allocating middleware ports automatically. Some services are detected from your configuration, while others must be listed explicitly in CC_REQUEST_FLOW:
- Otoroshi Challenge: set
OTOROSHI_CHALLENGE_SECRET - Varnish: add a
clevercloud/varnish.vclfile or setCC_VARNISH_FILE - Redirection.io: set
CC_REDIRECTIONIO_PROJECT_KEY - OAuth2 Proxy: set
CC_REQUEST_FLOW=oauth2-proxyand itsOAUTH2_PROXY_*settings
Multiple services can run simultaneously. Setting CC_REQUEST_FLOW replaces automatic detection, so list every service you need in order (e.g. oauth2-proxy,varnish). To add a custom middleware, include custom in the chain and define CC_REQUEST_FLOW_CUSTOM with @@LISTEN_PORT@@ and @@FORWARD_PORT@@ placeholders. To block public access, set CC_REQUEST_FLOW=block.
If your application manages its own HTTP server, configure it to listen on port 9000 instead of 8080 when at least one middleware is active. Clever Cloud handles this automatically for runtimes with a managed web server.