• Deploy A Rust Website on Heroku

    Deploy A Rust Website on Heroku

    Mar 14, 2021Updated on Jan 7, 2022

    Rust is a blazing fast and memory efficient programming language that's used by tech companies like Firefox, Dropbox and Cloudflare to name a few.

    Today we are going to focus on the web side of Rust, hence the name "Rocket".

    Well, per the official website rocket.rs - "Rocket is a web framework for Rust that makes it simple to write fast, secure web applications without sacrificing flexibility, usability, or type safety". That's a self explanatory introduction, nothing more I can add.

    Having completed the formalities, let's launch some Rockets.

    Setting up Rocket

    To run Rocket locally we need to have installed a compatible version of Rust (install Rust), and since Rocket uses advanced and unstable features of Rust we'll need to use the nightly version of Rust. To configure the nightly version of Rust as the default toolchain run the following command on your terminal.

    rustup default nightly
    

    or you can set it as the default toolchain for your Rocket project only by running the following command inside the Rocket project's directory after having created it.

    rustup override set nightly
    

    Now, proceed with creating a new cargo project

    Cargo new rocket-demo-app --bin
    
    # switch into the project's directory
    cd rocket-demo-app
    

    Add Rocket as a dependency in the Cargo.toml file found on the project's root.

    [dependencies]
    rocket = "0.4.7"
    

    Update the src/main.rs file by adding a bit of Rocket code

    #![feature(proc_macro_hygiene, decl_macro)]
    
    #[macro_use] extern crate rocket;
    
    #[get("/")]
    fn index() -> &'static str {
      "This is my Rocket Demo app"
    }
    
    fn main() {
      rocket::ignite().mount("/", routes![index]).launch();
    }
    

    Then run the following command,

    Cargo run
    

    Rust will fetch all the dependencies used by Rocket, make a dev build of our project and run the binary code, launching our project.

    Finished dev [unoptimized + debuginfo] target(s) in 3m 00s
         Running `target\debug\rocket-demo-app.exe`
    🔧 Configured for development.
        => address: localhost
        => port: 8000
        => log: normal
        => workers: 8
        => secret key: generated
        => limits: forms = 32KiB
        => keep-alive: 5s
        => read timeout: 5s
        => write timeout: 5s
        => tls: disabled
    🛰   Mounting /:
        => GET / (index)
    🚀 Rocket has launched from http://localhost:8000
    

    In the output above, Rocket has launched our project on the 8000 port, so to view it navigate to http://localhost:8000.

    All we did on the main/src.rs file is declare an index route, mount it at the "/" path and launch our rocket app.

    Rocket routes

    Rocket applications center around routes and handlers, where a Rocket route is simply a combination of parameters matching an incoming request and a handler that processes the request and returns a response.

    A route is declared by annotating a function just as in the example above, the index route is:

    #[get("/")]
    fn index() -> &'static str {
      "This is my Rocket Demo app"
    }
    

    Where the annotation at the top - #[get("/")] is the route's attribute and the function that follows below it fn index() is the route's handler.

    Route mounting

    Let's add a new route to our Rocket project. Add the following code after the index route.

    #[get("/about")]
    fn about() -> &'static str {
      "This is the about page of my Rocket Demo app"
    }
    

    And re-run the cargo project.

    When you try navigating to the /about page, you'll see a 404: Not Found error.

    What happened?

    Well, Rocket needs to mount routes before dispatching requests to them, that is the reason we have rocket::ignite().mount("/", routes![index]).launch(); inside the main() function for the first route. Let's mount our _about page route too. Update the main() function with the following code.

    fn main(){
      rocket::ignite().mount("/", routes![index, about]).launch();
    }
    

    Re-run cargo and try visiting the "/about" route again.

    After declaring and mounting our routes, we call the lauch() method which starts up the server and has our Rocket app up and running waiting for incoming requests to dispatch them accordingly.

    For more on Rocket requests head to the official documentation

    Before proceeding with the next step, use git to stage and commit all the changes done to the app.

    git add . && git commit -m "initialize Rocket project"
    

    Setting up Heroku

    Start with creating an account on Heroku if you do not have one before proceeding.

    Inside the Heroku dashboard add a new app and fill in it's details Add new Heroku app

    Next, download and install the Heroku CLI, then proceed with running the following command inside the project's directory.

    heroku login
    

    Follow the instructions which will redirect you to your browser and let you log into your Heroku account.

    Back on the project, link the remote Heroku app to your Rocket project with the following command.

    heroku git:remote -a rocket-demo-app
    

    Create a new file on the project's root and name it Procfile without any extensions, add the following code into it.

    web: ROCKET_PORT=$PORT ROCKET_KEEP_ALIVE=0 ./target/release/rocket-demo-app
    

    Specify a nightly version of Rust to work with by creating another file on the project's root, naming it rust-toolchain (without a file extension). The following nightly version is a good start:

    nightly-2020-10-24
    

    Commit the new changes.

    Use Heroku's Rust buildpack.

    heroku buildpacks:set emk/rust
    

    Then push the changes to heroku.

    git push heroku master
    

    After finishing all it needs to do, the command-line tool will give you the link your app has been deployed to, open the link and view the deployed app.

    remote: -----> Building application using Cargo
    remote:    Compiling rocket-demo v0.1.0 (/tmp/build_898d5ac6)
    remote:     Finished release [optimized] target(s) in 3.39s
    remote: -----> Discovering process types
    remote:        Procfile declares types -> web
    remote:
    remote: -----> Compressing...
    remote:        Done: 1.5M
    remote: -----> Launching...
    remote:        Released v6
    remote:        https://rocket-demo-app.herokuapp.com/ deployed to Heroku
    remote:
    remote: Verifying deploy... done.
    To https://git.heroku.com/rocket-demo-app.git
       13450ef..0febf7c  main -> main
    

    Above is an example output you'd expect from the heroku-cli tool.

    This is a nice start when delving into deploying Rust applications and in this particular case we were deploying a Rocket framework app on Heroku.

    There is so much more to learn and experiment in this "fast, easy, and flexible" framework, this has just been a short intro into deploying it, more can be learnt here.

    Go out there and launch some Rockets.