BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News NGINX Modules Can Now Be Written in Rust

NGINX Modules Can Now Be Written in Rust

This item in japanese

NGINX announced the availability of ngx-rust project, allowing developers to write NGINX modules in Rust. The Rust programming language has emerged as a powerful and popular choice due to its stability, security features, rich ecosystem, and strong community support.

NGINX is a high-performance, open-source web server and reverse proxy server software that powers a significant portion of the internet's websites. Initially created by Igor Sysoev in 2002, NGINX has since evolved and gained widespread popularity in web hosting, content delivery, and application deployment. It is known for its performance, scalability, and versatility, making it a crucial component for serving web content and managing internet traffic efficiently.

The three principal functions of NGINX are:

  • Web Server: NGINX primarily operates as a web server, handling HTTP and HTTPS requests. It can serve static web content such as HTML files, images, and JavaScript, making it an essential component for hosting websites and web applications.
  • Reverse Proxy Server: NGINX can work as a reverse proxy server, serving as an intermediary between client requests and backend servers. It is often deployed to distribute incoming requests across multiple backend servers, ensuring load balancing and fault tolerance. This is particularly valuable in high-traffic environments.
  • Load Balancer: NGINX can act as a load balancer, distributing incoming network traffic across multiple servers. This ensures that servers don't get overloaded, optimizing the use of resources and providing a seamless experience to users.

Originally, ngx-rust was created to expedite the development of an Istio-compatible service mesh product with NGINX. However, this project remained dormant for some time, during which the community actively engaged with it, forking the repository and creating their projects based on the Rust bindings examples provided by ngx-rust.

More recently, F5's Distributed Cloud Bot Defense team required the integration of NGINX proxies into its protection services. This necessitated the development of a new module. At the same time, F5 aimed to expand its Rust portfolio and improve the developer experience to meet evolving customer needs. With internal innovation sponsorships and collaboration with the original ngx-rust author, F5 revitalized the ngx-rust project. This revival involved publishing ngx-rust crates with enhanced documentation and improved build ergonomics for community usage.

NGINX relies on modules as the fundamental building blocks that implement most functionality. Modules also empower NGINX users to customize its features and support specific use cases. Traditionally, NGINX supported modules written in C, but advancements in computer science and programming language theory have allowed languages like Rust to be used for NGINX module development.

To get started with ngx-rust, you can choose to build from source locally, contribute to the ngx-rust project, or simply obtain the crate from crates.io. The ngx-rust README provides guidelines for contributing and local build requirements. While ngx-rust is still in its early stages of development, F5 plans to enhance its quality and features with community support.

The ngx-rust project comprises two key crates:

  • nginx-sys: This crate generates bindings from NGINX source code, automating the creation of foreign function interface (FFI) bindings through  bindgen code automation.
  • ngx: The main crate implements Rust glue code, APIs, and re-exports nginx-sys. Module writers interact with NGINX through ngx symbols, and the re-export of nginx-sys eliminates the need for explicit import.

The process of initializing a workspace for an ngx-rust project involves creating a working directory, initializing a Rust project, and setting up dependencies:

cd $YOUR_DEV_FOLDER
mkdir ngx-rust-howto
cd ngx-rust-howto
cargo init --lib

 

Creating a Rust module involves implementing the HTTPModule trait, which defines the NGINX entry points, including postconfiguration, preconfiguration, create_main_conf, and more. The new module only needs to implement the functions necessary for its specific task. The following code is an example of postconfiguration method implementation:

 

struct Module;
struct Module; 

impl http::HTTPModule for Module { 
    type MainConf = (); 
    type SrvConf = (); 
    type LocConf = ModuleConfig; 

    unsafe extern "C" fn postconfiguration(cf: *mut ngx_conf_t) -> ngx_int_t { 
        let htcf = http::ngx_http_conf_get_module_main_conf(cf, &ngx_http_core_module); 

        let h = ngx_array_push( 
            &mut (*htcf).phases[ngx_http_phases_NGX_HTTP_ACCESS_PHASE as usize].handlers, 
        ) as *mut ngx_http_handler_pt; 
        if h.is_null() { 
            return core::Status::NGX_ERROR.into(); 
        } 

        // set an Access phase handler 
        *h = Some(howto_access_handler); 
        core::Status::NGX_OK.into() 
    } 
} 

 

More example code and implementations are available at the ngx-rust-howto repository.

With the introduction of the ngx-rust project, NGINX is embracing the Rust programming language, providing developers with a new way of writing NGINX modules. This initiative aims to enhance NGINX's capabilities and offer developers a safer and more ergonomic way to work with the web server. Also, Cloudflare started to use Rust for the NGINX module implementation, as reported in this detailed blog post.

About the Author

Rate this Article

Adoption
Style

BT