Edge
Tutorials
CGI apps on Edge

CGI apps on Wasmer Edge

In this tutorial, you will learn how to deploy a CGI app on Wasmer Edge. We will be using the Rust's CGI crate (opens in a new tab) to create a CGI app.

We'll just make a simple Hello, World! CGI app.

What is CGI?

CGI or Common Gateway Interface is a standard for running programs on a web server to generate dynamic content. CGI programs are often written in scripting languages like Perl, Python, or Ruby, but they can also be written in compiled languages like C, C++, or Rust.

CGI with Wasmer

CGI works using the standard input and output streams. Wasmer maps the standard input and output streams to the HTTP request and response. You can read more about WCGI in our article, Announcing WCGI (opens in a new tab).

Prerequisites

The project requires the following tools to be installed on your system:

Creating a CGI app

Install Wasmer CLI

Install the latest version of Wasmer CLI following the instructions here.

ℹ️

You can see all commands available with wasmer --help. You can also read the CLI documentation online.

Log in into Wasmer

Create a new account in Wasmer (opens in a new tab). Then, log in into the Wasmer CLI and follow the provided steps to provide the CLI access to your Wasmer account.

wasmer login
⚠️

Please check that you have the latest version of wasmer runtime as this tutorial depends on version 4.2.3 or higher.

Install the wasm32-wasi target:

rustup target add wasm32-wasi

This will install the wasm32-wasi target for the Rust compiler.

Initialize the project

We'll initialize an empty rust project using the cargo command-line tool.

cargo init --bin hello-cgi

Add the CGI crate

cargo add cgi

Writing the CGI app

We'll write a simple CGI app that prints Hello, World! to the standard output. This app also accepts a name as a body of the request and prints Hello, {name}!

Note: This cgi app will be wired to WCGI and will be served on the root path.

src/main.rs
use cgi::{http::StatusCode, Request, Response};
 
fn main() {
    cgi::handle(handler);
}
 
fn handler(request: Request) -> Response {
    let who = String::from_utf8_lossy(request.body());
    let who = if who.trim().is_empty() {
        "World"
    } else {
        who.trim()
    };
 
    cgi::text_response(StatusCode::OK, format!("Hello, {who}!"))
}
 

Wiring it up with WCGI

We'll use the wcgi runner from Wasmer to run our CGI app. This wiring up is done automatically by the wasmer runtime and we just need to specify the runner.

Cargo.toml
[package]
name = "<your-namespace>/<your-package-name>"
version = "0.1.0"
description = "An application sample for WCGI"
license = "MIT OR Apache-2.0"
 
[[module]]
name = "server"
source = "target/wasm32-wasi/release/hello-cgi.wasm"
abi = "wasi"
 
[[command]]
name = "server"
module = "server"
runner = "https://webc.org/runner/wcgi" # 👈🏼 This is the runner we'll be using
 
[command.annotations.wasi]
env = ["SCRIPT_NAME=rust_wcgi"] # This hack is required for now
 
[command.annotations.wcgi]
dialect = "rfc-3875" # This is the CGI dialect we'll be using
ℹ️
    1. your-namespace: This is usually your username and also can be your organization name.
    1. your-package-name: This is the name of your package that'll be published to the wasmer-registry.

Building the CGI app

As you see above in the source property, in the module section. We use the release build in wasm32-wasi target.

cargo build --release --target wasm32-wasi

This will create a hello-cgi.wasm file in the target/wasm32-wasi/release directory.

Running the CGI app

Now we can test our CGI app locally using the wasmer command-line.

wasmer run . --net

The above command will start a local server on port 8000.

To test the app, we can use curl to send a request to the server.

curl http://localhost:8000

The root path will return Hello, World! as we didn't specify any name in the body.

Hello, World!
curl -X POST -d "Wasmer" http://localhost:8000

The above command will send a POST request with the body Wasmer to the server.

Hello, Wasmer!

Deploying the CGI app

For this we need to create a app.yaml in the root of the project.

app.yaml
---
kind: wasmer.io/App.v0
name: <your-app-name> # 👈🏼 This is the name of your app
package: <your-namespace>/<your-package-name> # 👈🏼 This is the name of your package that you set above

This would be the final directory structure that you'll see:

Now write the following command to deploy the app.

wasmer deploy
Loaded app from: /Volumes/Work/Projects/wasmer-edge/wcgi-rust-template/app.yaml
 
Publish new version of package '<your-namespace>/<your-package-name>'? yes # 👈🏼 choose yes here
Publishing package...
[1/2] ⬆️   Uploading...
[2/2] 📦  Publishing...
Successfully published package `<your-namespace>/<your-package-name>@0.1.0`
Waiting for package to become available.......
Package 'wasmer/wcgi-rust-template@0.1.17' published successfully!
 
Deploying app <your-app-name>...
 
  App <your-namespace>/<your-app-name> was successfully deployed!
 
> App URL: https://wasmer-wcgi-rust-template.wasmer.app # 👈🏼 This is the URL of our app
> Versioned URL: https://rp9hwiqclq02.id.wasmer.app # 👈🏼 This is the versioned URL of our app
> Admin dashboard: https://wasmer.io/apps/wasmer-wcgi-rust-template
 
Waiting for new deployment to become available...
(You can safely stop waiting now with CTRL-C)
.
New version is now reachable at https://wasmer-wcgi-rust-template.wasmer.app
Deployment complete

Testing the deployed app

We can test the deployed app using curl.

curl https://wasmer-wcgi-rust-template.wasmer.app
Hello, World!

Works as expected!

Conclusion

In this tutorial, we learned how to deploy a CGI app on Wasmer Edge.

References

Resources

We've have also created a template repository for you to get started with CGI apps on Wasmer Edge.

wasmerio/wcgi-rust-template

Next steps