Listen on the right port
Cloud routes traffic to your application on the port set by thePORT environment variable, which is 3000 by default. Your application should read this value and listen on the IPv6 wildcard address, :::
:: accepts both IPv6 and IPv4 connections. This matters because Cloud’s startup probes reach your application over IPv6. If you bind to 0.0.0.0 or 127.0.0.1, Cloud won’t be able to reach your application and the deployment will fail its startup probe. Actix Web accepts the same address as a string, for example .bind(("::", port)).
Rocket reads its own ROCKET_ADDRESS and ROCKET_PORT variables rather than PORT. Cloud sets both for you, so a Rocket application only needs to use its default configuration.
If your application deploys successfully but still isn’t reachable, take a look at the deployment troubleshooting guide.
Compile during the build
Cloud detects your application from theCargo.toml file at the root of your repository and recognizes axum, Actix Web, Rocket, and warp from your dependencies. Cloud downloads your crates automatically and pre-fills the following build command:
/var/www/bin and adds that directory to your PATH. Cloud leaves the compiled build directory out of the image that runs your application, which keeps your instances small and quick to start. Of course, you’re free to edit the build command if your application has any additional requirements.
Cloud detects which binary to run from your Cargo.toml and sets the start command when you create your environment. Cloud chooses the binary named by default-run, then the one built from src/main.rs, then the only binary if there is just one. If none of these apply, Cloud runs the first executable it finds in /var/www/bin, sorted alphabetically. To be explicit, set default-run in your manifest before you create the environment:
default-run later, update your environment’s start command to match, for example my-app.
Each environment keeps its compiled output between builds, so a binary you have renamed or removed may remain in /var/www/bin and on your PATH. Naming your binary in the start command, rather than relying on the alphabetical fallback, keeps Cloud from running a stale one.
Since your binaries are on the PATH, you may refer to them by name in your start command, deploy commands, and background processes. For example, if your application builds both a my-app and a migrate binary, you may run my-app serve or migrate without spelling out the full path.
By compiling in your build commands, your application starts quickly when a new instance boots or when your environment wakes up after scaling to zero, since there’s nothing left to compile.
Cloud caches your downloaded crates and compiled dependencies between builds of the same environment, so later builds can recompile only what changed. The cache is best effort, so an occasional build may start from scratch. To make the most of it, you should commit your Cargo.lock file.
Release builds can take a while on larger applications. Build commands must complete within 15 minutes, so you may want to tune your release profile for compile time if you approach that limit.
Build commands run without root privileges, so you may not install system packages with
apt-get. When a crate offers a choice, prefer pure Rust options, such as rustls instead of OpenSSL.Rust versions
Cloud builds your application with a recent stable Rust release, and there is no version setting to manage. If you need a specific toolchain, pin it with arust-toolchain.toml file at the root of your repository. The rustup tool installs the pinned toolchain during your build:
Shut down gracefully
When an instance stops, whether during a deployment or while scaling down, Cloud sends aSIGTERM signal to your process. To avoid cutting off requests that are still in progress, your application should handle this signal and wait for those requests to finish before exiting. Note that tokio::signal::ctrl_c only listens for SIGINT, so you should also listen for SIGTERM. If you are using axum, you may use the following function with with_graceful_shutdown:
SIGTERM. For warp, pass the same shutdown_signal future to bind_with_graceful_shutdown. You should keep your application’s shutdown timeout shorter than your environment’s graceful shutdown timeout (30 seconds by default) so the rest of the instance has time to stop cleanly, since Cloud will terminate any process that is still running once that timeout has passed. Actix Web also waits 30 seconds by default, so lower it with HttpServer::shutdown_timeout.
Logging
Anything your application writes to standard output or standard error, including panic messages, appears in your environment’s logs. The tracing-subscriber crate writes to standard output by default, so a single line of setup is enough:json feature of tracing-subscriber and call .json() on the builder.
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 to determine the request scheme or client IP address, you should configure your framework or middleware to trust them only when a request comes through Cloud’s proxy. In general, you should avoid trusting forwarded headers from arbitrary sources, since clients can set them to any value they like.
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 with std::env::var.
For Postgres and MySQL, sqlx accepts the connection URL as is. Enable the runtime-tokio and tls-rustls features, along with the feature for your database (postgres or mysql):
rediss:// scheme, provided you enable its tokio-rustls-comp feature:
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. If you use sqlx, you may embed your migrations in a small binary that lives alongside your application atsrc/bin/migrate.rs, so there’s no extra tooling to install. It needs sqlx’s migrate and macros features, and this example uses Postgres. For MySQL, use sqlx::MySqlPool instead:
PATH, your deploy command is:

