How to Set Up a Web Server with Rust and Actix
Actix web tutorial: build a Rust web server and Todo REST API with Actix-web, serde, and tips for deploying to a DigitalOcean Droplet.
Drake Nguyen
Founder · System Architect
Introduction
This actix web tutorial walks you through building a small Rust web server and a simple Todo REST API using the Actix web framework. You will create routes, serialize JSON with serde, and test endpoints locally. The guide also includes tips for deploying the Rust app on a Netalith Droplet or other Linux servers.
Prerequisites
- A Netalith Droplet (Ubuntu) or another Linux host to run and deploy the rust web server.
- SSH access to the Droplet and a basic understanding of the Linux command line.
- Rust toolchain installed (rustup / cargo / rustc).
- Familiarity with Rust fundamentals (structs, ownership, async functions) and JSON serialization with serde.
Step 1 — Prepare the Ubuntu Droplet
SSH into the server, update packages, install build tools, and install Rust using rustup.
ssh your_username@your_droplet_ip
sudo apt update && sudo apt upgrade -y
# Install build tools and SSL headers often needed by Rust crates
sudo apt install -y build-essential libssl-dev curl
# Install Rust (rustup)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
rustc --version
cargo --version
Step 2 — Create the project
Create a new Cargo project and add the Actix web and serde dependencies to Cargo.toml.
cargo new sammy_todos
cd sammy_todos
# Cargo.toml (dependencies section)
[dependencies]
actix-web = "4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
Step 3 — Write a basic Actix web server
Create a minimal server in src/main.rs. This example shows a root route and how to bind the server for local testing.
use actix_web::{get, App, HttpServer, HttpResponse, Responder};
#[get("/")]
async fn index() -> impl Responder {
HttpResponse::Ok().body("Welcome to the Sammy Todo API")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().service(index))
.bind("127.0.0.1:8080")?
.run()
.await
}
Run the server locally:
cargo run
Test the root endpoint:
curl http://127.0.0.1:8080
Step 4 — Add a Todo model (JSON serialization)
Use serde to derive Serialize and Deserialize so the API can accept and return JSON.
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
struct Todo {
id: i32,
title: String,
completed: bool,
}
Step 5 — Create a Todo (POST)
Implement a POST handler that accepts JSON and returns the created Todo. In production you would persist the item to a database; this example returns the received payload.
use actix_web::{post, web};
#[post("/todos")]
async fn create_todo(todo: web::Json) -> impl Responder {
// Return the created resource as JSON
HttpResponse::Created().json(todo.into_inner())
}
Step 6 — Get a Todo by ID (GET)
Add a route to fetch a Todo by its id. This sample returns a dummy record to illustrate routing and handlers.
use actix_web::{get, web};
#[get("/todos/{id}")]
async fn get_todo(id: web::Path) -> impl Responder {
let todo = Todo { id: id.into_inner(), title: "Learn Actix-Web".to_string(), completed: false };
HttpResponse::Ok().json(todo)
}
Bind routes and run the server
Register all services in main. For local testing bind to 127.0.0.1; when deploying to a droplet use 0.0.0.0 or configure a reverse proxy.
use actix_web::{App, HttpServer};
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.service(index)
.service(create_todo)
.service(get_todo)
})
// Use 0.0.0.0:8080 to accept external connections on a Droplet
.bind("127.0.0.1:8080")?
.run()
.await
}
Example API tests:
# Create a todo (replace id handling if you implement persistence)
curl -X POST -H "Content-Type: application/json" -d '{"id":1,"title":"Buy groceries","completed":false}' http://127.0.0.1:8080/todos
# Fetch a todo
curl http://127.0.0.1:8080/todos/1
Deploying the Actix web server to a Netalith Droplet
When you move from development to deployment, follow these practical steps for a reliable rust web framework deployment:
- Build a release binary:
cargo build --release. - Copy the release binary to the Droplet or build directly on the server.
- Run the server behind a reverse proxy (Nginx) or use a systemd unit to run the rust actix-web app as a service.
- Open the required ports in the firewall (ufw) and bind the server to
0.0.0.0if you need external access, or keep it local and proxy from Nginx. - Consider logging, monitoring, and TLS termination (Let's Encrypt) in front of the rust http server for production traffic.
Tip: For a one-click approach you can build and deploy from CI to a Netalith Droplet, or use Docker to containerize the actix web server and run it on the Droplet.
Conclusion
This actix web tutorial for beginners introduced building a rust web server, creating a simple rust rest api (Todo), and testing endpoints with curl. From here you can extend the example into a full CRUD app by integrating a database, adding middleware, authentication, and structured error handling. Follow best practices for deploying and securing your actix-web server on an Ubuntu server or Netalith Droplet.