Skip to main content

Deploy Rust

This guide will help you deploy a Rust application to Deployxa.

Overview

Rust is a systems programming language focused on safety, speed, and concurrency. Deployxa provides optimized deployments for Rust applications with automatic configuration.

Features:

  • Automatic framework detection
  • Rust 1.70+ support
  • Axum, Actix-web, Rocket support
  • PostgreSQL, MySQL support
  • Automatic HTTPS
  • Global CDN
  • Minimal container size

Prerequisites

  • A Rust application
  • A GitHub repository with your code
  • A Deployxa account

Quick Start

1. Create Your Rust App

If you don't have a Rust app yet:

cargo new my-rust-app
cd my-rust-app

Add dependencies to Cargo.toml:

[dependencies]
axum = "0.7"
tokio = { version = "1", features = ["full"] }

Create src/main.rs:

use axum::{routing::get, Router};

#[tokio::main]
async fn main() {
let app = Router::new().route("/", get(|| async { "Hello, Deployxa!" }));

let port = std::env::var("PORT").unwrap_or_else(|_| "8080".to_string());
let addr = format!("0.0.0.0:{}", port);

println!("Server running on {}", addr);

let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
axum::serve(listener, app).await.unwrap();
}

2. Push to GitHub

git init
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/yourusername/my-rust-app.git
git push -u origin main

3. Deploy to Deployxa

  1. Go to Deployxa Dashboard
  2. Click "New Project"
  3. Select your GitHub repository
  4. Deployxa will automatically detect Rust
  5. Click "Deploy"

Your app will be live in under 60 seconds!

Configuration

Detected Settings

Deployxa automatically detects these settings:

SettingValue
FrameworkRust
Build Commandcargo build --release
Output Directorytarget/release
Start Command./target/release/my-rust-app
Port8080

Custom Configuration

If you need to customize settings:

  1. Go to ProjectSettingsBuild
  2. Modify settings as needed
  3. Save changes

Example Custom Settings:

{
"buildCommand": "cargo build --release",
"startCommand": "./target/release/my-rust-app"
}

Environment Variables

Adding Environment Variables

  1. Go to ProjectEnvironment
  2. Click "Add Variable"
  3. Enter key and value
  4. Click "Save"

Common Rust Environment Variables:

PORT=8080
RUST_LOG=info

# Database
DATABASE_URL=postgresql://user:pass@host:5432/dbname
DB_HOST=your-db-host
DB_NAME=your-database
DB_USER=your-username
DB_PASSWORD=your-password

Using Environment Variables

In your Rust app:

use std::env;

fn main() {
let port = env::var("PORT").unwrap_or_else(|_| "8080".to_string());
let db_host = env::var("DB_HOST").unwrap_or_else(|_| "localhost".to_string());

println!("Server running on port {}", port);
}

Database Configuration

Using PostgreSQL with SQLx

Add dependencies to Cargo.toml:

[dependencies]
sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "postgres"] }
tokio = { version = "1", features = ["full"] }
use sqlx::postgres::PgPoolOptions;
use std::env;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
let database_url = env::var("DATABASE_URL")
.expect("DATABASE_URL must be set");

let pool = PgPoolOptions::new()
.max_connections(5)
.connect(&database_url)
.await?;

println!("Successfully connected to PostgreSQL!");

Ok(())
}

Using MySQL with SQLx

Add dependencies to Cargo.toml:

[dependencies]
sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "mysql"] }
tokio = { version = "1", features = ["full"] }
use sqlx::mysql::MySqlPoolOptions;
use std::env;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
let database_url = env::var("DATABASE_URL")
.expect("DATABASE_URL must be set");

let pool = MySqlPoolOptions::new()
.max_connections(5)
.connect(&database_url)
.await?;

println!("Successfully connected to MySQL!");

Ok(())
}

Web Frameworks

Using Axum

Add dependencies to Cargo.toml:

[dependencies]
axum = "0.7"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
use axum::{
routing::get,
Router,
Json,
};
use serde::Serialize;
use std::env;

#[derive(Serialize)]
struct Message {
message: String,
}

#[tokio::main]
async fn main() {
let app = Router::new()
.route("/", get(|| async {
Json(Message {
message: "Hello, Deployxa!".to_string(),
})
}));

let port = env::var("PORT").unwrap_or_else(|_| "8080".to_string());
let addr = format!("0.0.0.0:{}", port);

println!("Server running on {}", addr);

let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
axum::serve(listener, app).await.unwrap();
}

Using Actix-web

Add dependencies to Cargo.toml:

[dependencies]
actix-web = "4"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
use actix_web::{get, web, App, HttpServer, HttpResponse};
use serde::Serialize;
use std::env;

#[derive(Serialize)]
struct Message {
message: String,
}

#[get("/")]
async fn index() -> HttpResponse {
HttpResponse::Ok().json(Message {
message: "Hello, Deployxa!".to_string(),
})
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
let port = env::var("PORT").unwrap_or_else(|_| "8080".to_string());
let port = port.parse::<u16>().unwrap();

println!("Server running on port {}", port);

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

Using Rocket

Add dependencies to Cargo.toml:

[dependencies]
rocket = "0.5"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
#[macro_use] extern crate rocket;

use rocket::serde::json::Json;
use serde::Serialize;

#[derive(Serialize)]
struct Message {
message: String,
}

#[get("/")]
fn index() -> Json<Message> {
Json(Message {
message: "Hello, Deployxa!".to_string(),
})
}

#[launch]
fn rocket() -> _ {
rocket::build().mount("/", routes![index])
}

Custom Domains

Adding a Custom Domain

  1. Go to ProjectDomains
  2. Click "Add Domain"
  3. Enter your domain (e.g., example.com)
  4. Configure DNS records
  5. Wait for verification

DNS Configuration

For Apex Domain (example.com):

Type: A
Name: @
Value: 76.76.21.21

For Subdomain (www.example.com):

Type: CNAME
Name: www
Value: cname.deployxa.com

Performance Optimization

Enable Compression

Using Axum with tower-http:

[dependencies]
tower-http = { version = "0.5", features = ["compression-gzip"] }
use axum::Router;
use tower_http::compression::CompressionLayer;

let app = Router::new()
.route("/", get(handler))
.layer(CompressionLayer::new());

Enable Caching

use axum::{
response::IntoResponse,
http::StatusCode,
};

async fn handler() -> impl IntoResponse {
(
StatusCode::OK,
[("Cache-Control", "public, max-age=3600")],
"Hello, Deployxa!",
)
}

Database Connection Pooling

SQLx provides connection pooling by default:

let pool = PgPoolOptions::new()
.max_connections(10)
.min_connections(2)
.connect_timeout(std::time::Duration::from_secs(5))
.connect(&database_url)
.await?;

Monitoring

Viewing Logs

  1. Go to ProjectLogs
  2. Select log type:
    • Build Logs: Deployment process
    • Runtime Logs: Application output
    • Error Logs: Application errors

Rust Logging

Add dependency:

[dependencies]
env_logger = "0.10"
log = "0.4"
use log::info;
use std::env;

fn main() {
env::set_var("RUST_LOG", "info");
env_logger::init();

info!("Application started");
}

Monitoring Metrics

  1. Go to ProjectAnalytics
  2. View metrics:
    • Request count
    • Response times
    • Error rates
    • Bandwidth usage
    • CPU/RAM usage

Health Checks

Deployxa automatically monitors your application:

  • HTTP health checks every 30 seconds
  • Automatic restart on failure
  • Alerts on consecutive failures

Add a health check endpoint:

use axum::{routing::get, Json};
use serde::Serialize;

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

async fn health() -> Json<Health> {
Json(Health {
status: "healthy".to_string(),
})
}

let app = Router::new()
.route("/health", get(health));

Troubleshooting

Application Crashes on Start

Problem: Application crashes immediately

Solution:

  1. Check runtime logs for errors
  2. Verify environment variables
  3. Check for missing dependencies
  4. Ensure PORT is configured correctly
  5. Check for port conflicts

Database Connection Failed

Problem: Cannot connect to database

Solution:

  1. Verify DATABASE_URL is correct
  2. Check database host and port
  3. Ensure database exists
  4. Check firewall rules
  5. Verify database credentials

Build Failed

Problem: cargo build fails

Solution:

  1. Check build logs for specific errors
  2. Verify dependencies are correct
  3. Check for syntax errors
  4. Test build locally
  5. Ensure Rust version is compatible

Slow Build Times

Problem: Build takes too long

Solution:

  1. Use release mode: cargo build --release
  2. Enable incremental compilation
  3. Reduce dependencies
  4. Use build cache
  5. Consider upgrading plan

Slow Response Times

Problem: Application responds slowly

Solution:

  1. Enable compression
  2. Use caching
  3. Optimize database queries
  4. Use connection pooling
  5. Upgrade plan for more resources

Best Practices

Project Structure

my-rust-app/
├── src/
│ ├── main.rs
│ ├── handlers/
│ │ └── mod.rs
│ ├── models/
│ │ └── mod.rs
│ └── db/
│ └── mod.rs
├── Cargo.toml
├── Cargo.lock
├── .env.example
└── README.md

Environment Variables

  • Never commit .env file
  • Use .env.example as template
  • Rotate secrets regularly
  • Use different values per environment

Security

  • Keep dependencies updated
  • Use HTTPS only
  • Validate all inputs
  • Use parameterized queries
  • Enable CORS properly
  • Use authentication/authorization

Performance

  • Enable compression
  • Use caching
  • Optimize database queries
  • Use connection pooling
  • Use async/await properly
  • Minimize allocations

Database

  • Use connection pooling
  • Index frequently queried columns
  • Use transactions for complex operations
  • Backup database regularly
  • Use prepared statements

Advanced Configuration

Custom Build Configuration

Create .cargo/config.toml:

[build]
rustflags = ["-C", "target-cpu=native"]

[target.x86_64-unknown-linux-gnu]
rustflags = ["-C", "link-arg=-s"]

Docker Support

For local development with Docker:

FROM rust:1.75-bookworm AS builder
WORKDIR /app
COPY . .
RUN cargo build --release

FROM debian:bookworm-slim
WORKDIR /app
COPY --from=builder /app/target/release/my-rust-app .
EXPOSE 8080
CMD ["./my-rust-app"]

Graceful Shutdown

use tokio::signal;
use axum::Router;

#[tokio::main]
async fn main() {
let app = Router::new();

let port = std::env::var("PORT").unwrap_or_else(|_| "8080".to_string());
let addr = format!("0.0.0.0:{}", port);

let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();

axum::serve(listener, app)
.with_graceful_shutdown(shutdown_signal())
.await
.unwrap();
}

async fn shutdown_signal() {
let ctrl_c = async {
signal::ctrl_c().await.expect("failed to install Ctrl+C handler");
};

#[cfg(unix)]
let terminate = async {
signal::unix::signal(signal::unix::SignalKind::terminate())
.expect("failed to install signal handler")
.recv()
.await;
};

#[cfg(not(unix))]
let terminate = std::future::pending::<()>();

tokio::select! {
_ = ctrl_c => {},
_ = terminate => {},
}
}

Examples

Basic Rust App

use std::env;

#[tokio::main]
async fn main() {
let port = env::var("PORT").unwrap_or_else(|_| "8080".to_string());

println!("Server running on port {}", port);

// Your server code here
}

REST API with Axum

use axum::{
routing::{get, post},
Router,
Json,
extract::Path,
};
use serde::{Deserialize, Serialize};
use std::env;
use std::sync::{Arc, Mutex};

#[derive(Clone, Serialize, Deserialize)]
struct User {
id: u32,
name: String,
}

struct AppState {
users: Mutex<Vec<User>>,
}

#[tokio::main]
async fn main() {
let state = Arc::new(AppState {
users: Mutex::new(vec![
User { id: 1, name: "John".to_string() },
User { id: 2, name: "Jane".to_string() },
]),
});

let app = Router::new()
.route("/users", get(get_users))
.route("/users/:id", get(get_user))
.route("/users", post(create_user))
.with_state(state);

let port = env::var("PORT").unwrap_or_else(|_| "8080".to_string());
let addr = format!("0.0.0.0:{}", port);

let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
axum::serve(listener, app).await.unwrap();
}

async fn get_users(
axum::extract::State(state): axum::extract::State<Arc<AppState>>,
) -> Json<Vec<User>> {
let users = state.users.lock().unwrap();
Json(users.clone())
}

async fn get_user(
axum::extract::State(state): axum::extract::State<Arc<AppState>>,
Path(id): Path<u32>,
) -> Json<User> {
let users = state.users.lock().unwrap();
let user = users.iter().find(|u| u.id == id).unwrap();
Json(user.clone())
}

async fn create_user(
axum::extract::State(state): axum::extract::State<Arc<AppState>>,
Json(user): Json<User>,
) -> Json<User> {
let mut users = state.users.lock().unwrap();
users.push(user.clone());
Json(user)
}

With Database

use sqlx::postgres::PgPoolOptions;
use axum::{routing::get, Router, Json};
use serde::Serialize;
use std::env;

#[derive(Serialize, sqlx::FromRow)]
struct User {
id: i32,
name: String,
}

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
let database_url = env::var("DATABASE_URL")
.expect("DATABASE_URL must be set");

let pool = PgPoolOptions::new()
.max_connections(5)
.connect(&database_url)
.await?;

let app = Router::new()
.route("/users", get(move || get_users(pool.clone())));

let port = env::var("PORT").unwrap_or_else(|_| "8080".to_string());
let addr = format!("0.0.0.0:{}", port);

let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
axum::serve(listener, app).await.unwrap();

Ok(())
}

async fn get_users(pool: sqlx::PgPool) -> Json<Vec<User>> {
let users = sqlx::query_as::<_, User>("SELECT id, name FROM users")
.fetch_all(&pool)
.await
.unwrap();

Json(users)
}

Resources


Need Help? Contact support@deployxa.com or join our community Discord.