Rust-native · Bring your own AWS

Ship your Rust binary to your own EC2 servers

Cross-compiles to a lean executable, runs as a systemd service. No container runtime, no managed-cloud tax. Your AWS account, your data, our orchestration.

Not on Rust? Python and static sites deploy the same way →

~10 min
Time to deploy, once connected
Native
Binary, not a container image
$0
Markup on AWS costs
Your account
All infra stays in your AWS

Own your AWS without it feeling like ops

Connecting your AWS account takes more setup than a managed cloud, but you get infra that's actually yours. Here's how we keep that setup from becoming ongoing friction.

1

Connect AWS

Run cumulus aws connect to grant a scoped cross-account role. One CloudFormation template. Done once per account.

2

Add a config

Drop a cumulus.toml in your repo root. Pick your runtime and target. Most defaults are sensible.

3

Deploy

Run cumulus app deploy. Cumulus builds your app on an ephemeral Fargate task in your account, uploads the artifact, and runs a health-gated deploy with automatic rollback.

4

Auto-deploy on push

Connect your GitHub repo. Every push to your deploy branch builds, deploys, and streams logs to your dashboard.

A Rust API running natively on EC2

One config file. No Dockerfile to maintain. Cumulus builds your binary on an ephemeral Fargate task in your own AWS account. The output is a stripped executable deployed as a systemd service.

cumulus.toml
# Drop this in your repo root
[project]
name   = "my-api"
region = "us-east-1"

[[app]]
name    = "api"
runtime = "rust"
target  = "ec2"
binary  = "my_api"
server  = "prod-1"

[app.health_check]
path = "/health"   # probed before cutover;
port = 8080        # a non-2xx rolls back

[app.env]
# Resolved from SSM at deploy, never baked into the artifact
DATABASE_URL = { secret = "/my-api/DATABASE_URL" }
Terminal
# Install the CLI
$ curl -fsSL https://cumulus.collectif.dev/install.sh | sh

# Sign in (opens your browser)
$ cumulus login

# Connect your AWS account (once)
$ cumulus aws connect

# Provision a server
$ cumulus server create prod-1

# Register the project + apps from cumulus.toml
$ cumulus link

# Store the secret in SSM, encrypted with your KMS key
$ cumulus app env-set my-api/api DATABASE_URL="postgres://…" --secret

# Deploy (defaults to the current commit)
$ cumulus app deploy my-api/api
Deploy output
→ deploying `api` (Rust → EC2)  [env: production]
pre-flight passed
building on Fargate (arm64)…
artifact uploaded
agent installed the systemd service
health check passed (200 /health)
cut over, zero downtime
decommissioned old release
✓ deployed `api` to `prod-1`
For Rust developers

Moving off Shuttle?

Shuttle.rs closed its Pro tier in January 2026. If you're looking for a permanent home for your Rust backend, Cumulus is the natural migration path, and you end up with more durable infrastructure than you started with.

Your service runs as a native binary under systemd on an EC2 instance in your own AWS account. No managed-cloud dependency, no container overhead, no vendor-specific framework required. Bring your existing Axum, Actix, or any other Rust web service as-is.

Prefer serverless? The same Rust binary deploys to AWS Lambda instead. It runs on Graviton (arm64) or x86_64, behind a Function URL, with instant rollback to any previous version.

And if Cumulus ever shut down tomorrow, your API would still be serving traffic. The EC2 instance and the systemd service are yours, and they have no runtime dependency on our control plane.

Read the quickstart →
No framework changes required
# Before: Shuttle annotations
# #[shuttle_runtime::main]
# async fn main() -> ShuttleAxum { ... }

# After: a standard Tokio main, deployed by Cumulus
[[app]]
name    = "api"
runtime = "rust"
target  = "ec2"      # or "lambda"
binary  = "api"
server  = "prod-1"

[app.env]
DATABASE_URL = { secret = "/api/DATABASE_URL" }

Rust first. Python and static sites too.

Every combination that makes sense. Mix runtimes and targets in one cumulus.toml: a Rust API, a Python worker, and a Next.js frontend, all in one project.

RuntimeTargetBuildHow it runs
RustEC2Cross-compiled to a native binary on an ephemeral Fargate task, with no CI toolchain to maintainNative systemd service, not a container. Health-gated cutover, 5-release rollback history, zero-downtime swap.
RustLambdaCompiled for the Lambda custom runtimearm64 (Graviton) or x86_64, behind a Function URL. Instant rollback to any previous version, no redeploy needed to revert.
PythonEC2Source tarball + uv-managed venv built on the serveruvicorn, gunicorn, or a raw process. uv.lock, poetry.lock, Pipfile.lock, or requirements.txt all work.
PythonLambdaDependencies installed into a Lambda-matching container, zippedManaged Python runtime. uv / poetry / pipenv / pip all work as dependency sources.
StaticS3Node build on Fargate, then s3 syncOptional CloudFront CDN + ACM cert + Route 53 for a custom domain (one-command provisioning landing soon).

The deployment loop you actually want

🏠

100% your infrastructure

Every resource (EC2, Lambda, S3, SSM, RDS) lives in your AWS account. Cumulus assumes a scoped cross-account role constrained to cumulus-* resources with a unique ExternalId. Nothing runs in ours, and your apps keep serving traffic whether or not you're using Cumulus.

♻️

Health-gated deploys

Every deploy probes your app's /health endpoint before cutting over. A non-2xx response triggers automatic compensating rollback, and the old release keeps serving while we clean up.

↩️

Rollback built in

A failed health check rolls the deploy back automatically. To revert on purpose, redeploy a known-good commit — cumulus app releases lists the last five retained releases, then cumulus app deploy <app> --sha <good>. Lambda reverts by re-targeting the alias, so it's instant.

🔑

Secrets stay in SSM

Env vars live in SSM Parameter Store in your account, KMS-encrypted with your CMK. Values are fetched at deploy time and written to disk at mode 0600. They never touch build artifacts.

🌿

Multiple environments

Deploy to staging and production from the same config. Promote a known-good SHA between environments with cumulus app promote: no rebuild, same artifact.

🔄

Auto-deploy on push

Connect a GitHub repo. Every push to your configured branch triggers a build and deploy, with logs streaming live to your dashboard via SSE.

📡

Live log streaming

Tail journald logs from any deployed app with cumulus app logs. Streamed in real time. No SSH required, no agent port exposed to the internet.

👥

Teams & roles

Invite members with Owner, Admin, Member, Billing, or Viewer roles. Sign-in is GitHub OAuth; API tokens for the CLI are org-scoped and stored only as a hash. The control plane never keeps the plaintext.

🌐

Custom domains & TLS

ACM certificates, CloudFront (static sites) or an ALB (EC2 apps), and Route 53 records for your own domain. One-command provisioning on deploy is landing soon.

What can Cumulus do in your account?

The short answer: only what you grant, only on resources it creates. Here's the full picture.

  • 🔒

    Scoped cross-account role

    You deploy a CloudFormation template and see exactly what it permits before accepting. Lambda functions, S3 buckets, SSM parameters, and IAM roles are constrained by cumulus-* name prefixes at the IAM level. EC2 and CloudFront actions are included for server provisioning, and you can review the full policy in the template.

  • 🗝️

    Unique ExternalId per connection

    Your account connection is issued a cryptographically random ExternalId embedded in the CloudFormation template. Every AssumeRole call must present it. This prevents confused-deputy attacks where Cumulus could be tricked into acting on another customer's account.

  • 🛡️

    IMDSv2 enforced, hop-limit 1

    All managed EC2 instances require IMDSv2 (HttpTokensRequired). IMDSv1 is disabled. The hop-limit of 1 blocks container-to-host SSRF. A container on the instance cannot steal instance role credentials from the metadata service.

  • 🔑

    Your KMS key, your control

    All encrypted resources (S3 artifacts, SSM parameters, and RDS) use customer-managed keys. No AWS default managed keys (aws/s3, aws/rds). Revoking your CMK revokes Cumulus's ability to read or write encrypted data, independently of IAM.

  • 📋

    Every action in your CloudTrail

    Cumulus assumes the role under sessions named cumulus-<operation>-<id>. Every AWS API call it makes in your account appears in your own CloudTrail under that session name. No side channel, no blind spots.

  • 🏷️

    All resources tagged and prefixed

    Every resource Cumulus creates carries ManagedBy: cumulus and uses the cumulus- name prefix. Use your AWS Cost Explorer or Config to audit exactly what's under Cumulus's management, with no guesswork.

Flat fee. Zero AWS markup.

A multi-service app across two environments bills as many separate services on per-service platforms, often over $150/mo in platform fees before your first AWS dollar. Here it's one flat number. You pay AWS directly; Cumulus charges for the management plane only.

Hobby
Free
forever

  • 1 project
  • 3 apps
  • All runtimes & targets
  • Health-gated deploys & rollback
  • Community support
  • Preview environments
  • Team members
Coming soon
Team
$49
per month

  • Everything in Pro
  • 5 team members
  • Priority builds
  • Slack notifications
Coming soon
Business
$149
per month

  • Everything in Team
  • Unlimited members
  • SSO & audit log
  • SLA

All plans include unlimited deployments, rollbacks, and log streaming. AWS costs go directly to your AWS bill, and Cumulus never marks them up.

How does this compare to per-service pricing?

Per-service billing, spelled out

Bring-your-own-AWS alternatives bill per service: each web server, background worker, static site, or database, counted separately, then multiplied by every environment.

Scenario: API + background worker + frontend + Postgres, across staging and production, at roughly $20/service/mo.

  • API + worker + frontend + Postgres4 services
  • × staging and production× 2 envs
  • 8 service-units × $20= $160/mo
Platform fees, before AWS$160/mo

The same app on Cumulus

Both apps share one server per environment, the frontend goes to S3 + CloudFront, and Postgres runs on RDS, all under one flat plan. Staging and production don't multiply the fee.

  • API + worker on one server / env2 servers
  • Frontend (S3 + CloudFront)included
  • Staging + productionsame fee
Cumulus Pro, all-in$19/mo

AWS costs are billed directly to you, never marked up. The flat fee wins once your app has more than two or three components.

Your Rust binary. Your AWS. ~10 minutes from connected to live.

Start free on the Hobby plan. No card required. Your infra stays in your account whether you use Cumulus or not.

Get startedRead the quickstart