{"id":15047227,"url":"https://github.com/jmz-mzr/webserv","last_synced_at":"2026-04-09T05:32:31.736Z","repository":{"id":227857432,"uuid":"772569422","full_name":"jmz-mzr/webserv","owner":"jmz-mzr","description":"A high-performance, non-blocking C++ web server emulating NGINX functionality","archived":false,"fork":false,"pushed_at":"2024-03-28T10:01:34.000Z","size":14599,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-02T13:52:24.128Z","etag":null,"topics":["42","42born2code","42cursus","42network","42paris","42school","cpp","cpp98","http","http-server","nginx","webserver"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jmz-mzr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2024-03-15T13:04:07.000Z","updated_at":"2024-04-06T13:32:18.000Z","dependencies_parsed_at":"2024-03-28T11:36:30.465Z","dependency_job_id":null,"html_url":"https://github.com/jmz-mzr/webserv","commit_stats":null,"previous_names":["jmz-mzr/webserv"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jmz-mzr/webserv","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmz-mzr%2Fwebserv","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmz-mzr%2Fwebserv/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmz-mzr%2Fwebserv/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmz-mzr%2Fwebserv/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jmz-mzr","download_url":"https://codeload.github.com/jmz-mzr/webserv/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmz-mzr%2Fwebserv/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31587833,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T14:31:17.711Z","status":"online","status_checked_at":"2026-04-09T02:00:06.848Z","response_time":112,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["42","42born2code","42cursus","42network","42paris","42school","cpp","cpp98","http","http-server","nginx","webserver"],"created_at":"2024-09-24T20:55:17.215Z","updated_at":"2026-04-09T05:32:31.716Z","avatar_url":"https://github.com/jmz-mzr.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Webserv\n\n\u003cp align=\"center\"\u003e\n  \u003cimg alt=\"GIF showing an interactive website served with Webserv\" src=\"https://github.com/jmz-mzr/webserv/assets/60391881/55091ea5-d1fc-474f-aef5-94695ce98072\"\u003e\n\u003c/p\u003e\n\n\u003cdetails align=\"center\"\u003e\n\u003csummary\u003e\u003cb\u003eTable of Contents\u003c/b\u003e\u003c/summary\u003e\n\u003cdiv align=\"left\"\u003e\n\u003cbr\u003e\n\n- [Overview](#overview)\n  - [Features](#features)\n- [Installation](#installation)\n- [Usage](#usage)\n  - [How requests are processed](#how-requests-are-processed)\n- [Configuration](#configuration)\n  - [All the directives](#directives)\n- [Debugging and Logs](#debugging-and-logs)\n- [Testing](#testing)\n- [Uninstallation](#uninstallation)\n- [Documentation](#documentation)\n\n\u003c/div\u003e\n\u003c/details\u003e\n\n\u003cbr\u003e\n\n## Overview\n\nWebserv is a high-performance, non-blocking web server designed to replicate NGINX's functionality.  \nDeveloped in C++ for MacOS and Linux, it serves static websites, supports large file uploads and downloads, and is configurable to a high degree, just like NGINX.  \nIt implements the HTTP protocol standards as defined in [RFC 9112](https://www.rfc-editor.org/rfc/rfc9112), [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110), and [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986).\n\n### Features\n\n- Multiple virtual servers IPv4 \u0026 IPv6 compatibles\n- Customizable route serving, error pages, redirections, response codes\n- Default index files for directory requests\n- Limit on allowed request methods \u0026 client body size, directory listing on/off toggling\n- CGI support for external program execution ([RFC 3875](https://www.rfc-editor.org/rfc/rfc3875))\n- PHP and Perl interactive website examples with cookie and session management\n- Multiple testers allowing a perfect CI flow\n\n\u003cbr\u003e\n\n## Installation\n\n```sh\nsource configure \u0026\u0026 make install\n```\n\nYou can change the installation directory with the `INSTALLDIR` variable in the [`configure`](https://github.com/jmz-mzr/webserv/blob/main/configure) file. By default, it is installed in `$HOME/.local`.\n\n\u003cbr\u003e\n\n## Usage\n\n```sh\nwebserv [configuration file]\n```\n\nProvide your own configuration file as first argument. Without it, `$INSTALLDIR/etc/webserv/default.conf` is used as the default one.  \nThe file [`default.conf`](https://github.com/jmz-mzr/webserv/blob/main/default.conf) of this repository is used to run all the provided tests and examples.\n\nThe server root is the `$INSTALLDIR/var/www/webserv` directory. After installation, it is a copy of the `www` directory of this repository.  \nAs with NGINX, use the [root](#configuration) or [alias](#configuration) directives in the virtual servers of your configuration file, to set a custom relative or absolute path for the files served in response to a request.\n\n### How requests are processed\n\nThe requested are processed [the same way as NGINX](https://nginx.org/en/docs/http/request_processing.html):\n\n1. Virtual servers listen to an `address[:port]` pair. If no port is given, they listen on port `8000`. Without a given [listen](#configuration) directive, they listen to `*:8000`.\n2. When a request reaches the web server through an `address[:port]` pair, the [server_name](#configuration) directive selects which corresponding virtual server will serve it. If the request’s `Host` header field does not match any virtual server name, the first virtual server with a matching `address[:port]` is used.\n3. The selected virtual server searches for the most specific prefix location regardless of the listed order. Then it checks nested extension locations in the order listed. The first matching expression is the location used. If no expression matches the request, then the most specific prefix location found earlier is used.\n\n\u003cbr\u003e\n\n## Configuration\n\nThe configuration file's structure is the same as the [NGINX structure](https://nginx.org/en/docs/beginners_guide.html#conf_structure), with only the `server{}` and `location{}` blocks.  \n\u003cspan id=\"directives\"/\u003e\n\nThe directives are inherited: a child context inherits the settings of its parent level. For example, a `server{}` block directive is inherited by all the `location{}` blocks in it. However, when the same directive is defined again in a child context, it overrides the parent value.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eHere are all the directives\u003c/b\u003e\u003c/summary\u003e\n\u003cbr\u003e\n  \n| Directive\u003cbr\u003e(links to NGINX version) | Syntax | Default | Informations |\n| :---: | :---: |  :---: |  --- |\n| \u003cspan id=\"listen\"\u003e[listen][1]\u003c/span\u003e | `listen `*`address[:port]`*`;` | `listen *:8000;` | An address may be a hostname, a IPv4, or a IPv6 in square brackets (e.g.`[::1]`). |\n| \u003cspan id=\"server_name\"\u003e[server_name][2]\u003c/span\u003e | `server_name `*`name ...`*`;` | `server_name \"\";` | Names are case-insensitive. An IP is also a valid name. |\n| \u003cspan id=\"root\"\u003e[root][3]\u003c/span\u003e | `root `*`path`*`;` | `root html;` | Sets the root directory for requests. |\n| \u003cspan id=\"alias\"\u003e[alias][4]\u003c/span\u003e | `alias `*`path`*`;` | / | Defines a replacement for the specified location. |\n| \u003cspan id=\"index\"\u003e[index][5]\u003c/span\u003e | `index `*`file`*`;` | `index index.html;` | Defines a file used as an index. |\n| \u003cspan id=\"return\"\u003e[return][6]\u003c/span\u003e | `return `*`code [text]`*`;` / `return `*`code URL`*`;` / `return `*`URL`*`;` | / | Specifies a redirect URL (for codes 301, 302, 303, 307, and 308) or the response body text (for other codes). A redirect URL can be a URI local to this server. |\n| \u003cspan id=\"error_page\"\u003e[error_page][7]\u003c/span\u003e | `error_page `*`code ... uri`*`;` | / | Defines the URI that will be shown for the specified error(s). |\n| \u003cspan id=\"cgi_pass\"\u003ecgi_pass\u003c/span\u003e | `cgi_pass `*`path`*`;` | / | Defines a script to execute for requests at this specific location. |\n| \u003cspan id=\"client_max_body_size\"\u003e[client_max_body_size][8]\u003c/span\u003e | `client_max_body_size `*`size`*`;` | / | Sets the maximum allowed size of the client request body. |\n| \u003cspan id=\"ignore_except\"\u003eignore_except\u003c/span\u003e | `ignore_except `*`method ...`*`;` | / | Ignores the location match for requests with the given method(s). |\n| \u003cspan id=\"limit_except\"\u003elimit_except\u003c/span\u003e | `limit_except `*`method ...`*`;` | / | Returns 403 for requests with the given method(s). |\n| \u003cspan id=\"hide_limit_rule\"\u003ehide_limit_rule\u003c/span\u003e | `hide_limit_rule `*`on / off`*`;` | `hide_limit_rule off;` | Returns 405 instead of 403 for requests hitting `limit_except`. |\n| \u003cspan id=\"autoindex\"\u003e[autoindex][9]\u003c/span\u003e | `autoindex `*`on / off`*`;` | `autoindex off;` | Enables or disables the directory listing output. |\n| \u003cspan id=\"hide_directory\"\u003ehide_directory\u003c/span\u003e | `hide_directory `*`on / off`*`;` | `hide_directory off;` | Returns 404 instead of 403 for requests hitting a directory without `autoindex`. |\n\n[1]: https://nginx.org/en/docs/http/ngx_http_core_module.html#listen\n[2]: https://nginx.org/en/docs/http/ngx_http_core_module.html#server_name\n[3]: https://nginx.org/en/docs/http/ngx_http_core_module.html#root\n[4]: https://nginx.org/en/docs/http/ngx_http_core_module.html#alias\n[5]: https://nginx.org/en/docs/http/ngx_http_index_module.html#index\n[6]: https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#return\n[7]: https://nginx.org/en/docs/http/ngx_http_core_module.html#error_page\n[8]: https://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size\n[9]: https://nginx.org/en/docs/http/ngx_http_autoindex_module.html#autoindex\n\n\u003c/details\u003e\n\n\u003cbr\u003e\n\n## Debugging and Logs\n\n```sh\nmake debug\n```\n\nThe compiled debug version is the `webserv_debug` binary at the root of this repository. It has far more verbose and helpful logs.\n\nLogs are stored in `$INSTALLDIR/var/log/webserv.log`, and in `/tmp/webserv.log` for the debug version.  \nIf their size exceeds 20MB, they rotate in a new file, appending “.old“ to the previous one.\n\n\u003cbr\u003e\n\n## Testing\n\nThree testing suites are provided:\n\n- An extensive [Python tester](https://github.com/jmz-mzr/webserv/tree/main/tests/http_py) for HTTP protocol and configuration directives compliance\n- A 42 tester for load stress-testing and large file exchanges with multiple clients\n- A [GoogleTest suite](https://github.com/jmz-mzr/webserv/tree/main/tests/cpp_gtest/data) for configuration parsing and possible directives' values\n\nRun the tests from the root of this repository with:\n\n```sh\n./tests/run_tests.sh\n```\n\nTo enable the GoogleTest suite, you need to have CMake installed, then run:\n\n```sh\nmake test\n```\n\n\u003e [!IMPORTANT]\n\u003e To run correctly, the testers expect the `default.conf` file of this repository, and `$INSTALLDIR/var/www/webserv` to have at least the content of the `www` directory of this repository.\n\n\u003cdiv align=\"center\"\u003e\n  \u003cvideo src=\"https://github.com/jmz-mzr/webserv/assets/60391881/19abd646-6048-4dc2-af2f-50f958e42858\" height=\"1080\" width=\"1920\" /\u003e\n\u003c/div\u003e\n\n\u003cbr\u003e\n\n## Uninstallation\n\n\u003e [!TIP]\n\u003e\n\u003e ```sh\n\u003e source configure -u\n\u003e ```\n\u003e\n\u003e This unsets the webserv-specific environment variables, cleans the `PATH` variable if relevant, removes the installed binary, and all the webserv-related files (after asking for confirmation).\n\n\u003e [!CAUTION]\n\u003e\n\u003e ```sh\n\u003e make uninstall\n\u003e ```\n\u003e\n\u003e This removes the installed binary, the `$INSTALLDIR/etc/webserv` configuration directory, and the `$INSTALLDIR/var/www/webserv` directory serving your files (without asking for confirmation).\n\n\u003cbr\u003e\n\n## Documentation\n\nFor more details on the HTTP protocol:\n\n- [HTTP Overview](https://developer.mozilla.org/en-US/docs/Web/HTTP)\n- [HTTP Methods](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods)\n- [HTTP Headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers)\n- [HTTP Response Codes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjmz-mzr%2Fwebserv","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjmz-mzr%2Fwebserv","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjmz-mzr%2Fwebserv/lists"}