Nginx 2.0 is a cutting-edge, event-driven web server designed with efficiency, scalability, and HTTP protocol compliance at its core. Inspired by the original Nginx architecture, our goal was to create a web server that matches its predecessor in performance, flexibility, and ease of use. Developed through the collaborative efforts of myself and Tukka, Nginx 2.0 embodies our commitment to innovation, offering a robust platform for both static and dynamic web content, optimized for modern web applications and services.
Our journey in developing Nginx 2.0 has been driven by a commitment to innovation, performance, and the pursuit of excellence in web serving technology. Here, we delve into the core features that embody our ambitions and technical prowess, showcasing the strides we've made in redefining the capabilities of a modern web server.
In crafting Nginx 2.0, we prioritized strict adherence to the HTTP/1.1 standard, ensuring our server robustly supports essential HTTP methods such as GET, HEAD, POST, and DELETE. This commitment not only aligns with our goal for broad compatibility but also reflects our dedication to providing a solid, reliable foundation for web serving.
The complexity and diversity of web server configurations led us to implement a recursive descent parser, mirroring the hierarchical model seen in Nginx. This strategy enhances configuration management, making it intuitive and manageable while preserving the flexibility needed for complex setups.
Understanding the diverse environments in which our server operates, we developed a custom abstraction layer for I/O multiplexing that seamlessly integrates with both kqueue (macOS) and epoll (Linux). This cross-platform approach is a testament to our commitment to optimizing performance across different systems, ensuring Nginx 2.0 performs efficiently under various operational conditions.
Our focus on efficiency and performance is particularly evident in how Nginx 2.0 handles large responses and video streaming. By supporting Transfer-Encoding: chunked and Range requests, we've optimized the delivery of large content, ensuring minimal resource usage while maintaining smooth, uninterrupted video playback. This feature is a direct outcome of our dedication to enhancing user experiences, addressing common challenges in content delivery with innovative solutions.
To extend the server's capabilities beyond serving static content, we integrated comprehensive CGI support into Nginx 2.0. This allows for the execution of external programs for dynamic content generation and form processing, among other tasks. This integration reflects our vision for a versatile web server that can cater to a wide range of web application requirements, offering the flexibility needed for developing interactive, personalized web experiences.
The development of a configurable logging framework within Nginx 2.0 stems from our recognition of the critical role that logging plays in understanding and optimizing server operations. By implementing a system that supports multiple log levels and allows for dynamic configuration of log outputs, we've provided ourselves with a powerful tool for monitoring, debugging, and improving server performance. This framework embodies our commitment to transparency and control, ensuring that we can always keep a pulse on the server's health and efficiency.
Welcome to Nginx 2.0, an event-driven web server designed for efficiency, scalability, and compliance with the HTTP/1.1 standard. This guide will walk you through the steps to install and build Nginx 2.0 on your system.
Before you begin, ensure your system meets the following requirements:
Nginx 2.0 uses a Makefile for building from source. Follow these steps to clone the repository and build the server:
Clone the Repository
Start by cloning the Nginx 2.0 repository to your local machine:
git clone https://github.com/anassajaanan/Nginx-2.0
cd nginx-2.0Build the Project
You can build the project in two configurations: debug for development and release for production.
Debug Build:
The debug build includes additional debug symbols and is compiled with address and undefined behavior sanitizers (on macOS) or with strong protection and overflow checks (on Linux) for development and testing purposes.
make debugRelease Build:
The release build is optimized for performance with -O3 optimization, native architecture targeting, and link-time optimization. This is the recommended configuration for deployment.
make prodRunning Nginx 2.0
To start the server, specify a configuration file path if desired. If no path is provided, the server will use the default configuration located at [conf/nginx.conf]
./webserver [configfile_path] # For release buildReplace [configfile_path] with the path to your configuration file. If omitted, Nginx 2.0 will use the default configuration.
For a debug build:
./webserver_debug [configfile_path] # For debug buildTo clean up build artifacts and start fresh, use the clean or fclean commands:
Clean Objects and Dependencies:
make cleanFull Clean (Including Binaries):
make fcleanValgrind Memory Check:
For Linux users, run your debug build with Valgrind to check for memory leaks:
make valgrindEnsure Valgrind is installed on your system for this to work.
This section outlines the directives available in Nginx 2.0, their applicable contexts, validation policies, and usage examples. This structured approach ensures a clear understanding of how to configure your web server effectively.
rootContexts Allowed: server, location
Validation Policy: Must be unique within its context.
Example:
server {
root /var/www/html; # Document root
}listenContexts Allowed: server
Validation Policy: Must be unique within its context.
Example:
server {
listen 8080; # Server listens on port 8080
}autoindexContexts Allowed: server, location
Validation Policy: Must be unique within its context.
Example:
location /images {
autoindex on; # Enables directory listing
}server_nameContexts Allowed: server
Validation Policy: Must be unique within its context.
Example:
server {
server_name example.com;
}client_max_body_sizeContexts Allowed: http, server
Validation Policy: Must be unique within its context.
Example:
http {
client_max_body_size 20M; # Limits request body size
}error_pageContexts Allowed: http, server, location
Validation Policy: Supports two or more arguments.
Example:
server {
error_page 404 /404.html;
}try_filesContexts Allowed: server, location
Validation Policy: Must be unique within its context, supports two or more arguments. The last argument is treated as a fallback.
Example:
location / {
try_files $uri $uri/ /index.html;
}indexContexts Allowed: http, server, location
Validation Policy: Supports one or more arguments. The server will use the first found file as the index. The last argument is treated as a fallback if it starts with a slash. If no index is found, a directory listing is shown.
Example:
location / {
index index.html index.htm /fallback;
}returnContexts Allowed: server, location
Validation Policy: Supports either one argument as a status code to return a predefined status message, or two arguments where the first is the status code and the second is a URL for redirection or text to return as the body. When used for redirection, common status codes are 301 (permanent redirect) or 302 (temporary redirect).
Example 1: Returning a Status Code with Text:
location /gone {
return 410 "The resource is no longer available";
}This configuration returns a 410 status code with a custom message indicating that the resource is no longer available.
Example 2: Redirection:
location /oldpage {
return 301 http://example.com/newpage;
}This directive redirects requests for /oldpage to a new URL with a 301 status code, indicating a permanent redirect.
limit_exceptContexts Allowed: location
Validation Policy: Must be unique within its context, supports one or more arguments to specify allowed HTTP methods.
Example:
This directive restricts the allowed methods for the /api endpoint to GET and POST, denying all other methods.
location /api {
limit_except GET POST;
}keepalive_timeoutContexts Allowed: http, server
Validation Policy: Must be unique within its context.
Example:
server {
keepalive_timeout 15; # Keep connections alive for 15 seconds
}cgi_extensionContexts Allowed: server
Validation Policy: Must be unique within its context, supports one or more arguments. Specifies the file extensions to be treated as CGI scripts.
Example:
server {
cgi_extension .cgi .pl .py .sh .extension; # Handle .cgi .pl .py files as CGI scripts
}This comprehensive example demonstrates a server setup with nested contexts and multiple directives, showcasing a realistic configuration for Nginx 2.0.
http {
client_max_body_size 20M; # Apply to all servers
keepalive_timeout 15; # Connection keep-alive timeout
server {
listen 8080;
server_name localhost;
root /var/www/example;
index index.html index.htm index.php;
# Serve static files directly
location / {
try_files $uri $uri/ /fallback;
}
# Enable directory listing for /images
location /images {
autoindex on;
root /var/www/example;
}
# Custom error pages
error_page 404 /404.html;
error_page 500 502 /50x.html;
# API endpoint with method restrictions
location /api {
limit_except GET POST DELETE;
}
# CGI script execution for specific extensions
cgi_extension .cgi .pl;
}
}
This guide and example should equip you with the knowledge to configure Nginx 2.0 effectively, ensuring your web server is tailored to your specific requirements and operational contexts.
Below is an overview of the Nginx 2.0 project structure, providing insight into the organization of the codebase and the purpose of each directory and key files:
/web-server-project
├── src # Source files
│ ├── config # Configuration-related classes and files
│ │ ├── BaseConfig.cpp
│ │ ├── BaseConfig.hpp
│ │ ├── LocationConfig.cpp
│ │ ├── LocationConfig.cpp
│ │ ├── MimeTypeConfig.cpp
│ │ ├── MimeTypeConfig.hpp
│ │ ├── ReturnDirective.cpp
│ │ ├── ReturnDirective.hpp
│ │ ├── ServerConfig.cpp
│ │ ├── ServerConfig.hpp
│ │ ├── TryFilesDirective.cpp
│ │ └── TryFilesDirective.hpp
│ │
│ ├── cgi # CGI handling classes
│ │ ├── CgiDirective.hpp
│ │ ├── CgiDirective.cpp
│ │ ├── CgiHandler.hpp
│ │ └── CgiHandler.cpp
│ │
│ ├── http # HTTP protocol handling classes
│ │ ├── HttpRequest.hpp
│ │ ├── HttpRequest.cpp
│ │ ├── HttpResponse.hpp
│ │ ├── HttpResponse.cpp
│ │ ├── HttpRequest.cpp
│ │ ├── RequestHandler.hpp
│ │ └── RequestHandler.cpp
│ │
│ ├── logging # Logging functionality
│ │ ├── Logger.hpp
│ │ └── Logger.cpp
│ │
│ ├── parsing # Dedicated parsing logic
│ │ ├── ConfigLoader.cpp
│ │ ├── ConfigLoader.hpp
│ │ ├── ConfigNode.cpp
│ │ ├── ConfigNode.hpp
│ │ ├── ConfigParser.cpp
│ │ ├── ConfigParser.hpp
│ │ ├── ConfigTokenizer.cpp
│ │ ├── ConfigTokenizer.hpp
│ │ ├── ContextNode.cpp
│ │ ├── ContextNode.hpp
│ │ ├── DirectiveNode.cpp
│ │ ├── DirectiveNode.hpp
│ │ ├── LogicValidator.cpp
│ │ ├── LogicValidator.hpp
│ │ ├── MimeTypeParser.cpp
│ │ ├── MimeTypeParser.hpp
│ │ ├── SyntaxValidator.cpp
│ │ ├── SyntaxValidator.hpp
│ │ ├── TreeBuilder.cpp
│ │ └── TreeBuilder.hpp
│ │
│ ├── event_polling # Abstraction over kqueue and Epoll
│ │ ├── EpollManager.cpp
│ │ ├── EpollManager.hpp
│ │ ├── EventPoller.cpp
│ │ ├── EventPoller.hpp
│ │ ├── KqueueManager.cpp
│ │ └── KqueueManager.hpp
│ │
│ ├── server # Core server functionality
│ │ ├── ClientState.cpp
│ │ ├── ClientState.hpp
│ │ ├── ResponseState.cpp
│ │ ├── ResponseState.hpp
│ │ ├── Server.cpp
│ │ ├── Server.hpp
│ │ ├── ServerManager.cpp
│ │ └── ServerManager.hpp
│ │
│ └── main.cpp # Entry point of the application
│
├── conf # Configuration files (e.g., nginx.conf, mime.types)
├── content # Static content served by the server
├── logs # Log files generated by the server
├── uploads # Directory for handling uploaded files
└── Makefile # Build instructions for your project
This structure is designed to enhance maintainability and scalability, ensuring that anyone can easily navigate and contribute to the project.
To aid in further exploration and mastery of web server development, networking, and programming concepts, we recommend the following curated list of resources:
select() - Understanding the select() system call for multiplexing.select() - Deep dive into non-blocking I/O operations and the use of select().Special thanks are extended to Abdelaziz Eroui for his informative lecture on TCP/IP and socket programming, part of The Missing Semester series, which provided deep insights into the fundamentals of networking critical to our project's success.
We would also like to express our gratitude to Mehdi Cheracher for his lecture on networking and asynchronous programming. His teachings have been instrumental in guiding our approach to handling network communications efficiently.
Their contributions to the field and dedication to education have been invaluable to both our project and the wider community.
We warmly welcome contributions from the community and are thrilled to have you join us in improving Nginx 2.0! Whether you're fixing bugs, adding new features, or improving documentation, your contributions are invaluable to making Nginx 2.0 better for everyone.
If you have any questions or need assistance, feel free to reach out by opening an issue. We're here to help and look forward to your contributions!