Update, 24 June 2014: I'm planning to add support for building projects with Cargo shortly. I'll announce it here and on Twitter when it's ready.

Update, 12 July 2014: Highly experimental Cargo support is now available.

Update, 17 September 2014: This post is obsolete. Please see Deploying Rust to Heroku, with example code for Iron.

If you have git and the Heroku toolbelt on your system, this should be easy:

git clone https://github.com/emk/heroku-rust-hello.git
cd heroku-rust-hello
heroku create --buildpack https://github.com/emk/heroku-buildpack-rust.git
git push heroku master

If you want to create your own Rust web server from scratch, keep reading. But fair warning: Rust is not yet ready for serious web development.

Setting up rustc

First, we need to install a Rust compiler. Assuming that we're running Linux, let's grab the latest nightly build, and hope that all of our supporting libraries are up to date:

curl -O http://static.rust-lang.org/dist/rust-nightly-x86_64-unknown-linux-gnu.tar.gz
tar xzf rust-nightly-x86_64-unknown-linux-gnu.tar.gz
cd rust-nightly-x86_64-unknown-linux-gnu
./install.sh

If you're not running Linux, check out these instructions for downloading nightly builds. If you're running an older Linux, you may want to check out my Ubuntu 10.04 instructions.

Compiling our test program

Now, let's create a git repository for our code, and get a copy of all our dependencies:

mkdir heroku-rust-hello
cd heroku-rust-hello
git init
git submodule add https://github.com/Ogeon/rustful.git lib/rustful
git submodule update --init --recursive

Next, place the following code into hello.rs. This is heavily based on the rustful example code, and you may want to double-check there to see if any APIs have changed.

extern crate rustful;
extern crate http;

use std::os::getenv;
use std::io::net::ip::Port;
use rustful::{Server, Router, Request, Response};
use http::method::Get;

// An example handler for "/".
fn hello(request: &Request, response: &mut Response) {
    match response.write("Hello from Rust!".as_bytes()) {
        Err(e) => println!("error: {}", e),
        _ => {}
    }
}

/// Look up our server port number in PORT, for
/// compatibility with Heroku.
fn get_server_port() -> Port {
    getenv("PORT")
        .and_then(|s| from_str::<Port>(s.as_slice()))
        .unwrap_or(8080)
}

/// Configure and run our server.
fn main() {
    let routes = [
        (Get, "/", hello)
    ];

    let server = Server::new(get_server_port(), Router::from_routes(routes));
    server.run();
}

To build it, we'll need a Makefile:

default: all

all: deps build

deps:
    (cd lib/rustful && make deps && make)

build:
    rustc -L lib/rustful/lib/ -o hello hello.rs

.PHONY: all deps build

And now we can build and test our program!

make
./hello
# Look at http://0.0.0.0:8080/ in a browser.

If this fails, begin by double-checking the rustful example code and seeing if any APIs have changed. When you're finished running this, hit Control-C.

Verifying that we're statically linked

While we're here, let's check to make sure that we've statically linked the Rust library. Run ldd to check what libraries we use:

$ ldd ./hello
    linux-vdso.so.1 =>  (0x...)
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x...)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x...)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x...)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x...)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x...)
    /lib64/ld-linux-x86-64.so.2 (0x...)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x...)

If you see something like the above list, everything's good. But if you see anything like:

    libnative-1fb5e2c0-0.11.0-pre.so => ...
    libsyntax-555559ea-0.11.0-pre.so => ...

…then you're dynamically linking the Rust runtime libraries, and you won't be able to run on Heroku. To fix this, look for dependencies which are only available as .so files. These force rust to link dynamically. Your first suspect should be libsyntax, which is used to implement macros, but which should only be needed at compile time. Particular thanks go to Huon Wilson for explaining this.

Preparing for Heroku

Create a Procfile telling Heroku how to run your application:

web: ./hello

Now for the tricky part: Since the Rust language is still under heavy development, we need to save a copy of our nightly build somewhere that we can find it again. Take your copy of rust-nightly-x86_64-unknown-linux-gnu.tar.gz and toss it up on a webserver somewhere, or in an S3 bucket. Now, tell Heroku where to find it by creating a RustConfig file containing two variables:

URL="https://example.com/rust-nightly-x86_64-unknown-linux-gnu.tar.gz"
VERSION="2014-05-29"

Here, the VERSION string can be a date, or version number, or just about any other identifier. Every time VERSION changes, our Heroku buildpack will download and cache a new copy of rustc.

And finally, let's commit our changes to git:

git add Makefile Procfile hello.rs RustConfig
git commit -m "Create initial application"

Deploying to Heroku

For this next step, you will need Heroku toolbelt installed.

heroku create --buildpack https://github.com/emk/heroku-buildpack-rust.git
git push heroku master

If you're lucky, Heroku should deploy your application and print out a URL. If you open that URL in a web browser, you should see "Hello from Rust!"

I had lots of help

I owe many thanks to Chris Morgan and Huon Wilson for their Rust expertise, and to Ogeon for some incredibly quick enhancements to his rustful library. Without their help, this would have taken much longer.

Also, before continuing, please be aware that the Rust language is still under heavy development, and your code will almost certainly break from week to week. And for web-related projects in Rust, please review Chris Morgan's Are we web yet? before building anything more than toy servers.

When this breaks

I intend to keep these instructions up-to-date for the immediate future. If something breaks, please see my contact page. You may also want to take a look at my heroku-buildpack-rust repository. Happy Rust hacking!