{"id":22298090,"url":"https://github.com/password123456/setup-nginx-http-server-with-security-best-practice","last_synced_at":"2026-02-10T22:32:01.859Z","repository":{"id":265195724,"uuid":"895415168","full_name":"password123456/setup-nginx-http-server-with-security-best-practice","owner":"password123456","description":"Nginx HTTP Server security best practice","archived":false,"fork":false,"pushed_at":"2024-11-28T07:01:45.000Z","size":26,"stargazers_count":1,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-05T05:37:29.860Z","etag":null,"topics":["nginx","nginx-configuration","nginx-hardening","nginx-security","nginx-server"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/password123456.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,"publiccode":null,"codemeta":null}},"created_at":"2024-11-28T07:00:37.000Z","updated_at":"2025-02-27T11:56:57.000Z","dependencies_parsed_at":"2024-11-28T10:17:11.588Z","dependency_job_id":null,"html_url":"https://github.com/password123456/setup-nginx-http-server-with-security-best-practice","commit_stats":null,"previous_names":["password123456/setup-nginx-http-server-with-security-best-practice"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/password123456/setup-nginx-http-server-with-security-best-practice","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/password123456%2Fsetup-nginx-http-server-with-security-best-practice","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/password123456%2Fsetup-nginx-http-server-with-security-best-practice/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/password123456%2Fsetup-nginx-http-server-with-security-best-practice/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/password123456%2Fsetup-nginx-http-server-with-security-best-practice/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/password123456","download_url":"https://codeload.github.com/password123456/setup-nginx-http-server-with-security-best-practice/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/password123456%2Fsetup-nginx-http-server-with-security-best-practice/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29319686,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-10T20:44:44.282Z","status":"ssl_error","status_checked_at":"2026-02-10T20:44:43.393Z","response_time":65,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["nginx","nginx-configuration","nginx-hardening","nginx-security","nginx-server"],"created_at":"2024-12-03T17:59:40.410Z","updated_at":"2026-02-10T22:32:01.841Z","avatar_url":"https://github.com/password123456.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Setup Nginx HTTP Server With Security Best Practice\n![Hits][hits-button]\n\n[hits-button]: https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Fpassword123456%2Fsetup-nginx-http-server-with-security-best-practice\u0026count_bg=%2379C83D\u0026title_bg=%23555555\u0026icon=\u0026icon_color=%23E7E7E7\u0026title=hits\u0026edge_flat=false\n\nThis document revisits the essential security configurations for Nginx HTTP Server from a practical perspective.\n\nBy following the key recommendations outlined below, you can avoid common configuration errors and prevent security vulnerabilities.\n\n***\n## Table of Contents\n- [1. Ensure Proper Permissions for Nginx Process Account](#1-ensure-proper-permissions-for-nginx-process-account)\n- [2. Ensure Nginx Version Information is Not Exposed](#2-ensure-nginx-version-information-is-not-exposed)\n- [3. Ensure the autoindex Feature is removed or disabled](#3-ensure-the-autoindex-feature-is-removed-or-disabled)\n- [4. Set Proper Permissions for Critical Directories and Files](#4-set-proper-permissions-for-critical-directories-and-files)\n- [5. Disabling Unused HTTP Methods](#5-disabling-unused-http-methods)\n- [6. Ensure Removal of Insecure and Outdated SSL Protocols and Ciphers](#6-ensure-removal-of-insecure-and-outdated-ssl-protocols-and-ciphers)\n- [7. Ensure Proper Permissions on SSL Certificate Files](#7-ensure-proper-permissions-on-ssl-certificate-files)\n- [8. Ensure Blocking of Arbitrary Host Connections Not Configured in the Web Server](#8-ensure-blocking-of-arbitrary-host-connections-not-configured-in-the-web-server)\n- [9. Limit Simultaneous Connections per IP](#9-limit-simultaneous-connections-per-ip)\n- [10. Limit Requests per IP](#10-limit-requests-per-ip)\n- [11. Inspect and Control Request Headers](#11-inspect-and-control-request-headers)\n- [12. Utilizing the Location Block](#12-utilizing-the-location-block)\n\n***\n\n## 1. Ensure Proper Permissions for Nginx Process Account\nNginx HTTP Server typically runs under the default `nginx`, `www-data` user account (or another non-privileged account). \n\nIt is important to ensure that Nginx is not running under a privileged account, such as `root`. If it is, it must be changed to a non-privileged user to prevent potential security risks.\n\n\n**Audit:**\n- Verify the current user account under which Nginx is running, execute the following command:\n  ```\n  [root@localhost ~]# ps -ef | grep nginx\n  root      626653       1  0 Apr08 ?        00:00:00 nginx: master process /usr/sbin/nginx\n  nginx     626654  626653  0 Apr08 ?        00:00:00 nginx: worker process\n  nginx     626655  626653  0 Apr08 ?        00:00:01 nginx: worker process\n  nginx     626656  626653  0 Apr08 ?        00:00:00 nginx: worker process\n  nginx     626657  626653  0 Apr08 ?        00:00:00 nginx: worker process\n  ```\n\n**Remediation:**\n- If Nginx is running under the `root` account or any other account with elevated privileges, modify the configuration to run under a non-privileged account such as `nginx`, `nobody`, `daemon`:\n  ```\n  [root@localhost ~]# vim /etc/nginx/nginx.conf\n  ...\n  user nginx;   # \u003c== # \u003c== Set to a non-privileged account e.g. nginx, nobody, daemon\n  ...\n  ```\n\n(1) Check sudo privileges:\n- The Nginx process account must not have sudo privileges:\n  ```\n  [root@localhost ~]# sudo -l -U nginx\n  User nginx is not allowed to run sudo on pg-sec-mqrelay01\n  ```\n\n(2) Verify shell access:\n- The Nginx process account should not have access to a login shell:\n  ```\n  [root@localhost ~]# cat /etc/passwd | grep -i nginx\n  nginx:x:498:498:Nginx web server:/var/lib/nginx:/sbin/nologin\n  ```\n\n(3) Ensure password is locked:\n- The password for the Nginx process account should be locked:\n  ```\n  [root@localhost ~]# passwd -S nginx\n  nginx LK 2023-10-16 -1 -1 -1 -1 (Password locked.)\n  ```\n\n## 2. Ensure Nginx Version Information is Not Exposed\nBy default, Nginx HTTP Server displays the version information in the HTTP response header. This can provide attackers with insights into potential vulnerabilities. Hiding the version information mitigates this risk.\n\n**Audit:**\n- Verify that Nginx version information is exposed in the HTTP response header:\n  ```\n  [root@localhost ~]# curl -i -k http://127.0.0.1\n  HTTP/1.1 200\n  Server: nginx/1.26.1\n  ...\n  ```\n**Remediation:**\n- To prevent the version information from being exposed, modify the following settings in the Nginx configuration:\n  ```\n  [root@localhost ~]# vim /etc/nginx/nginx.conf\n  http {\n        ...\n        server_tokens off;  # \u003c== Set to hide version information\n        ...\n  ```\n\n## 3. Ensure the autoindex Feature is removed or disabled\nThe autoindex feature provides directory listing functionality. Directory listing can expose critical information about the web application and server, and should be disabled by default.\n\n**Audit:**\n- Verify whether directory listing is displayed or the autoindex feature is enabled.\n  ```\n  [root@localhost ~]# vim /etc/nginx/nginx.conf\n  ...\n  \n  location / {        \n      root   /usr/local/nginx/html/html;\n      autoindex on;\n      index  index.html index.htm;\n  }\n  ```\n\n**Remediation:**\n- To disable the autoindex feature, remove or comment out the autoindex directive in the Nginx configuration:\n  ```\n  [root@localhost ~]# vim /etc/nginx/nginx.conf\n  ...\n\n  location / {        \n      root   /usr/local/nginx/html/html;\n      autoindex on;                 # \u003c== Remove or comment out\n      index  index.html index.htm;  # \u003c== Remove if necessary\n  }\n  ```\n\n## 4. Set Proper Permissions for Critical Directories and Files\nEnsure that the Nginx installation directory and configuration files are accessible only to the \"root\" user. The permissions for these directories and files should be checked and modified if any other users have access rights.\n\n**Audit:**\n- Verify the permissions of Nginx's installation directory and configuration files.\n  ```\n  [root@localhost ~]# ls -al /etc/nginx/\n  total 88\n  drwxr-xr-x.  4 root  root  4096 Aug 12 11:28 .\n  drwxr-xr-x. 87 root  root  8192 Aug  6 11:46 ..\n  drwxr-xr-x.  4 root  root    68 Aug 12 11:06 conf.d\n  drwxr-xr-x.  2 root  root     6 Jun 10  2021 default.d\n  -rw-r--r--.  1 root  root  1077 Jun 10  2021 fastcgi.conf\n  -rw-r--r--.  1 root  root  1077 Jun 10  2021 fastcgi.conf.default\n  -rw-r--r--.  1 root  root  1007 Jun 10  2021 fastcgi_params\n  -rw-r--r--.  1 root  root  1007 Jun 10  2021 fastcgi_params.default\n  -rw-r--r--.  1 root  root  2837 Jun 10  2021 koi-utf\n  -rw-r--r--.  1 root  root  2223 Jun 10  2021 koi-win\n  -rw-r--r--.  1 root  root  5170 Jun 10  2021 mime.types\n  -rw-r--r--.  1 root  root  5170 Jun 10  2021 mime.types.default\n  -rw-r--r--.  1 root  root   927 Oct 16  2023 nginx.conf\n  -rw-r--r--.  1 root  root  2656 Jun 10  2021 nginx.conf.default\n  -rw-r--r--.  1 root  root   636 Jun 10  2021 scgi_params\n  -rw-r--r--.  1 root  root   636 Jun 10  2021 scgi_params.default\n  -rw-r--r--.  1 root  root   664 Jun 10  2021 uwsgi_params\n  -rw-r--r--.  1 root  root   664 Jun 10  2021 uwsgi_params.default\n  -rw-r--r--.  1 root  root  3610 Jun 10  2021 win-utf\n  ```\n\n**Remediation:**\n- Ensure that all Nginx directories and configuration files are owned by root:root.\n- Adjust the permissions so that others (non-owners) cannot access the directories and files.\n  ```\n  [root@localhost ~]# chown root:root -R /etc/nginx\n  [root@localhost ~]# chmod o-rwx -R /etc/nginx\n  ```\n  \n## 5. Disabling Unused HTTP Methods\nWhen unused HTTP methods are enabled on a web service, they can expose vulnerabilities or unintended behaviors that may lead to abuse and become an attack vector. \n\nIt is important to disable any methods that are not in use, particularly the `TRACE` method, which is used for debugging and is generally unnecessary for normal web service operations.\n\n**HTTP Methods:**\n\n| Name    | Description                                                                                                                                         |\n|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------|\n| OPTIONS | \tUsed to check the list of supported methods by the web server.                                                                                     |\n| HEAD    | \tThe server sends only the header information in the response. It is often used to check the existence of a page by receiving the HTTP status code. |\n| GET     | \tSimilar to POST, but does not handle form input; typically used to retrieve information such as lists in forums via URI transmission.              |\n| POST    | \tUsed when sending data from a client to a web application for processing.                                                                          |\n| PUT     | \tSimilar to POST, used to save content specified by the client to the server.                                                                       |\n| DELETE  | \tUsed by the client to delete files on the server.                                                                                                  |\n| TRACE   | \tUsed to invoke a loopback message on the web server to trace the data transmission path.                                                           |\n| CONNECT | \tUsed to request proxy functionality from the web server.                                                                                           |\n\n**Audit:**\n- Verify that which HTTP methods are available on your web server:\n  ```\n  [root@localhost ~]# curl -i -k -X OPTIONS http://example.com\n  HTTP/1.1 200 OK\n  Server: nginx\n  Date: Mon, 12 Aug 2024 03:00:29 GMT\n  Content-Type: text/html; charset=utf-8\n  Content-Length: 0\n  Connection: keep-alive\n  Allow: GET, HEAD, OPTIONS, PUT, DELETE, POST, PATCH\n  ...\n  ```\n\n**Remediation:**\n- Disable TRACE Method\n- Enable Only Necessary HTTP Methods:\n  ```\n  [root@localhost ~]# vim /etc/nginx/nginx.conf\n  ...\n  \n  server {\n      ...\n      # Allow only specified methods (e.g., HEAD, GET, POST)\n      if ($request_method !~ ^(HEAD|GET|POST)$ ){\n              return 403;\n        }\n  }\n  ...\n  ```\n***Note: The $request_method directive can be applied at the server or location block level as needed.***\n\n\n## 6. Ensure Removal of Insecure and Outdated SSL Protocols and Ciphers\nWhen configuring SSL, outdated and insecure protocols or algorithms should be avoided. \n\nMajor browsers like Chrome, Microsoft Edge, and Firefox have dropped support for TLS 1.0 and TLS 1.1 due to security vulnerabilities such as POODLE and BEAST. These older protocols are known to be vulnerable to various attacks.\n\n| No. | CVE-ID        | Vulnerability Name                                      | Description                                                                |\n|-----|---------------|---------------------------------------------------------|----------------------------------------------------------------------------|\n| 1   | CVE-2014-3566 | POODLE (Padding Oracle On Downgraded Legacy Encryption) | Exploits outdated encryption methods, enabling protocol downgrade attacks. |\n| 2   | CVE-2011-3389 | BEAST (Browser Exploit Against SSL/TLS)                 | Allows attackers to decrypt HTTPS cookies and hijack sessions.             |\n\n**Deprecated Cipher Algorithms**\n- The following cipher algorithms are considered insecure and should not be used:\n  - RC4 \n  - DES \n  - 3DES \n  - MD5 \n  - aNULL \n  - eNULL \n  - EXPORT\n\n**Audit:**\n- Verify the SSL settings for `ssl_protocols` and `ssl_ciphers` configurations.\n  ```\n  [root@localhost ~]# vim /etc/nginx/nginx.conf\n  ...\n  \n  server {\n          listen       443 ssl;\n          server_name  example.com;  \n          ...  \n          ssl_protocols TLSv1 TLSv1.1 TLSv1.2; \n          ssl_ciphers HIGH:MEDIUM:aNULL:MD5:EXPORT:RC4:eNULL:DES:3DES;\n    }\n  ```\n\n**Remediation:**\n- `ssl_protocols` should use TLS 1.2 or later.\n- `ssl_ciphers` to utilize secure algorithms supported in TLS 1.2 or later.\n\n**Recommended Configuration (General Use):**\n\n- For general services (not bound by PCI-DSS), use the following configuration:\n  ```\n  ssl_protocols TLSv1.2 TLSv1.3;\n  ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;\n  ```\n- After configuration, verify the SSL security status using [SSL Labs' SSL Test.](https://www.ssllabs.com/ssltest/)\n- Refer to [Mozilla's SSL Configuration Generator](https://ssl-config.mozilla.org/) for specific configurations based on your web server and OpenSSL version.\n\n\n## 7. Ensure Proper Permissions on SSL Certificate Files\nIn cases where a web service vulnerability allows remote access to web server permissions, attackers may attempt to access SSL certificate files, potentially leading to the exposure of the private key. If the SSL certificate's private key is leaked, an attacker could create a spoofed website that appears legitimate or use the key to distribute malware. This becomes especially dangerous when SSL certificate pinning is used, or if the certificate is a wildcard certificate, as it could necessitate replacing certificates across all servers and clients.\n\nEnsure that SSL certificate files are secured by verifying and applying proper file permissions.\n\n**Audit:**\n- Verify the file ownership and permissions for the `ssl_certificate` and `ssl_certificate_key` files.\n  ```\n  [root@localhost ~]# vim /etc/nginx/nginx.conf\n  ...\n  server {\n          listen       443 ssl;\n          server_name  example.com;\n          ...\n          ssl_certificate /etc/nginx/conf.d/cert/example.com_ssl.crt;\n          ssl_certificate_key /etc/nginx/conf.d/cert/example.com_ssl.key;\n          ...\n    }\n  \n  \n  [root@localhost ~]# ls -al /etc/nginx/conf.d/cert\n  total 12\n  drwxr-x---. 2 root root   64 Apr  8 14:47 .\n  drwxr-x---. 4 root root   68 Aug 12 11:06 ..\n  -rw-r--r--. 1 nobody root 7869 Apr  8 14:45 example.com_ssl.crt\n  -rw-r--r--. 1 nobody root 1679 Apr  8 14:44 example.com_ssl.key\n  ```\n\n**Remediation:**\n- Set the ownership of certificate and key files to `root:root`.\n- Adjust the file permissions to `600` or `400` to prevent leaked.\n  ```\n  [root@localhost ~]# chown root:root -R /etc/nginx/conf.d/cert/example.com_ssl.crt\n  [root@localhost ~]# chown root:root -R /etc/nginx/conf.d/cert/example.com_ssl.key\n  [root@localhost ~]# chmod 400 /etc/nginx/conf.d/cert/example.com_ssl.crt\n  [root@localhost ~]# chmod 400 /etc/nginx/conf.d/cert/example.com_ssl.key\n  ```\n  \n\n## 8. Ensure Blocking of Arbitrary Host Connections Not Configured in the Web Server\nIn a typical web server configuration, if someone knows the server's IP address, they might still be able to access the web service without knowing the valid hostname (domain). By isolating and blocking access to requests made to non-service hosts, you can reduce unnecessary connections that shouldn't lead to your service, thereby reducing server load and improving performance.\n\nBlocking such arbitrary connections also enhances security by preventing various types of web service attacks, such as host header injection and IP address-based scanning.\n\nEnsure that your web server is configured to only respond to requests made to the correct service host, while blocking all others.\n\n**Audit:**\n- Verify that unknown host requests are accepting when accessing the web server.\n\n**(Vulnerable) Web server accepting connections with unknown host requests:**\n  ```\n  [root@localhost ~]# curl -k -v https://192.168.130.23 -H 'Host: invalid.host.com'\n  *   Trying 192.168.130.23:443...\n  * Connected to 192.168.130.23 (192.168.130.23) port 443\n  * ALPN: curl offers h2,http/1.1\n  * TLSv1.3 (OUT), TLS handshake, Client hello (1):\n  * TLSv1.3 (IN), TLS handshake, Server hello (2):\n  * TLSv1.2 (IN), TLS handshake, Certificate (11):\n  * TLSv1.2 (IN), TLS handshake, Server key exchange (12):\n  * TLSv1.2 (IN), TLS handshake, Server finished (14):\n  * TLSv1.2 (OUT), TLS handshake, Client key exchange (16):\n  * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):\n  * TLSv1.2 (OUT), TLS handshake, Finished (20):\n  * TLSv1.2 (IN), TLS handshake, Finished (20):\n  * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 / prime256v1 / rsaEncryption\n  * ALPN: server did not agree on a protocol. Uses default.\n  * Server certificate:\n  *  subject: CN=*.example.com\n  *  start date: Jan  2 00:00:00 2024 GMT\n  *  expire date: Jan 20 23:59:59 2025 GMT\n  *  issuer: C=GB; ST=Greater Manchester; L=Salford; O=Sectigo Limited; CN=Sectigo RSA Domain Validation Secure Server CA\n  *  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.\n  *   Certificate level 0: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption\n  *   Certificate level 1: Public key type RSA (2048/112 Bits/secBits), signed using sha384WithRSAEncryption\n  *   Certificate level 2: Public key type RSA (4096/152 Bits/secBits), signed using sha384WithRSAEncryption\n  * using HTTP/1.x\n  \u003e GET / HTTP/1.1\n  \u003e Host: invalid.host.com\n  \u003e User-Agent: curl/8.5.0\n  \u003e Accept: */*\n  \u003e\n  \u003c HTTP/1.1 200 OK\n  \u003c Date: Mon, 12 Aug 2024 05:35:40 GMT\n  \u003c Server: Nginx\n  \u003c Cache-Control: no-cache, no-store, must-revalidate\n  \u003c Expires: Thu, 01 Jan 1970 09:00:00 KST\n  ...\n  ```\n\n**(Not Vulnerable) Web server not accepting connections with unknown host requests:**\n  ```\n  [root@localhost ~]# curl -k -v https://192.168.130.236 -H 'Host: invalid.host.com'\n  *   Trying 192.168.130.236:443...\n  * Connected to 192.168.130.236 (192.168.130.236) port 443 (#0)\n  * ALPN: offers h2\n  * ALPN: offers http/1.1\n  * (304) (OUT), TLS handshake, Client hello (1):\n  * (304) (IN), TLS handshake, Server hello (2):\n  * (304) (IN), TLS handshake, Unknown (8):\n  * (304) (IN), TLS handshake, Certificate (11):\n  * (304) (IN), TLS handshake, CERT verify (15):\n  * (304) (IN), TLS handshake, Finished (20):\n  * (304) (OUT), TLS handshake, Finished (20):\n  * SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256\n  * ALPN: server accepted http/1.1\n  * Server certificate:\n  *  subject: CN=*.example.com\n  *  start date: Jan  2 00:00:00 2024 GMT\n  *  expire date: Jan 20 23:59:59 2025 GMT\n  *  issuer: C=GB; ST=Greater Manchester; L=Salford; O=Sectigo Limited; CN=Sectigo RSA Domain Validation Secure Server CA\n  *  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.\n  *   Certificate level 0: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption\n  *   Certificate level 1: Public key type RSA (2048/112 Bits/secBits), signed using sha384WithRSAEncryption\n  *   Certificate level 2: Public key type RSA (4096/152 Bits/secBits), signed using sha384WithRSAEncryption\n  * using HTTP/1.x\n  \u003e GET / HTTP/1.1\n  \u003e Host: invalid.host.com\n  \u003e User-Agent: curl/7.84.0\n  \u003e Accept: */*\n  \u003e\n  * Mark bundle as not supporting multiuse\n  \u003c HTTP/1.1 403 Forbidden\n  \u003c Server: Nginx\n  \u003c Date: Mon, 12 Aug 2024 05:32:49 GMT\n  \u003c Content-Type: text/html\n  \u003c Content-Length: 162\n  \u003c Connection: keep-alive\n  \u003c\n  \u003chtml\u003e\n  \u003chead\u003e\u003ctitle\u003e403 Forbidden\u003c/title\u003e\u003c/head\u003e\n  \u003cbody bgcolor=\"white\"\u003e\n  \u003ccenter\u003e\u003ch1\u003e403 Forbidden\u003c/h1\u003e\u003c/center\u003e\n  \u003chr\u003e\u003ccenter\u003eNginx\u003c/center\u003e\n  \u003c/body\u003e\n  \u003c/html\u003e\n  * Connection #0 to host 192.168.130.236 left intact\n  ```\n\n**Remediation:**\n- Create a virtual host that processes and blocks requests with host headers that do not match the intended service hosts.\n  ```\n  [root@localhost ~]# vim /etc/nginx/nginx.conf\n  ...\n  \n  # VirtualHost to handle and block requests with unmatched host headers\n  server {\n          listen       80 default_server;\n          listen       443 default_server ssl;\n  \n          error_log    /var/log/nginx/http.unknown-header.error.log;\n          access_log   /var/log/nginx/http.unknown-header.access.log  main;\n  \n          ssl_certificate /etc/nginx/conf.d/cert/example.com_ssl.crt;\n          ssl_certificate_key /etc/nginx/conf.d/cert/example.com_ssl.key;\n          ssl_session_cache shared:SSL:1m;\n          ssl_session_timeout  10m;\n  \n          ssl_protocols TLSv1.2 TLSv1.3;\n          ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;\n          \n          location / {\n               deny all;\n          }\n  }\n  \n  # VirtualHost for the valid service hostname (example.com)\n  server {\n          listen       80;\n          server_name  example.com;\n  \n          location / {\n            return 301 https://example.com$request_uri;\n          }\n          ...\n  }\n      \n  server {\n          listen       443 ssl;\n          server_name  example.com;\n  \n          error_log    /var/log/nginx/example.com.error.log;\n          access_log   /var/log/nginx/example.access.log  main;\n  \n          ssl_certificate /etc/nginx/conf.d/cert/example.com_ssl.crt;\n          ssl_certificate_key /etc/nginx/conf.d/cert/example.com_ssl.key;\n          ssl_session_cache shared:SSL:1m;\n          ssl_session_timeout  10m;\n  \n          ssl_protocols TLSv1.2 TLSv1.3;\n          ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;\n          ...\n  }\n  ```\n\n**Notes:**\n- Ensuring that requests with incorrect host header are blocked is a critical part of web server security.\n- `Many web servers are not configured this way by default`, making this an essential configuration for system administrators to apply.\n\n\n## 9. Limit Simultaneous Connections per IP\nLimiting the number of simultaneous connections from a single IP address is a critical step in preventing resource exhaustion and ensuring the availability of services. By implementing connection limits, you can mitigate the risk of slow denial-of-service (DoS) attacks and maintain stable web server performance.\n\n**Audit:**\n- Verifying Simultaneous Connections\n- To audit the current simultaneous connections per IP, you can monitor server logs or analyze connection counts using tools like Nginx’s built-in logging or external monitoring systems.\n\n**Remediation:** \n- Configuring Connection Limits\n\n(1) Define a Shared Memory Zone\n- Use the limit_conn_zone directive in the http block to create a shared memory zone that tracks connections by IP. Example:\n  ```\n  http {\n      limit_conn_zone $binary_remote_addr zone=limitperip:10m;\n      ...\n  }\n  ```\n- `Memory Allocation:` 10MB can store approximately 160,000 unique IPs.\n- `Tracking Mechanism:` $binary_remote_addr tracks client IPs efficiently.\n\n(2) Apply Connection Limits\n- Use the limit_conn directive to enforce restrictions at the server or location level. Examples:\n  ```\n  server {\n      listen 443 ssl;\n      server_name auth.example.com;\n  \n      # Allow a maximum of 10 simultaneous connections per IP\n      limit_conn limitperip 10;\n  }\n  \n  server {\n      listen 443 ssl;\n      server_name download.example.com;\n  \n      location /download/ {\n          # Restrict simultaneous connections to 3 per IP for this location\n          limit_conn limitperip 3;\n          limit_conn_status 429;  # Return HTTP 429 (Too Many Requests)\n      }\n  }\n  ```\n\n**Notes:**\n- The `ngx_http_limit_conn_module` module must be enabled.\n- Fine-tune memory allocation and limits based on your server’s capacity and traffic profile.\n- The configuration ensures that excessive connections from a single IP do not degrade server performance or accessibility for other users.\n\nBy enforcing simultaneous connection limits, you can protect your server from potential abuse and maintain service quality under high-load scenarios.\n\n\n## 10. Limit Requests per IP\nRate limiting per IP address in Nginx helps maintain stable web services by controlling the number of requests a client can make within a given timeframe. This configuration prevents abuse by users generating excessive requests and protects the server from being overwhelmed.\n\n**Audit:**\n- Verifying Request Limits\n- To check if rate-limiting is configured:\n  - Review the Nginx configuration file for `limit_req_zone` and `limit_req` directives.\n  - Analyze the server logs to identify patterns of excessive requests or potential abuse.\n\n\n**Remediation:**\n- Configuring Rate Limits\n\n(1) Define a Shared Memory Zone\n- Use the `limit_req_zone` directive to allocate a shared memory zone that tracks request rates by IP. Example:\n  ```\n  http {\n      limit_req_zone $binary_remote_addr zone=ratelimit:10m rate=5r/s;\n      ...\n  }\n  ```\n- `Memory Allocation`: 10MB can store approximately 160,000 unique IPs.\n- `Rate:` Limits each IP to 5 requests per second (`5r/s`).\n\n(2) Apply Request Limits\n- Use the `limit_req` directive in the `location` block to enforce the rate limits. Example:\n  ```\n  server {\n      listen 443 ssl;\n      server_name auth.example.com;\n  \n      location / {\n          limit_req zone=ratelimit burst=10 nodelay;\n          limit_req_status 429;  # Return HTTP 429 (Too Many Requests)\n      }\n  }\n  ```\n- `Burst:` Allows up to 10 requests to be queued during traffic spikes.\n- `nodelay:` Ensures all requests in the burst are processed immediately without delay.\n\n**Notes:**\n- The `ngx_http_limit_conn_module` module must be enabled.\n- Adjust the rate and burst settings to align with your application's traffic profile.\n- Rate limits help maintain consistent performance by preventing abuse while accommodating occasional bursts of traffic.\n\nBy implementing IP-based rate limits, you can protect your server from misuse and ensure a reliable experience for legitimate users.\n\n\n## 11. Inspect and Control Request Headers\nWeb servers can inspect and control HTTP request headers to determine the presence or value of specific headers. This capability enables conditional access, such as blocking specific clients or permitting predefined user agents (e.g., mobile apps). It is commonly applied for:\n\n- Blocking known attack tools or abusive scanning software.\n- Allowing access only to predefined clients or bots.\n- Securing APIs by validating authorization headers.\n\n**Audit:**\n- Verifying Header Restrictions is applied\n  - Review the Nginx configuration for if directives that check headers like User-Agent or Authorization.\n  - Check server logs for unauthorized requests and verify appropriate error responses are sent.\n\n\n**Remediation:**\n- Configuring Header Restrictions\n\n(1) Block Known Vulnerability Scanners\n- Example configuration to block common web vulnerability scanning tools:\n  ```\n  server {\n      listen 443 ssl;\n      server_name download.example.com;\n  \n      # Block requests with known attack tool User-Agent strings\n      if ($http_user_agent ~* \"Paros|ZmEu|nikto|dirbuster|sqlmap|openvas|w3af|Morfeus|Zollard|Arachni|Brutus|bsqlbf|Grendel-Scan|Havij|Hydra|N-Stealth|Netsparker|Pangolin|pmafind|webinspect\") {\n          return 404;  # Return HTTP 404 Not Found\n      }\n  }\n  ```\n\n(2) Restrict Specific Headers for Certain URLs\n- Example to enforce valid authorization headers for API access:\n  ```\n  server {\n      listen 443 ssl;\n      server_name download.example.com;\n  \n      location /api {\n          proxy_http_version 1.1;\n  \n          # Only allow requests with Authorization header starting with \"Bearer\"\n          if ($http_authorization !~ \"^Bearer\") {\n              return 401;  # Return HTTP 401 Unauthorized\n          }\n  \n          proxy_pass http://app:3000/;\n      }\n  }\n  ```\n\n(3) Allow Only Specific Clients\n- Example to permit access to predefined User-Agent strings:\n  ```\n  http {\n      if ($http_user_agent !~ \"Agent.MyApp\") {\n          return 404;  # Return HTTP 404 Not Found\n      }\n  }\n  \n  server {\n      listen 443 ssl;\n      server_name auth.example.com;\n  }\n  \n  server {\n      listen 443 ssl;\n      server_name download.example.com;\n  }\n  ```\n  \n**Notes:**\n- The `$http_` variables in Nginx provide access to HTTP headers.\n- Regular expressions (`~` or `~*`) are used to match patterns in headers.\n- Use conditional blocks (`if`) judiciously to avoid unintended behavior or performance issues.\n- Return appropriate HTTP status codes (e.g., `404`, `401`) to signal blocked or unauthorized access.\n\n## 12. Utilizing the Location Block\nThe location block in Nginx is used to define how specific URIs are handled. Each virtual host can use multiple location blocks, which can be configured with different priorities. This allows fine-grained control over request handling.\n\n**Basic Usage**\n- The syntax for a `location` block is as follows:\n  ```\n  location [modifier] [URI] {\n      ...\n  }\n  ```\n\n**Matching Priorities**\n\n| Priority | Modifier | Description                                | Example                                              |\n|----------|----------|--------------------------------------------|------------------------------------------------------|\n| 1        | `=`      | Matches exact URIs.                        | `location = /favicon.ico { # do something }`         |\n| 2        | `^~`     | Matches URIs with a preferred prefix.      | `location ^~ /images/ { # do something }`            |\n| 3        | `~`      | Matches URIs using case-sensitive regex.   | `location ~ \\.php$ { # do something }`               |\n| 4        | `~*`     | Matches URIs using case-insensitive regex. | `location ~* \\.(jpg\\|jpeg\\|png)$ { # do something }` |                         |                                          |\n| 5        | `/`      | Matches all other URIs (fallback).         | `location /docs/ { # do something }`                 |\n\n**Remediation:**\n- Example Use Cases of the location Block\n\n(1) Serve Specific File for Dynamic URLs\n- Serve `/cafe-detail/index.html` for requests like `/cafes/12345`\n  ```\n  location ~ ^/cafes/[1-9]+$ {\n      try_files $uri /cafes/cafe-detail/index.html;\n  }\n  ```\n\n(2) Block Access to Hidden(.Dot) Files\n- Deny access to hidden files (starting with a dot):\n  ```\n  location ~ /\\. {\n      deny all;\n      return 404;\n  }\n  ```\n\n(3) Serve Static Files with Caching\n- Serve `css` and `js` files with a 30-day cache:\n  ```\n  location ~* \\.(css|js)$ {\n      root /var/www/static;\n      expires 30d;\n  }\n  ```\n\n(4) Restrict Access to Sensitive Files\n- Block access to `.sql` and `.bak` files:\n  ```\n  location ~* \\.(sql|bak)$ {\n      deny all;\n      return 404;\n  }\n  ```\n\n(5) Add Content-Type for API Responses\n- Add a Content-Type header for `.json` or `.xml` responses:\n  ```\n  location /api/ {\n      location ~* \\.(json|xml)$ {\n          add_header Content-Type application/json;\n      }\n  }\n  ```\n\n(6) Redirect Mobile Users\n- Redirect mobile users to a mobile-specific site version:\n  ```\n  location / {\n      set $mobile_rewrite do_not_perform;\n      if ($http_user_agent ~* \"(android|bb\\d+|meego).+mobile|avantgo|bada\\/|blackberry|blazer|compal|elaine|fennec|...)\") {\n          set $mobile_rewrite perform;\n      }\n      if ($mobile_rewrite = perform) {\n          rewrite ^ /mobile$uri redirect;\n      }\n  }\n  ```\n\n(7) Enable File Downloads\n- Set response headers for file downloads:\n  ```\n  location ~* ^/download/.*\\.(zip|tar\\.gz)$ {\n      root /var/www/files;\n      add_header Content-Disposition \"attachment\";\n  }\n  ```\n\n(8) Rate Limiting for Login Attempts\n- Limit request rates for WordPress login pages:\n  ```\n  location = /wp-login.php {\n      limit_req zone=one burst=1 nodelay;\n      include fastcgi_params;\n      fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;\n  }\n  location ~* /wp-admin/.*\\.php$ {\n      auth_basic \"Restricted Access\";\n      auth_basic_user_file /etc/nginx/.htpasswd;\n      include fastcgi_params;\n      fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;\n  }\n  ```\n\n(9) Rewrite API Versions\n- Process API requests with version-specific rewrites:\n  ```\n  location /api/ {\n      rewrite ^/api/v1/(.*)$ /api.php?version=1\u0026request=$1 break;\n      rewrite ^/api/v2/(.*)$ /api.php?version=2\u0026request=$1 break;\n  }\n  ```\n\n(10) Redirect Old Blog URLs\n- Rewrite legacy blog URLs to a new format:\n  ```\n  location /blog/ {\n      rewrite ^/blog/(\\d{4})/(\\d{2})/(.*)$ /articles/$1-$2-$3 permanent;\n  }\n  ```\n\n(11) Disable Caching for Sensitive Pages\n- Prevent caching for certain pages:\n  ```\n  location ~ ^/payments/v[1-2]/daily/download {\n      add_header Cache-Control 'no-cache, no-store, must-revalidate, proxy-revalidate, max-age=0';\n      add_header Pragma no-cache;\n      expires 0;\n  }\n  ```\n  \nUsing the location block effectively enhances web server performance, security, and user experience.\n\n---\n### Read Next\n- [Setup Apache HTTP Server With Shorts Security Best Practice](https://github.com/password123456/setup-apache-http-server-with-shorts-security-best-practice)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpassword123456%2Fsetup-nginx-http-server-with-security-best-practice","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpassword123456%2Fsetup-nginx-http-server-with-security-best-practice","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpassword123456%2Fsetup-nginx-http-server-with-security-best-practice/lists"}