At Gcore, we operate a cutting-edge CDN that relies heavily on the scalability and performance of nginx. While nginx offers us a solid foundation, we recognize the need to extend its functionalities with custom modules to better serve our CDN requirements. Traditionally, these modules were written in the C programming language, but C has exposed our codebase to a variety of bugs, particularly those related to memory corruption. That’s why we turned to Rust—a language renowned for its focus on performance, reliability, and productivity. In this article, we’ll delve into why we decided to use Rust, introduce our new nginx bindings library, and provide some insights into the benefits we’ve observed.
The Rust programming language offers us a robust set of features aimed at minimizing bugs and enhancing code safety. Rust emphasizes aspects like performance and reliability—attributes that align seamlessly with our objectives. After transitioning to Rust, we found that not only were there fewer bugs, but the development time for new features also significantly decreased compared to C.
For Rust code to interact smoothly with nginx’s C API, an interface layer is essential. While there are existing crates like nginx, ngx, and nginx-rs, we felt the need to build a more secure abstraction layer. Our goal was to leverage Rust’s type system fully and features like lifetimes to maximize safety. For instance, Rust’s lifetime ensures that values stored in a Request’s internal memory pool are accessible only while the Request itself is alive.
We’re delighted to announce that we’re open-sourcing our very own nginx bindings library—nginx-rust. This library empowers developers to create their custom nginx modules using Rust, benefitting from its myriad advantages.
We’ve included a straightforward example in our library for those keen to get started. This example demonstrates how to configure nginx to reject incoming requests with user agents that start with a particular, configurable string. What sets this example apart is that it’s designed as a static nginx module rather than a dynamic one, unlike many similar projects. Plus, the build process is fully integrated with nginx, making it seamless.
Our provided example serves as a practical guide for creating an nginx module specifically designed to block requests with user agents that begin with a certain substring. The configuration within
deny_user_agent curl;. This directive effectively blocks all incoming requests from user agents that kick off with the substring “curl”.
Give this a test run on your local nginx server:
curl localhostwill result in a 403 Forbidden response.
- On the other hand, running
curl localhost --user-agent "not curl"will bypass this filter and proceed without issues.
As mentioned, our build process is fully integrated with nginx thanks to the
config.make files we’ve provided. The
config file is fairly standard, resembling any other configuration file you might come across for an nginx module. However, it does include a specific link time dependency on the static library generated using Rust.
config.make file, we specify the usage of
cargo, Rust’s native package manager, to compile this static library. This file also notifies nginx’s build process of all Rust package dependencies so that any modifications made to the Rust code will be accounted for whenever you execute a
make command for nginx.
This example module is only a starting point. We encourage you to use it as a skeleton for your own nginx modules using the full power of the Rust language and Rust’s ecosystem. Feel free to include any dependencies from crates.io as you craft your own high-performance, secure nginx modules.
The shift to Rust has been a transformative experience for us at Gcore, yielding fewer bugs and faster development cycles. We hope that by sharing our journey and open-sourcing our nginx-rust library, we can help the broader community realize the incredible potential of integrating Rust with nginx.
We encourage you to explore nginx-rust and start building your own high-performance, secure nginx modules today!