Skip to main content

Deploying Rust Applications

This comprehensive guide covers everything you need to know about deploying Rust applications via Deploy with Git, from simple HTTP servers to complex microservices using Actix-web, Rocket, or Axum.

Overview

Deploy with Git automatically detects Rust applications by looking for:

  • Cargo.toml file
  • Cargo.lock for dependency locking (optional)
  • rust-toolchain.toml or rust-toolchain for version specification (optional)

Basic Rust Deployment

Simple Actix-web API

docker run -d \
--name actix-api \
-e GIT_REPO_URL=https://github.com/your-username/actix-api \
-e APP_PORT=3000 \
-p 3000:3000 \
runonflux/orbit:latest

What Happens Automatically

  1. Detection: Finds Cargo.toml and identifies as Rust project
  2. Version Selection:
    • Checks RUST_VERSION environment variable
    • Checks rust-toolchain.toml channel field
    • Checks rust-toolchain file
    • Falls back to stable channel
  3. Runtime Installation:
    • Installs Rust using official rustup installer
    • Sets RUSTUP_HOME to /opt/flux-tools/rustup
    • Sets CARGO_HOME to /opt/flux-tools/cargo
    • Adds cargo bin directory to PATH
  4. Dependencies: Runs cargo fetch to download and verify dependencies
  5. Build: Compiles optimized release binary with cargo build --release
  6. Start: Executes compiled binary from target/release/

Framework-Specific Guides

Actix-web Framework

Actix-web is a powerful, pragmatic, and extremely fast web framework for Rust:

docker run -d \
--name actix-rest-api \
-e GIT_REPO_URL=https://github.com/your-username/actix-api \
-e APP_PORT=3000 \
-e RUST_VERSION=stable \
-p 3000:3000 \
runonflux/orbit:latest

Example main.rs:

use actix_web::{get, web, App, HttpResponse, HttpServer, Responder};
use serde::{Deserialize, Serialize};
use std::env;

#[derive(Serialize, Deserialize)]
struct HealthCheck {
status: String,
}

#[get("/health")]
async fn health() -> impl Responder {
HttpResponse::Ok().json(HealthCheck {
status: "healthy".to_string(),
})
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
let port = env::var("APP_PORT")
.unwrap_or_else(|_| "3000".to_string())
.parse::<u16>()
.expect("APP_PORT must be a valid port number");

HttpServer::new(|| {
App::new()
.service(health)
})
.bind(("0.0.0.0", port))?
.run()
.await
}

Example Cargo.toml:

[package]
name = "actix-api"
version = "1.0.0"
edition = "2021"

[dependencies]
actix-web = "4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

Rocket Framework

Rocket is a web framework for Rust with focus on ease-of-use, expressiveness, and speed:

docker run -d \
--name rocket-api \
-e GIT_REPO_URL=https://github.com/your-username/rocket-api \
-e APP_PORT=3000 \
-p 3000:3000 \
runonflux/orbit:latest

Example main.rs:

#[macro_use] extern crate rocket;

use rocket::{State, Config};
use rocket::serde::{Serialize, json::Json};
use std::env;

#[derive(Serialize)]
#[serde(crate = "rocket::serde")]
struct HealthCheck {
status: String,
}

#[get("/health")]
fn health() -> Json<HealthCheck> {
Json(HealthCheck {
status: "healthy".to_string(),
})
}

#[launch]
fn rocket() -> _ {
let port = env::var("APP_PORT")
.unwrap_or_else(|_| "3000".to_string())
.parse::<u16>()
.expect("APP_PORT must be a valid port number");

let config = Config {
port,
address: "0.0.0.0".parse().unwrap(),
..Config::default()
};

rocket::custom(&config)
.mount("/", routes![health])
}

Axum Framework

Axum is an ergonomic and modular web framework built with Tokio, Tower, and Hyper:

docker run -d \
--name axum-api \
-e GIT_REPO_URL=https://github.com/your-username/axum-api \
-e APP_PORT=3000 \
-p 3000:3000 \
runonflux/orbit:latest

Warp Framework

Warp is a super-easy, composable, web server framework for warp speeds:

docker run -d \
--name warp-api \
-e GIT_REPO_URL=https://github.com/your-username/warp-api \
-e APP_PORT=3000 \
-p 3000:3000 \
runonflux/orbit:latest

Version Management

Specify Rust Version

Option 1: Environment Variable

docker run -d \
-e GIT_REPO_URL=https://github.com/your-username/rust-app \
-e APP_PORT=3000 \
-e RUST_VERSION=stable \
-p 3000:3000 \
runonflux/orbit:latest

Supported values:

  • stable - Latest stable release
  • nightly - Nightly builds
  • beta - Beta channel
  • 1.75.0 - Specific version number

Option 2: rust-toolchain.toml File

[toolchain]
channel = "stable"
components = ["rustfmt", "clippy"]

Option 3: rust-toolchain File

stable

Build Optimization

Release Mode

By default, Deploy with Git builds Rust applications in release mode for optimal performance:

# Default: Optimized release build
docker run -d \
-e GIT_REPO_URL=https://github.com/your-username/rust-app \
-e APP_PORT=3000 \
-p 3000:3000 \
runonflux/orbit:latest

This runs cargo build --release, which:

  • Optimizes for speed
  • Removes debug symbols
  • Takes longer to build but runs faster
  • Creates binary in target/release/ directory

Custom Build Command

Override the default build command if needed:

docker run -d \
-e GIT_REPO_URL=https://github.com/your-username/rust-app \
-e APP_PORT=3000 \
-e BUILD_COMMAND="cargo build --release --features production" \
-p 3000:3000 \
runonflux/orbit:latest

Environment Variables

Rust-Specific Variables

VariableDescriptionDefault
RUST_VERSIONRust channel or versionstable
RUSTFLAGSAdditional compiler flags-
CARGO_BUILD_JOBSParallel build jobsAuto-detected

Common Application Variables

docker run -d \
--name rust-api \
-e GIT_REPO_URL=https://github.com/your-username/rust-api \
-e APP_PORT=3000 \
-e RUST_VERSION=stable \
-e DATABASE_URL=postgres://user:pass@db:5432/mydb \
-e JWT_SECRET=your-secret-key \
-e RUST_LOG=info \
-p 3000:3000 \
runonflux/orbit:latest

Advanced Scenarios

Monorepo - Deploy Specific Service

docker run -d \
--name rust-auth-service \
-e GIT_REPO_URL=https://github.com/your-username/monorepo \
-e PROJECT_PATH=services/auth \
-e APP_PORT=3000 \
-p 3000:3000 \
runonflux/orbit:latest

Private Repository

docker run -d \
--name private-rust-api \
-e GIT_REPO_URL=https://github.com/your-username/private-api \
-e GIT_TOKEN=ghp_your_personal_access_token \
-e APP_PORT=3000 \
-p 3000:3000 \
runonflux/orbit:latest

With Deployment Hooks

Create pre-deploy.sh in your repository root:

#!/bin/bash
# Run database migrations before deployment
echo "Running database migrations..."
# Your migration logic here

Create post-deploy.sh:

#!/bin/bash
# Warm up cache after deployment
echo "Warming up cache..."
curl http://localhost:$APP_PORT/api/warmup
docker run -d \
--name rust-api-with-hooks \
-e GIT_REPO_URL=https://github.com/your-username/rust-api \
-e APP_PORT=3000 \
-p 3000:3000 \
runonflux/orbit:latest

CI/CD Integration

Automatic Deployment with Webhooks

docker run -d \
--name rust-api \
-e GIT_REPO_URL=https://github.com/your-username/rust-api \
-e APP_PORT=3000 \
-e WEBHOOK_SECRET=my-secret-phrase \
-p 3000:3000 \
-p 9001:9001 \
runonflux/orbit:latest

Configure GitHub Webhook:

  • Payload URL: https://your-app-9001.app.runonflux.io/webhook
  • Content type: application/json
  • Secret: my-secret-phrase
  • Events: Just the push event

Polling for Updates

docker run -d \
--name rust-api \
-e GIT_REPO_URL=https://github.com/your-username/rust-api \
-e APP_PORT=3000 \
-e POLLING_INTERVAL=300 \
-p 3000:3000 \
runonflux/orbit:latest

Troubleshooting

Binary Not Found After Build

Problem: "Binary 'my-app' was not created"

Solution: Ensure your Cargo.toml has a valid package name:

[package]
name = "my-app" # Binary will be named "my-app"
version = "1.0.0"
edition = "2021"

The binary name is derived from the package name in Cargo.toml.

Build Takes Too Long

Problem: Rust build timeout

Solution: Rust builds can be slow, especially first builds. Increase build timeout:

-e BUILD_TIMEOUT=3600  # 60 minutes for large projects

Performance tips:

  • Release builds are slower but produce faster binaries
  • First build downloads and compiles all dependencies
  • Subsequent builds are much faster (cached dependencies)
  • Consider using fewer dependencies for faster builds

Port Binding Issues

Problem: Application not accessible

Solution: Ensure your Rust application binds to 0.0.0.0 (not localhost or 127.0.0.1):

// Good: Accessible from outside container
HttpServer::new(|| App::new())
.bind(("0.0.0.0", port))?
.run()
.await

// Bad: Only accessible from inside container
HttpServer::new(|| App::new())
.bind(("127.0.0.1", port))?
.run()
.await

Dependency Compilation Errors

Problem: Cargo build fails with dependency errors

Solution: Check Rust version compatibility. Some crates require specific Rust versions:

# Try with latest stable
-e RUST_VERSION=stable

# Or specific version if crate requires it
-e RUST_VERSION=1.75.0

Performance Tips

  1. Release Mode: Always use release builds in production (automatic with Deploy with Git)
  2. Static Linking: Rust produces static binaries by default - no runtime dependencies needed
  3. Binary Size: Use strip = true in Cargo.toml to reduce binary size:
    [profile.release]
    strip = true
    opt-level = 3
    lto = true
  4. Dependency Caching: Dependencies are cached based on Cargo.lock hash - no recompilation if unchanged
  5. Health Checks: Implement /health endpoint for faster deployment verification
  6. Async Runtime: Use Tokio for async operations - excellent performance characteristics

Example Repository Structure

my-rust-api/
├── Cargo.toml # Package manifest
├── Cargo.lock # Dependency lock file
├── rust-toolchain.toml # Optional: Pin Rust version
├── pre-deploy.sh # Optional: Pre-deployment hook
├── post-deploy.sh # Optional: Post-deployment hook
├── src/
│ ├── main.rs # Application entry point
│ ├── routes/
│ │ ├── mod.rs
│ │ ├── users.rs
│ │ └── auth.rs
│ ├── models/
│ │ ├── mod.rs
│ │ └── user.rs
│ └── middleware/
│ ├── mod.rs
│ └── auth.rs
└── tests/
└── integration_test.rs

Why Rust?

Rust delivers exceptional performance with memory safety:

  • Blazingly Fast: Performance comparable to C/C++
  • Memory Safe: No null pointers, no data races
  • Zero-Cost Abstractions: High-level features with no runtime overhead
  • Concurrent: Fearless concurrency with ownership system
  • Reliable: Catch bugs at compile time, not runtime

Perfect for:

  • High-performance APIs
  • Microservices
  • Real-time systems
  • WebSocket servers
  • Data processing pipelines

Next Steps