Deploying Rust applications to Heroku, with example code for Iron
Now with support for Iron, Cargo and Cargo.lock
!
You can deploy an example Rust application to Heroku using this button:
If you’d prefer to use the command line, you’ll need git
and the
Heroku toolbelt. Once these are installed, run:
git clone https://github.com/emk/heroku-rust-cargo-hello.git
cd heroku-rust-cargo-hello
heroku create --buildpack https://github.com/emk/heroku-buildpack-rust.git
git push heroku master
This will download the example application, create a new Heroku project, and deploy the code to Heroku. That’s it!
How it works
Our server is based on the Iron middleware library. We parse URL parameters and dispatch HTTP requests to the appropriate handler routine using Iron’s router module:
fn main() {
let mut router = Router::new();
router.get("/", hello);
router.get("/:name", hello_name);
Iron::new(router).listen(Ipv4Addr(0, 0, 0, 0), get_server_port());
}
The hello
function returns an HTTP status code and the content to send to
the user:
fn hello(_: &mut Request) -> IronResult<Response> {
Ok(Response::with(status::Ok, "Hello world!"))
}
The hello_name
function is similar, but we look up the value of the
:name
parameter that we declared to the router, above.
fn hello_name(req: &mut Request) -> IronResult<Response> {
let params = req.extensions.find::<Router,Params>().unwrap();
let name = params.find("name").unwrap();
Ok(Response::with(status::Ok, format!("Hello, {}!", name)))
}
The final piece needed to run on Heroku is a function to look up up our port number:
fn get_server_port() -> Port {
getenv("PORT")
.and_then(|s| from_str::<Port>(s.as_slice()))
.unwrap_or(8080)
}
The full source code is available on GitHub. To learn more about Rust, see the excellent Rust guide.
Keep reading for notes on building the program locally and on configuring your own programs to run on Heroku.
Building the program locally
First, check to see if the example program builds against the latest version of Rust:
If the build status is green: You should be able to install Rust, build the program, and run it as follows:
curl -s https://static.rust-lang.org/rustup.sh | sudo sh
cargo update
cargo build
PORT=5000 target/hello
Then visit 0.0.0.0:5000
and 0.0.0.0:5000/user
in your browser.
(The rustup.sh
script needs root access to your machine, so all the usual
caveats apply. At least it’s served over SSL, and in any case, you were
already going to be trusting the Rust developers enough to install their
compiler. You can find other installation options on the Rust
website.)
Once you verify that everything works with the latest Rust, you will
probably also want to put your Rust binaries somewhere that Heroku can find
them, and update your RustConfig
. The easiest way to do this is using
the update-bin.sh
script:
./update-bin.sh my-s3-bucket-name
If the build status is red: You will either need to update the example
program for the latest Rust, or you will need to download an older version
of Rust and Cargo from the URLs list in
the included RustConfig
file and omit the rustup.sh
and
cargo update
steps. The Rust language is still changing, but a
Rust 1.0 release is planned for the end of 2014.
Configuring other projects for Heroku
First, set up your project with Cargo.toml
and Cargo.lock
as described
in the Rust guide. You also need to create a Heroku project with
the appropriate buildpack:
cd my-rust-project
heroku create --buildpack https://github.com/emk/heroku-buildpack-rust.git
Then, all you need to do is add a Procfile
, which tells Heroku how to
launch your project:
web: ./target/hello
…and a RustConfig
file pointing at copies of the appropriate nightly
tarballs:
URL="https://s3.amazonaws.com/rust-builds/2014-09-17/rust-nightly-x86_64-unknown-linux-gnu.tar.gz"
VERSION="2014-09-17"
CARGO_URL="https://s3.amazonaws.com/rust-builds/2014-09-17/cargo-nightly-x86_64-unknown-linux-gnu.tar.gz"
CARGO_VERSION="2014-09-17"
Make sure that your program listens on the port specified by the
environment variable PORT
, as demonstrated in the example program. Now
you can commit these files and deploy to Heroku:
git push heroku master
A big thank you to Alex Crichton for helping debug various Cargo issues, and to the good folks at Heroku for their offers of help. And thanks to Chris Morgan and Huon Wilson for their help with the earliest versions of this code. If this breaks, please don’t hesitate to get in touch!
Want to contact me about this article? Or if you're looking for something else to read, here's a list of popular posts.