Build a High‑Performance Rust Media Server with Actix‑Web and Docker
This step‑by‑step tutorial shows how to create a low‑latency Rust and Actix‑Web media server, configure Docker, stream MP4 videos, and build a simple front‑end, enabling full control over media hosting and easy extensions such as authentication, database integration, transcoding, and CDN acceleration.
This article guides you step‑by‑step to create a high‑performance media server using Rust and Actix‑Web, enabling low‑latency video delivery and full control over media hosting.
Download Sample Video 🎥💾
First, download a sample MP4 video from https://sample-videos.com.
Create docker-compose.yml 📄
Create a file named docker-compose.yml with the following content:
<code>version: '3.5'
services:
rust:
image: rust:latest
container_name: rust
ports:
- 8080:8080
tty: true
volumes:
- .:/app
working_dir: /app
command: bash
networks:
default:
name: rust
</code>Run the container:
<code>$ docker-compose up</code>Set Up Rust Server 🦀🖥️
Enter the Rust container (via CLI or VSCode). Create a new Rust project:
<code>cargo new mp4_server</code>Add the following to Cargo.toml :
<code>[package]
name = "mp4_server"
version = "0.1.0"
edition = "2021"
[dependencies]
reqwest = { version = "0.12.7", features = ["json"] }
tokio = { version = "1.40.0", features = ["full"] }
serde = { version = "1.0.210", features = ["derive"] }
actix-web = "4.9.0"
actix-cors = "0.7.0"
</code>Replace the contents of src/main.rs with:
<code>use actix_web::{web, App, HttpServer, HttpResponse};
use tokio::fs::File;
use tokio::io::{AsyncReadExt, BufReader};
use actix_cors::Cors;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.wrap(Cors::permissive())
.route("/stream", web::get().to(stream_video))
})
.bind("0.0.0.0:8080")?
.run()
.await
}
async fn stream_video() -> HttpResponse {
let file_path = "/app/mp4_server/test.mp4"; // MP4 file path
let file = File::open(file_path).await;
match file {
Ok(mut f) => {
let mut buffer = Vec::new();
let mut reader = BufReader::new(f);
let mut content = Vec::new();
while let Ok(n) = reader.read_to_end(&mut buffer).await {
if n == 0 { break; }
content.extend_from_slice(&buffer[..n]);
}
HttpResponse::Ok()
.content_type("video/mp4")
.body(content)
}
Err(_) => HttpResponse::NotFound().body("Video not found"),
}
}
</code>Replace /app/mp4_server/test.mp4 with the actual path to your MP4 file, then run:
<code>cargo run</code>Create Simple Frontend 💻🎨
Create a file named mp4.html with the following content:
<code><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Stream MP4 Video</title>
</head>
<body>
<h1>Stream MP4 Video</h1>
<video width="640" height="360" controls>
<source src="http://localhost:8080/stream" type="video/mp4">
Your browser does not support the video tag.
</video>
</body>
</html>
</code>Summary 🎉👨💻
You have now built a high‑performance MP4 streaming server with Rust and Actix‑Web, ready for further customization.
Extensions:
Add authentication and authorization: Control access to your media server.
Store video metadata in a database: Use a database for titles, descriptions, tags, etc.
Implement video transcoding: Use third‑party libraries or services to support various formats and resolutions.
Accelerate delivery with a CDN: Improve user experience by using a CDN.
Further learning:
Actix‑Web documentation: https://actix.rs/docs/
Rust book: https://doc.rust-lang.org/book/
Tokio docs: https://docs.rs/tokio
Architecture Development Notes
Focused on architecture design, technology trend analysis, and practical development experience sharing.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.