{"id":19527711,"url":"https://github.com/jukbot/setup-nginx-webserver","last_synced_at":"2026-03-07T03:31:25.138Z","repository":{"id":88897330,"uuid":"71988517","full_name":"jukbot/setup-nginx-webserver","owner":"jukbot","description":"🚀Setup a perfect webserver on CentOS/Redhat 7.x guide with understanding.","archived":false,"fork":false,"pushed_at":"2018-10-15T14:33:31.000Z","size":2253,"stargazers_count":66,"open_issues_count":1,"forks_count":23,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-10-01T23:40:15.267Z","etag":null,"topics":["alpn","brotli","centos","firewall","http2","linux","nginx","nginx-modules","nginx-server","openssl","openssl-library","redhat","selinux","ssh-key","webserver"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jukbot.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2016-10-26T09:37:37.000Z","updated_at":"2025-09-11T09:49:21.000Z","dependencies_parsed_at":"2023-06-13T01:45:16.740Z","dependency_job_id":null,"html_url":"https://github.com/jukbot/setup-nginx-webserver","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jukbot/setup-nginx-webserver","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jukbot%2Fsetup-nginx-webserver","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jukbot%2Fsetup-nginx-webserver/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jukbot%2Fsetup-nginx-webserver/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jukbot%2Fsetup-nginx-webserver/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jukbot","download_url":"https://codeload.github.com/jukbot/setup-nginx-webserver/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jukbot%2Fsetup-nginx-webserver/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30206565,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-07T03:24:23.086Z","status":"ssl_error","status_checked_at":"2026-03-07T03:23:11.444Z","response_time":53,"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":["alpn","brotli","centos","firewall","http2","linux","nginx","nginx-modules","nginx-server","openssl","openssl-library","redhat","selinux","ssh-key","webserver"],"created_at":"2024-11-11T01:16:10.026Z","updated_at":"2026-03-07T03:31:25.116Z","avatar_url":"https://github.com/jukbot.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Setup a Secure Nginx Web Server on CentOS/Redhat 7.x\n(Updated 1 Oct, 2018)\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://cdn.rawgit.com/jukbot/secure-centos/master/Centos-logo-light.svg\" alt=\"PHP7\"/\u003e\n\u003c/p\u003e\n\nI've gather informations and created this article for sysadmin who're using CentOS or Enterprise Linux.\nBecause most of these linux branches have a long term support, f_cking stable and secured (SELinux). \nHowever, most libraries and applications that preinstalled are obsolete. \nSo this article will guide you STEP BY STEP to build a perfect web server with understanding.\n\n\n**THIS CONFIG BE USE IN ANYWHERE**\n- You can use this config in anytypes of environment eg. Nginx on VPS, VCM, any container or Docker. Just optimize to meet your load.\n\n**!!PLEASE READ!!**\n- Please be aware that this config is just an example that optimize for my server environment, some configure value might need to tune upon your server hardware and type of your application.\n\n\n**ANNOUCEMENT**\n```\nCentOS/RedHat 7.4 the openssl package has been updated to upstream version 1.0.2k, which provides a number of enhancements, new features, and bug fixes, including:\n- Added support for the Datagram Transport Layer Security TLS (DTLS) protocol version 1.2.\n- Added support for the automatic elliptic curve selection for the ECDHE key exchange in TLS.\n- Added support for the Application-Layer Protocol Negotiation (ALPN). -- YESSSSSSS!!!\n- Added Cryptographic Message Syntax (CMS) support for the following schemes: RSA-PSS, RSA-OAEP, ECDH, and X9.42 DH.\n```\n\n\n\n## Table of Contents  \n- [Introduction](#introduction)\n- [Prerequisites](#prerequisites)\n- [Setup and Initial Server](#setup-and-initial-server)\n- [Update and Upgrade](#update-and-upgrade)\n- [Install Common Packages](#install-common-packages)\n  * [1 Yum Utils](#1-yum-utils)\n  * [2 Extra Packages for Enterprise Linux (EPEL)](#2-extra-packages-for-enterprise-linux)\n  * [3 OpenSSL (with ALPN support)](#3-openssl)\n  * [4 Nginx](#4-nginx)\n    + [METHOD 1: Prebuilt binary package](#method-1--prebuilt-binary-package)\n    + [METHOD 2: Compile from source (If you want to install custom nginx modules)](#method-2--compile-from-source--if-you-want-to-install-custom-nginx-modules-)\n\n\n## Introduction\n\nThe new CentOS 7 server has to be customized before it can be put into use as a production system. In this article, will help you to increase the security and usability of your server with the lastest stable packages and will give you a solid foundation for subsequent actions.\n\nThis article **compatible with RedHat Enterprise Linux 7.x**, except some repository links need to change upon vendors and processor architecture of your hardware.\n\n\n## Prerequisites\n\nA newly activated CentOS 7 server, preferably setup with SSH keys. Log into the server as root with your server-ip-address.\n\n```\nssh -l root xx.xx.xxx.xxx\n```\nor\n```\nssh root@SERVER_IP_ADDRESS\n```\n\nTo view current ip of server in CentOS\n```\n# For minimal install\nip addr\n```\nor\n```\nifconfig\n```\n\nComplete the login process by accepting the warning about host authenticity, if it appears, then providing your root authentication (password or private key). If it is your first time logging into the server, with a password, you will also be prompted to change the root password.\n\nThe root user is the administrative user in a Linux environment that has very broad privileges. Because of the heightened privileges of the root account, you are actually discouraged from using it on a regular basis. This is because part of the power inherent with the root account is the ability to make very destructive changes, even by accident.\n\nThe next step is to set up an alternative user account with a reduced scope of influence for day-to-day work. We'll teach you how to gain increased privileges during the times when you need them.\n\n\n## Setup and Initial Server\n\n### Step 1 — Create a New User\n\nFor security reasons, it is not advisable to be performing daily computing tasks using the root account. Instead, it is recommended to create a standard user account that will be using sudo to gain administrative privileges. For this tutorial, assume that we're creating a user named joe. To create the user account, type:\n\n```\nadduser example\n```\nSet a password for the new user. You'll be prompted to input and confirm a password.\n\n```\npasswd example\n```\nAdd the new user to the wheel group so that it can assume root privileges using sudo.\n\n```\ngpasswd -a example wheel\n```\n\nFinally, open another terminal on your local machine and use the following command to add your SSH key to the new user's home directory on the remote server. You will be prompted to authenticate before the SSH key is installed.\n\n```\nssh-copy-id example@server-ip-address\n```\nAfter the key has been installed, log into the server using the new user account.\n\n```\nssh -l example server-ip-address\n```\n\nIf the login is successful, you may close the other terminal. From now on, all commands will be preceded with sudo.\n\n\n### Step 2 — Disallow Root Login and Password Authentication\n\nSince you can now log in as a standard user using SSH keys, a good security practice is to configure SSH so that the root login and password authentication are both disallowed. Both settings have to be configured in the SSH daemon's configuration file. So, open it using nano.\n\n```\nsudo vi /etc/ssh/sshd_config\n```\nTo exit vim editor press ESC then type :x to save and exit or :q! to ignore and exit \n\nLook for the PermitRootLogin line, uncomment it and set the value to no.\n```\nPermitRootLogin     no\n```\nDo the same for the PasswordAuthentication line, which should be uncommented already:\n```\nPasswordAuthentication      no\n```\nSave and close the file. To apply the new settings, reload SSH.\n```\nsudo systemctl reload sshd\n```\n\n### Step 3 - Configure the Timezones and Network Time Protocol Synchronization\n\nThe next step is to adjust the localization settings for your server and configure the Network Time Protocol (NTP) synchronization.\n\nThe first step will ensure that your server is operating under the correct time zone. The second step will configure your system to synchronize its system clock to the standard time maintained by a global network of NTP servers. This will help prevent some inconsistent behavior that can arise from out-of-sync clocks.\n\n#### 3.1 Configure Timezones\n\nOur first step is to set our server's timezone. This is a very simple procedure that can be accomplished using the timedatectl command:\n\nFirst, take a look at the available timezones by typing:\n\n```\nsudo timedatectl list-timezones\n```\nGrep possible Asian timezones \n```\nsudo timedatectl list-timezones | grep Asia\n```\n\nThis will give you a list of the timezones available for your server. When you find the region/timezone setting that is correct for your server, set it by typing:\n```\nsudo timedatectl set-timezone region/timezone\n```\n\nFor instance, to set it to United States eastern time, you can type:\n```\nsudo timedatectl set-timezone America/New_York\n```\nYour system will be updated to use the selected timezone. You can confirm this by typing:\n```\nsudo timedatectl\n```\n\n#### 3.2 Configure NTP Synchronization\n\nNow that you have your timezone set, we should configure NTP. This will allow your computer to stay in sync with other servers, leading to more predictability in operations that rely on having the correct time.\n\nFor NTP synchronization, we will use a service called ntp, which we can install from CentOS's default repositories:\n```\nsudo yum install ntp\n```\nNext, you need to start the service for this session. We will also enable the service so that it is automatically started each time the server boots:\n```\nsudo systemctl start ntpd\nsudo systemctl enable ntpd\n```\nYour server will now automatically correct its system clock to align with the global servers.\n\n#### 3.3 How do I see the current time zone?\n\nType the date command or the ls command:\n```\ndate\nls -l /etc/localtime\n```\n\n### Step 4 - Set Up FirewallD (Optional)\n\nAfter setting up the bare minimum configuration for a new server, there are some additional steps that are highly recommended in most cases.\n\n#### Prerequisites\n\nIn this guide, we will be focusing on configuring some optional but recommended components. This will involve setting our system up with a firewall and a swap file.\n\n#### Configuring a Basic Firewall\n\nFirewalls provide a basic level of security for your server. These applications are responsible for denying traffic to every port on your server with exceptions for ports/services you have approved. CentOS ships with a firewall called firewalld. A tool called firewall-cmd can be used to configure your firewall policies. Our basic strategy will be to lock down everything that we do not have a good reason to keep open.\n\nThe firewalld service has the ability to make modifications without dropping current connections, so we can turn it on before creating our exceptions:\n```\nsudo systemctl start firewalld\n```\nNow that the service is up and running, we can use the firewall-cmd utility to get and set policy information for the firewall. The firewalld application uses the concept of \"zones\" to label the trustworthiness of the other hosts on a network. This labelling gives us the ability to assign different rules depending on how much we trust a network.\n\nIn this guide, we will only be adjusting the policies for the default zone. When we reload our firewall, this will be the zone applied to our interfaces. We should start by adding exceptions to our firewall for approved services. The most essential of these is SSH, since we need to retain remote administrative access to the server.\n\nYou can enable the service by name (eg ssh-daemon) (MUST ENABLE) by typing:\n```\nsudo firewall-cmd --permanent --add-service=ssh\n```\nor disable it by typing:\n```\nsudo firewall-cmd --permanent --remove-service=ssh\n```\nor enable custom port by typing:\n```\nsudo firewall-cmd --permanent --add-port=4200/tcp\n```\n\nThis is the bare minimum needed to retain administrative access to the server. If you plan on running additional services, you need to open the firewall for those as well.\n\nIf you plan to run a web server with SSL/TLS enabled, you should allow traffic for https as well:\n\n```\nsudo firewall-cmd --permanent --add-service=http\nsudo firewall-cmd --permanent --add-service=https\n\n```\nIf you need SMTP email enabled, you can type:\n```\nsudo firewall-cmd --permanent --add-service=smtp\n```\nTo see any additional services that you can enable by name, type:\n```\nsudo firewall-cmd --get-services\n```\nWhen you are finished, you can see the list of the exceptions that will be implemented by typing:\n```\nsudo firewall-cmd --permanent --list-all\n```\nWhen you are ready to implement the changes, reload the firewall:\n```\nsudo firewall-cmd --reload\n```\nIf, after testing, everything works as expected, you should make sure the firewall will be started at boot:\n```\nsudo systemctl enable firewalld\n```\n\nRemember that you will have to explicitly open the firewall (with services or ports) for any additional services that you may configure later.\n\n\n### Step 5 - Enable the IPTables Firewall (Optional for advanced)\n\nBy default, the active firewall application on a newly activated CentOS 7 server is FirewallD. Though it is a good replacement for IPTables, many security applications still do not have support for it. So if you'll be using any of those applications, like OSSEC HIDS, it's best to disable/uninstall FirewallD.\n\n5.1 Let's start by disabling/uninstalling FirewallD:\n```\nsudo yum remove -y firewalld\n```\n\n5.2 Now, let's install/activate IPTables.\n```\nsudo yum install -y iptables-services\nsudo systemctl start iptables\n```\n\n5.3 Configure IPTables to start automatically at boot time.\n```\nsudo systemctl enable iptables\n```\n\nIPTables on CentOS 7 comes with a default set of rules, which you can view with the following command.\n```\nsudo iptables -L -n\n```\nThe output will resemble:\n```\nChain INPUT (policy ACCEPT)\ntarget     prot opt source               destination         \nACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED\nACCEPT     icmp --  0.0.0.0/0            0.0.0.0/0           \nACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           \nACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            state NEW tcp dpt:22\nREJECT     all  --  0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited\n\nChain FORWARD (policy ACCEPT)\ntarget     prot opt source               destination         \nREJECT     all  --  0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited\n\nChain OUTPUT (policy ACCEPT)\ntarget     prot opt source               destination\n```\n\nYou can see that one of those rules allows SSH traffic, so your SSH session is safe.\nBecause those rules are runtime rules and will be lost on reboot, it's best to save them to a file using:\n\n```\nsudo /usr/libexec/iptables/iptables.init save\n```\n\nThat command will save the rules to the /etc/sysconfig/iptables file. You can edit the rules anytime by changing this file with your favorite text editor.\n\n#### Allow Additional Traffic Through the Firewall\n\nSince you'll most likely be going to use your new server to host some websites at some point, you'll have to add new rules to the firewall to allow HTTP and HTTPS traffic. \n\n5.4 To accomplish that, open the IPTables file:\n```\nsudo nano /etc/sysconfig/iptables\n```\n\n5.5 Just after or before the SSH rule, add the rules for HTTP (port 80) and HTTPS (port 443) traffic, so that that portion of the file appears as shown in the code block below.\n```\n-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT\n-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT\n-A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT\n-A INPUT -j REJECT --reject-with icmp-host-prohibited\n```\n\n5.6 Save and close the file, then reload IPTables.\n```\nsudo systemctl reload iptables\n```\n\nWith the above step completed, your server should now be reasonably secure and be ready for use in production.\n\n\n### Step 6 - Optimized system configuration for maximum concurrency.\n\nIn default centos server is not fully optimized to make full use of available hardware. \nThis means it might fail under high load. So we need to config the sysctl.conf file for optimization.\n\n1. Open sysctl.conf file\n```\nsudo vi /etc/sysctl.conf\n```\n\n2. Edit file as following configuration \n(!! WARNING YOU MUST TEST EACH VALUUE BEFORE USE IN PRODUCTION, THIS CONFIG IS DEPEND ON YOUR SERVER ENVIRONMENT !!)\n\n```Ini\n# Increase number of incoming connections\nnet.core.somaxconn = 250000\n\n# Increase the maximum amount of option memory buffers\nnet.core.optmem_max = 25165824\n\n# Increase Linux auto tuning TCP buffer limits\n# min, default, and max number of bytes to use\n# set max to at least 4MB, or higher if you use very high BDP paths\nnet.core.rmem_default = 8388608\nnet.core.rmem_max = 16777216\nnet.core.wmem_max = 16777216\nnet.core.netdev_max_backlog = 65536\n\n# Decrease the time default value for tcp_fin_timeout connection\nnet.ipv4.tcp_fin_timeout = 15\n\n# Number of times SYNACKs for passive TCP connection.\nnet.ipv4.tcp_synack_retries = 2\nnet.ipv4.tcp_syn_retries = 2\n\n# Decrease the time default value for connections to keep alive\nnet.ipv4.tcp_keepalive_time = 300\nnet.ipv4.tcp_keepalive_probes = 5\nnet.ipv4.tcp_keepalive_intvl = 15\n\n# Enable timestamps as defined in RFC1323:\nnet.ipv4.tcp_timestamps = 1\n\n# Allowed local port range\nnet.ipv4.ip_local_port_range = 2000 65000\n\n# Turn on window scaling which can enlarge the transfer window:\nnet.ipv4.tcp_window_scaling = 1\n\n# Limit syn backlog to prevent overflow\nnet.ipv4.tcp_max_syn_backlog = 30000\n\n# Avoid a smurf attack\nnet.ipv4.icmp_echo_ignore_broadcasts = 1\n\n# Turn on protection for bad icmp error messages\nnet.ipv4.icmp_ignore_bogus_error_responses = 1\n\n# Turn on syncookies for SYN flood attack protection\nnet.ipv4.tcp_syncookies = 1\n\n# Protect Against TCP Time-Wait\nnet.ipv4.tcp_rfc1337 = 1\n\n# Turn on and log spoofed, source routed, and redirect packets\nnet.ipv4.conf.all.log_martians = 1\nnet.ipv4.conf.default.log_martians = 1\n\n# No source routed packets here\nnet.ipv4.conf.all.accept_source_route = 0\nnet.ipv4.conf.default.accept_source_route = 0\n\n# Turn on reverse path filtering\nnet.ipv4.conf.all.rp_filter = 1\n\n# Make sure no one can alter the routing tables\nnet.ipv4.conf.all.accept_redirects = 0\nnet.ipv4.conf.default.accept_redirects = 0\n\n# Don't act as a router\nnet.ipv4.ip_forward = 0\nnet.ipv4.conf.all.send_redirects = 0\nnet.ipv4.conf.default.send_redirects = 0\n\n# Turn on execshild protection\nkernel.randomize_va_space = 2\n\n# Optimization for port usefor LBs Increase system file descriptor limit\nfs.file-max = 65535\n\n# Allow for more PIDs (to reduce rollover problems); may break some programs 32768\nkernel.pid_max = 65536\n\n# Increase TCP max buffer size setable using setsockopt()\nnet.ipv4.tcp_rmem = 4096 87380 16777216\nnet.ipv4.tcp_wmem = 4096 87380 16777216\n\n# Increase the tcp-time-wait buckets pool size to prevent simple DOS attacks\nnet.ipv4.tcp_max_tw_buckets = 1440000\nnet.ipv4.tcp_tw_recycle = 1\nnet.ipv4.tcp_tw_reuse = 1\n\n# !! Disable ipv6 for security (!! Optional if you're using ipv6 !!)\nnet.ipv6.conf.all.disable_ipv6= 1\n```\n\n\n3. Reload the systemctl file\n```\nsysctl -p\n```\n\n## Update and Upgrade\n\nTo update installed packages\n```\nsudo yum -y update \n```\nTo upgrade installed packages\n```\nsudo yum -y upgrade\n```\n\n\n\n## Install Common Packages\n\n### 1 Yum Utils \n\n**Yum-utils** is a collection of utilities and plugins extending and supplementing yum in different ways. It included in the base repo (which is enabled by default). However if you install as minimal you have to install it manually by typing. \n\n```\nsudo yum -y install yum-utils\n```\n\nRead more about yum-utils \nhttps://www.if-not-true-then-false.com/2012/delete-remove-old-kernels-on-fedora-centos-red-hat-rhel/\nhttps://www.tecmint.com/linux-yum-package-management-with-yum-utils/\n\n### 2 Extra Packages for Enterprise Linux (EPEL)\n\nHow do I install the extra repositories such as Fedora EPEL repo on a Red Hat Enterprise Linux server version 7.x or CentOS Linux server version 7.x?\n\nYou can easily install various packages by configuring a CentOS 7.x or RHEL 7.x system to use Fedora EPEL repos and third party packages. Please note that these packages are not officially supported by either CentOS or Red Hat, but provides many popular packages and apps.\n\n#### How to install RHEL EPEL repository on Centos 7.x or RHEL 7.x\n\nThe following instructions assumes that you are running command as root user on a CentOS/RHEL 7.x system and want to use use Fedora Epel repos.\n\n#### Install Extra Packages for Enterprise Linux repository configuration\n\nInstall epel release for CentOS and RHEL 7.x using yum install\n```\nsudo yum install epel-release\n```\nRefresh repo by typing the following command: \n```\nyum repolist\n```\n\n#### Search and install package\n\nTo list all available packages under a repo called epel\n```\nsudo yum --disablerepo=\"*\" --enablerepo=\"epel\" list available\n```\n\nExample: Search and install htop package from epel repo on a CentOS/RHEL 7.x\n\n```\nsudo yum search htop\nsudo yum info htop\nsudo yum install htop\n```\n\nAnd, there you have it, a larger number of packages to install from EPEL repo on a CentOS and \nRed Hat Enterprise Linux (RHEL) version 7.x.\n\n\n### 3 OpenSSL\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://cdn.rawgit.com/jukbot/secure-centos/master/OpenSSL-Logo.png\" alt=\"OPENSSL\"/\u003e\n\u003c/p\u003e\n\n**OpenSSL** is a software library to be used in applications that need to secure communications against eavesdropping or need to ascertain the identity of the party at the other end. It has found wide use in internet web servers, serving a majority of all web sites.\n\n**Application-Layer Protocol Negotiation (ALPN)** is a Transport Layer Security (TLS) extension for application layer protocol negotiation. ALPN allows the application layer to negotiate which protocol should be performed over a secure connection in a manner which avoids additional round trips and which is independent of the application layer protocols. It is used by HTTP/2.\n\n***Due to TLS False Start was disabled in Google Chrome from version 20 (2012) onward except for websites with the earlier Next Protocol Negotiation (NPN) extension. NPN was replaced with a reworked version, ALPN. On July 11, 2014, ALPN was published as RFC 7301.***\n\n#### Why Has HTTP/2 Stopped Working for Users of the New Version of Google Chrome?\n\nAs of May 2016, approximately 8% of the world’s websites are accessible over HTTP/2. These websites all use SSL/TLS, because browsers that support HTTP/2 only upgrade the connection to the new standard if SSL/TLS is also in use. The vast majority of sites – those running NGINX and LiteSpeed – depend on OpenSSL’s implementation of NPN or ALPN to upgrade to HTTP/2.\n\n**OpenSSL added ALPN support on January 2015, in version 1.0.2. Versions 1.0.1 and earlier do not support ALPN.**\n\nUnlike a standalone web server like NGINX, OpenSSL is a core operating system library that is used by many of the packages shipped as part of a modern Linux operating system. To ensure the operating system is stable and reliable, OS distributors do not make major updates to packages such as OpenSSL during the lifetime of each release. They do backport critical OpenSSL patches to their supported versions of OpenSSL to protect their users against OpenSSL vulnerabilities. They do not backport new features, particularly those which change the ABI of essential shared libraries.\n\n\u003cp align=\"center\"\u003e\nThe table summarizes operating system support for ALPN and NPN.\n  \u003ca href=\"https://www.nginx.com/blog/supporting-http2-google-chrome-users/\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://cdn.rawgit.com/jukbot/secure-centos/master/alpn_os_support.PNG\" alt=\"OS that support ALPN\"/\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\nAs you can see, only Ubuntu \u003e= 16.04 LTS supports ALPN. This means that if you’re running your website on any other major operating system, the OpenSSL version shipped with the operating system does not support ALPN and Chrome users will be downgraded to HTTP/1.1\n\nSo to enable HTTP/2 on ALPN in chrome browser you need to be sure that you have already installed ***OpenSSL that supported ALPN** which is version \u003e= 1.0.2.\n\nAccording to https://en.wikipedia.org/wiki/OpenSSL#Major_version_releases\n\n**RedHat/CentOS \u003e= 7.4 now supported Application-Layer Protocol Negotiation (ALPN)**\n\n```\nIn CentOS/RedHat 7.4 the openssl package has been updated to upstream version 1.0.2k, which provides a number of enhancements, new features, and bug fixes, including:\n- Added support for the Datagram Transport Layer Security TLS (DTLS) protocol version 1.2.\n- Added support for the automatic elliptic curve selection for the ECDHE key exchange in TLS.\n- Added support for the Application-Layer Protocol Negotiation (ALPN). \n- Added Cryptographic Message Syntax (CMS) support for the following schemes: RSA-PSS, RSA-OAEP, ECDH, and X9.42 DH.\n\nAccording from https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html-single/7.4_release_notes/index\n```\n\nTo update your linux kernel just use command\n```\nsudo yum upgrade\n```\n\n**The following steps describe how to upgrade OpenSSL to the latest version**\n\nPrerequired: To compile openssl from source you need to install compiler and required libraries to build nginx.\n```\nsudo yum groupinstall 'Development Tools'\nsudo yum -y install gcc gcc-c++ make unzip autoconf automake zlib-devel pcre-devel openssl-devel zlib-devel pam-devel\n```\n\nTo verify the current openssl version by command\n```\nopenssl version\nOpenSSL 1.0.1e-fips 11 Feb 2013\n```\n\nTo view the lastest openssl package from current base repository\n```\nyum info openssl\n```\n\n1). Download the latest version of OpenSSL and generate the config, as follows:\n```shell\ncd /usr/local/src/\nwget https://www.openssl.org/source/openssl-1.1.1-latest.tar.gz\ntar -zxf openssl-1.1.1.tar.gz\n\ncd openssl-1.1.1\n./config\n```\n\nNote: \n- If you want to install other version you can download it from https://www.openssl.org/source/\n- We will use latest openssl version 1.1.1 (Long Term Support Version) from official website.\n- Alphabet suffix 'h' of openssl version number depends on release of openssl.\n\n2). Compile the source code, test and then install the package (need root permission)\n\n```\nmake\nmake test\nmake install\n```\n\nRecommended: \n- This will take a while depending on your CPU capacity. If your CPU has more than 1 core you can added suffix -j4 for using 4 cores to compile the source code. For example: `make -j4` to use all 4 cores to compile the source code.\n\n3). Move old openssl installed version to the root folder for backup or you can delete it (need root permission)\n```\nmv /usr/bin/openssl /root/\n```\n\n4). Create a symbolic link (need root permission)\n```\nln -s /usr/local/bin/openssl /usr/bin/openssl\n```\n\n5). Update new lib64 to LD_LIBRARY path then apply the config\n```\nexport LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib64\nldconfig\n````\n\n6). Verify the OpenSSL version \n```\nopenssl version\nOpenSSL 1.1.1  11 Sep 2018\n```\n\n\n### 4 Nginx\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://cdn.rawgit.com/jukbot/secure-centos/master/NGINX_logo.png\" alt=\"NGINX\"/\u003e\n\u003c/p\u003e\n\nCompiling NGINX from the sources provides you with more flexibility: you can add particular NGINX modules or 3rd party modules and apply latest security patches. \n\n(TL;DR - This section just explain the duty of each modules, can skip to the next section)\n\n#### NGINX Default Modules (No need to config this, it will install as default)\n\n**NGINX consists of modules.**  The set of modules as well as other build options are configured with the ./configure script.\n\nThe following list are modules built by Default. So you're not need to configure it out.\nHowever, you can disable it by including it to the configure script with the --without- prefix.\n\n**http_charset_module**\tAdds the specified charset to the “Content-Type” response header field, can convert data from one charset to another.\n\n**http_gzip_module**\tCompresses responses using the gzip method, helping to reduce the size of transmitted data by half or more.\n\n**http_ssi_module**\tProcesses SSI (Server Side Includes) commands in responses passing through it.\n\n**http_userid_module**\tSets cookies suitable for client identification.\n\n**http_access_module**\tLimits access to certain client addresses.\n\n**http_auth_basic_module**\tLimits access to resources by validating the user name and password using the HTTP Basic Authentication protocol.\n\n**http_autoindex_module**\tProcesses requests ending with the slash character (‘/’) and produces a directory listing.\n\n**http_geo_module**\tCreates variables with values depending on the client IP address.\n\n**http_map_module**\tCreates variables whose values depend on values of other variables.\n\n**http_split_clients_module**\tCreates variables suitable for A/B testing, also known as split testing.\n\n**http_referer_module**\tBlocks access to a site for requests with invalid values in the Referer header field.\n\n**http_rewrite_module**\tChanges the request URI using regular expressions and return redirects; conditionally selects configurations. Requires the PCRE library.\n\n**http_proxy_module**\tPasses requests to another server.\n\n**http_fastcgi_module**\tPasses requests to a FastCGI server\n\n**http_uwsgi_module**\tPasses requests to a uwsgi server.\n\n**http_scgi_module**\tPasses requests to an SCGI server.d\n\n**http_memcached_module**\tObtains responses from a memcached server.\n\n**http_limit_conn_module**\tLimits the number of connections per the defined key, in particular, the number of connections from a single IP address.\n\n**http_limit_req_module**\tLimits the request processing rate per a defined key, in particular, the processing rate of requests coming from a single IP address.\n\n**http_empty_gif_module**\tEmits single-pixel transparent GIF.\n\n**http_browser_module**\tCreates variables whose values depend on the value of the “User-Agent” request header field.\n\n**http_upstream_hash_module**\tEnables the hash load balancing method.\n\n**http_upstream_ip_hash_module**\tEnables the IP hash load balancing method.\n\n**http_upstream_least_conn_module**\tEnables the least_conn load balancing method.\n\n**http_upstream_keepalive_module**\tEnables keepalive connections.\n\n**http_upstream_zone_module**\tEnables the shared memory zone.\n\n\n#### NGINX Modules Not Built by Default (Select the module what you're using or plan to)\n\nSome NGINX modules are not built by default. You will need to enable them manually by adding to the ./configure command. The mail, stream, geoip, image_filter, perl and xslt modules can be compiled as dynamic. See Dynamic Modules for details.\n\n**--with-threads** Enables NGINX to use thread pools.\nSee Thread Pools in NGINX Boost Performance 9x! blog post for details.\n\n**--with-file-aio** Enables asynchronous I/O. (Suggest if you're working with I/O)\n\n**--with-ipv6** Enables IPv6 support. (Very Recommended !!)\n\n**--with-http_ssl_module** Provides support for HTTPS. Requires an SSL library such as OpenSSL. (Very Recommended !!)\n\n**--with-http_v2_module** Provides support for HTTP/2. (Very Recommended !!)\n\n**--with-http_realip_module** Changes the client address to the one sent in the specified header field.\n\n**--with-http_addition_module** Adds text before and after a response.\n\n**--with-http_xslt_module or --with-http_xslt_module=dynamic**  Transforms XML responses using one or more XSLT stylesheets. The module requires the Libxml2 and XSLT libraries. The module can also be compiled as dynamic.\n\n**--with-http_image_filter_module or --with-http_image_filter_module=dynamic**  Transforms images in JPEG, GIF, and PNG formats. The module requires the LibGD library. The module can also be compiled as dynamic.\n\n**--with-http_geoip_module or --with-http_geoip_module=dynamic**  Allows creating variables whose values depend on the client IP address. The module uses MaxMind GeoIP databases. The module can also be compiled as dynamic.\n\n**--with-http_sub_module** Modifies a response by replacing one specified string by another.\n\n**--with-http_dav_module** Intended for file management automation via the WebDAV protocol.\n\n**--with-http_flv_module** . Provides pseudo-streaming server-side support for Flash Video (FLV) files.\n\n**--with-mp4_module** Provides pseudo-streaming server-side support for MP4 files.\n\n**--with-http_gunzip_module** Decompresses responses with Content-Encoding: gzip for clients that do not support zip encoding method.\n\n**--with-http_gzip_static_module** Allows sending precompressed files with the *.gz filename extension instead of regular files.\n\n**--with-http_auth_request_module** Implements client authorization based on the result of a subrequest.\n\n**--with-http_random_index_module** Processes requests ending with the slash character (‘/’) and picks a random file in a directory to serve as an index file.\n\n**--with-http_secure_link_module** Used to check authenticity of requested links, protect resources from unauthorized access, and limit link lifetime.\n\n**--with-http_slice_module** Allows splitting a request into subrequests, each subrequest returns a certain range of response. Provides more effective caching of large files.\n\n**--with-http_degradation_module** Allows returning an error when a memory size exceeds the defined value.\n\n**--with-http_stub_status_module** Provides access to basic status information.\n\n**--with-http_perl_module or --with-http_perl_module=dynamic** . Used to implement location and variable handlers in Perl and insert Perl calls into SSI. Requires the PERL library. The module can also be compiled as dynamic.\n\n**--with-mail or --with-mail=dynamic** Enables mail proxy functionality. See the ngx_mail_core_module reference for the list of directives. The module can also be compiled as dynamic.\n\n**--with-mail_ssl_module** Provides support for a mail proxy server to work with the SSL/TLS protocol. Requires an SSL library such as OpenSSL.\n\n**--with-stream or --with-stream=dynamic** Enables the TCP proxy functionality. The module can also be compiled as dynamic.\n\n**--with-stream_ssl_module** Provides support for a stream proxy server to work with the SSL/TLS protocol. Requires an SSL library such as OpenSSL.\n\n**--with-google_perftools_module** Allows using Google Performance tools library.\n\n**--with-cpp_test_module --with-debug** Enables the debugging log.\n\n\n#### NGINX 3rd Party Modules (Optional module for compile from source method)\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://upload.wikimedia.org/wikipedia/commons/0/0f/Brotli_logo.jpeg\" alt=\"NGINX_BROTLI_COMPRESSION\"/\u003e\n\u003c/p\u003e\n\n**ngx_brotli module** - An open source data compression library introducing by Google, based on a modern variant of the LZ77 algorithm, Huffman coding and 2nd order context modeling. (By default nginx bundle with **gzip** compression library)\n \nBrotli performance https://www.opencpu.org/posts/brotli-benchmarks/\n\nInstalling nginx brotli module https://github.com/google/ngx_brotli\n\n```\ngit clone https://github.com/google/ngx_brotli.git\ncd /usr/local/src/ngx_brotli \ngit submodule update --init\n```\n\n-------------------------------------------------------------------------------------------------------------------------\n\nView more NGINX 3rd Party Modules: https://www.nginx.com/resources/wiki/modules/\n\nRead more about extending nginx https://www.nginx.com/resources/wiki/extending/\n\nRead more about dynamic modules https://www.nginx.com/blog/dynamic-modules-nginx-1-9-11/\n\n-------------------------------------------------------------------------------------------------------------------------\n\n### Choosing Between a Stable or a Mainline Version\n\nNGINX Open Source is available in 2 versions:\n\n**The mainline version** This version includes the latest features and bugfixes and is always up-to-date. It is reliable, but it may include some experimental modules, and it may also have some number of new bugs.\n\n**The stable version** This version doesn’t have new features, but includes critical bug fixes that are always backported to the mainline version. The stable version is recommended for production servers.\n\n\n### Choosing Between a Prebuilt Package and Compiling from Source\n\nBoth the NGINX Open Source mainline and stable versions can be installed in two ways:\n\n**Prebuilt binary package.** This is a quick and easy way to install NGINX Open Source. The package includes almost all official NGINX modules and is available for most popular operating systems. See Installing a Prebuilt Package.\n\n**Compile from source.** This way is more flexible: you can add particular modules, including third‑party modules, or apply the latest security patches. See Compiling and Installing from Source for details.\n\n-------------------------------------------------------------------------------------------------------------------------\n\n### METHOD 1: Prebuilt binary package\n\n#### Step 1 Set up the yum repository for RHEL/CentOS \n\nCreating the file nginx.repo in /etc/yum.repos.d, for example using vi:\n```\nsudo vi /etc/yum.repos.d/nginx.repo\n```\n\nThen edit nginx repository meta by add the following lines to nginx.repo: \n```Ini\n[nginx]\nname=nginx repo\nbaseurl=https://nginx.org/packages/centos/7/$basearch/\ngpgcheck=0\nenabled=1\n```\nSave the config by ESC -\u003e :x to save and exit the editor\n\nNote: If you're using RedHat just change os name from `centos` to `rhel` \n\n\n#### Step 2 Update the repository, install and start NGINX OSS package:\n```\nsudo yum update\nsudo yum install nginx\nsudo nginx\n```\n\n\n#### Step 3 Verify the installation and service status:\n```\nsudo nginx -V\nsudo systemctl status nginx\n```\n\n-------------------------------------------------------------------------------------------------------------------------\n\n### METHOD 2: Compile from source (If you want to install custom nginx modules)\n\n#### Step 1 - Install Compiler and build tools\n\nTo compile nginx from source you need to install compiler and required libraries to build nginx.\n```\nsudo yum groupinstall 'Development Tools'\nsudo yum -y install autoconf automake bind-utils wget curl unzip gcc-c++ pcre-devel zlib-devel libtool make nmap-netcat ntp pam-devel\n```\n\n#### Step 2 - Download NGINX Source Code\n\n```\ncd /usr/local/src\nwget http://nginx.org/download/nginx-1.14.0.tar.gz\ntar zxf nginx-1.14.0.tar.gz\ncd nginx-1.14.0\n```\n\nMainline version please see https://nginx.org/en/download.html\n\n\n#### Step 3 - Install NGINX Dependencies\n\nPrior to compiling NGINX from the sources, it is necessary to install its dependencies:\n\nPCRE library (March 3, 2018)\n- The PCRE library required by NGINX Core and Rewrite modules and provides support for regular expressions:\n```\ncd /usr/local/src\nwget https://ftp.pcre.org/pub/pcre/pcre-8.42.tar.gz\ntar -zxf pcre-8.42.tar.gz\ncd pcre-8.42\n./configure\nmake\nsudo make install\n```\n\nZLIB library (January 15, 2017)\n- The zlib library required by NGINX Gzip module for headers compression:\n```\ncd /usr/local/src\nwget https://zlib.net/zlib-1.2.11.tar.gz\ntar -zxf zlib-1.2.11.tar.gz\ncd zlib-1.2.11\n./configure\nmake\nsudo make install\n```\n\nOpenSSL library (lastest or \u003e= 1.0.2)\n- The OpenSSL library required by NGINX SSL modules to support the HTTPS protocol:\n- Please see the OpenSSL section\n\n\n#### Step 4 Config source code\n\n**NGINX Compile configure detail (TL;DR - Just explain the duty of each packages, can skip to next section)**\n\nFirst, we'll set prefix to /etc/nginx for our nginx installation path. \n\nNext, set sbin path to /usr/sbin/nginx for storing our nginx process.\n\nNext, set modules path to /usr/lib64/nginx/modules for storing our ngnx modules.\n\nNext, set conf path to /etc/nginx/nginx.conf for storing our default global nginx config file.\n\nNext, set error log path to /var/log/nginx/error.log for storing our error log file location.\n\nNext, set http log path to /var/log/nginx/access.log for storing our http log file location.\n\nNext, set pid path to /var/run/nginx.pid to set the name for main process ID file.\n\nNext, set lock path to /var/run/nginx.lock to set the name for Nginx lock file.\n\nNext, set http-client-body-temp path to /var/cache/nginx/client_temp for storing client temporary cache.\n\nNext, set http-proxy-temp path to /var/cache/nginx/proxy_temp for storing temporary proxy.\n\nNext, set http-fastcgi-temp path to /var/cache/nginx/fastcgi_temp for storing fastcgi cache. (commonly used in PHP)\n\nNext, set http-uwsgi-temp path to /var/cache/nginx/uwsgi_temp for storing uwsgi cache.\n\nNext, set http-scgi-temp path to /var/cache/nginx/scgi_temp for storing scgi cache.\n\nNext, set user as nginx.\n\nNext, set group as nginx.\n\nNext, set pcre (required library) path to /usr/local/src/pcre-8.41 that where you downloaded source to.\n\nNext, set zlib (required library) path to /usr/local/src/zlib-1.2.11 that where you downloaded source to.\n\nNext, set openssl (required library) path to /usr/local/src/openssl-1.1.1 that where you downloaded source to.\n\nNext, add ssl http module for enables used SSL/TLS (https) in nginx. (VERY recommeded I love HTTPS !!)\n\nNext, add http_v2 module for enables used http2 in nginx. (Required http_ssl_module !!!)\n\nNext, add http_realip_module to change the client address to the one sent in the specified header field.\nNext, add threads, file-aio for enables NGINX to use thread pools, asynchronous I/O.\n\nNext, add addition_module for adds text before and after a response.\n\nNext, add sub_module to modifies a response by replacing one specified string by another.\n\nNext, add dav_module to intend for file management automation via the WebDAV protocol.\n\nNext, add flv_module to provide pseudo-streaming server-side support for Flash Video (FLV) files.\n\nNext, add mp4_module to provide pseudo-streaming server-side support for MP4 files.\n\nNext, add gunzip_module for decompresses responses with Content-Encoding: gzip for clients that do not support zip encoding \nmethod.\n\nNext, add gzip_static_module for allows sending precompressed files with the *.gz filename extension instead of regular \nfiles.\n\nNext, add auth_request_module to implement client authorization based on the result of a subrequest.\n\nNext, add random_index_module for processes requests ending with the slash character (‘/’) and picks a random file in a \ndirectory to serve as an index file.\n\nNext, add secure_link_module for used to check authenticity of requested links, protect resources from unauthorized access, \nand limit link lifetime.\n\nNext, add slice_module for allows splitting a request into subrequests, each subrequest returns a certain range of \nresponse. Provides more effective caching of large files.\n\nNext, add degradation_module for allows returning an error when a memory size exceeds the defined value.\n\nNext, add stub_status_module to provides access to basic status information.\n\nNext, add mail module to enable mail proxy functionality. (OPTIONAL)\n\nNext, add mail_ssl_module to provide support for a mail proxy server to work with the SSL/TLS protocol. (OPTIONAL) \n(Requires an SSL library such as OpenSSL.)\n\nNext, add stream module to enable the TCP proxy functionality. (OPTIONAL)\n\nNext, add stream_ssl_module to provide support for a stream proxy server to work with the SSL/TLS protocol. (OPTIONAL)\n(Requires an SSL library such as OpenSSL.)\n\nNOTE: Someone ask WHERE IS ipv6 module? according to the changes with nginx 1.11.5 (11 Oct 2016) now this configure option was removed and IPv6 support is configured by default automatically. \n\n```\nNOTE!! Please change the library version to your current library path version. For example\n\n--with-pcre=/usr/local/src/pcre-8.42 \\\n--with-zlib=/usr/local/src/zlib-1.2.11 \\\n--with-openssl=/usr/local/src/openssl-1.1.1 \\\n```\n\n4.1 Run the nginx config \n(!! REMOVE THE LAST LINE, IF YOU DON'T WANT BROTLI MODULE, SEE BROTLI MODULE SECTION !!)\n\n```shell\n./configure \\\n--prefix=/etc/nginx \\\n--sbin-path=/usr/sbin/nginx \\\n--modules-path=/usr/lib64/nginx/modules \\\n--conf-path=/etc/nginx/nginx.conf \\\n--error-log-path=/var/log/nginx/error.log \\\n--http-log-path=/var/log/nginx/access.log \\\n--pid-path=/var/run/nginx.pid \\\n--lock-path=/var/run/nginx.lock \\\n--http-client-body-temp-path=/var/cache/nginx/client_temp \\\n--http-proxy-temp-path=/var/cache/nginx/proxy_temp \\\n--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \\\n--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \\\n--http-scgi-temp-path=/var/cache/nginx/scgi_temp \\\n--user=nginx \\\n--group=nginx \\\n--with-pcre-jit \\\n--with-ld-opt=\"-lrt\" \\\n--with-pcre=/usr/local/src/pcre-8.42 \\\n--with-zlib=/usr/local/src/zlib-1.2.11 \\\n--with-openssl=/usr/local/src/openssl-1.1.1 \\\n--with-http_ssl_module \\\n--with-http_v2_module \\\n--with-http_realip_module \\\n--with-threads \\\n--with-file-aio \\\n--with-http_addition_module \\\n--with-http_sub_module \\\n--with-http_dav_module \\\n--with-http_flv_module \\\n--with-http_mp4_module \\\n--with-http_gunzip_module \\\n--with-http_gzip_static_module \\\n--with-http_auth_request_module \\\n--with-http_random_index_module \\\n--with-http_secure_link_module \\\n--with-http_slice_module \\\n--with-http_degradation_module \\\n--with-http_stub_status_module \\\n--with-mail \\\n--with-mail_ssl_module \\\n--with-stream \\\n--with-stream_ssl_module \\\n--with-stream_realip_module \\\n--add-module=/usr/local/src/ngx_brotli \n```\n\n4.2 Then Compile and install the build:\n```\nsudo make \u0026\u0026 sudo make install\n```\n\n4.3 (FOR SECURITY) Create nginx user for running nginx service\n\nAfter the installation process has finished with success, add nginx system user (with /etc/nginx/ as his home directory and with no valid shell), the user that Nginx will run as by issuing the following command.\n```\nuseradd -d /etc/nginx/ -s /sbin/nologin nginx\n```\n\nThen, change user in nginx configure file to nginx user\n```Ini\nvi /etc/nginx/nginx.conf\n# Then change the user from nobody to nginx, then save and exit.\n\nuser nginx;\n```\n\n4.4 (FOR SECURITY) Config the firewall to allow http connnection\n```\nsystemctl enable firewalld.service\nfirewall-cmd --permanent --zone=public --add-service=http\nfirewall-cmd --permanent --zone=public --add-service=https\nsystemctl restart firewalld.service\n```\n\n4.5 Start nginx service by using below command\n```\n/usr/sbin/nginx -c /etc/nginx/nginx.conf\n```\n\nCheck nginx process \n```\nps -ef|grep nginx\n```\n\nTo stop nginx service using below command\n```\nkill -9 PID-Of-Nginx\n```\n\n4.6 (DO ONLY ONCE)* Add nginx as systemd service \n\nCreate a file \"nginx.service\" in /lib/systemd/system/nginx.service \n```\nsudo vi /lib/systemd/system/nginx.service\n```\n\nThen copy service detail below into the file and save\n```Ini\n[Unit]\nDescription=The NGINX HTTP and reverse proxy server\nAfter=syslog.target network.target remote-fs.target nss-lookup.target\n\n[Service]\nType=forking\nPIDFile=/run/nginx.pid\nExecStartPre=/usr/sbin/nginx -t\nExecStart=/usr/sbin/nginx\nExecReload=/usr/sbin/nginx -s reload\nExecStop=/bin/kill -s QUIT $MAINPID\nPrivateTmp=true\n\n[Install]\nWantedBy=multi-user.target\n```\n \nThen reload the system files\n```\nsystemctl daemon-reload\n```\n\n4.7 (DO ONLY ONCE)* Create a script for automatic start nginx service at system startup\n```text\nsudo ln -s /usr/local/nginx/sbin/nginx /usr/sbin/nginx\nsudo vi /etc/init.d/nginx then copy script below\n```\n\n```bash\n#!/bin/sh\n#\n# nginx - this script starts and stops the nginx daemon\n#\n# chkconfig:   - 85 15\n# description:  NGINX is an HTTP(S) server, HTTP(S) reverse \\\n#               proxy and IMAP/POP3 proxy server\n# processname: nginx\n# config:      /etc/nginx/nginx.conf\n# config:      /etc/sysconfig/nginx\n# pidfile:     /var/run/nginx.pid\n\n# Source function library.\n. /etc/rc.d/init.d/functions\n\n# Source networking configuration.\n. /etc/sysconfig/network\n\n# Check that networking is up.\n[ \"$NETWORKING\" = \"no\" ] \u0026\u0026 exit 0\n\nnginx=\"/usr/sbin/nginx\"\nprog=$(basename $nginx)\n\nNGINX_CONF_FILE=\"/etc/nginx/nginx.conf\"\n\n[ -f /etc/sysconfig/nginx ] \u0026\u0026 . /etc/sysconfig/nginx\n\nlockfile=/var/lock/subsys/nginx\n\nmake_dirs() {\n   # make required directories\n   user=`$nginx -V 2\u003e\u00261 | grep \"configure arguments:.*--user=\" | sed 's/[^*]*--user=\\([^ ]*\\).*/\\1/g' -`\n   if [ -n \"$user\" ]; then\n      if [ -z \"`grep $user /etc/passwd`\" ]; then\n         useradd -M -s /bin/nologin $user\n      fi\n      options=`$nginx -V 2\u003e\u00261 | grep 'configure arguments:'`\n      for opt in $options; do\n          if [ `echo $opt | grep '.*-temp-path'` ]; then\n              value=`echo $opt | cut -d \"=\" -f 2`\n              if [ ! -d \"$value\" ]; then\n                  # echo \"creating\" $value\n                  mkdir -p $value \u0026\u0026 chown -R $user $value\n              fi\n          fi\n       done\n    fi\n}\n\nstart() {\n    [ -x $nginx ] || exit 5\n    [ -f $NGINX_CONF_FILE ] || exit 6\n    make_dirs\n    echo -n $\"Starting $prog: \"\n    daemon $nginx -c $NGINX_CONF_FILE\n    retval=$?\n    echo\n    [ $retval -eq 0 ] \u0026\u0026 touch $lockfile\n    return $retval\n}\n\nstop() {\n    echo -n $\"Stopping $prog: \"\n    killproc $prog -QUIT\n    retval=$?\n    echo\n    [ $retval -eq 0 ] \u0026\u0026 rm -f $lockfile\n    return $retval\n}\n\nrestart() {\n    configtest || return $?\n    stop\n    sleep 1\n    start\n}\n\nreload() {\n    configtest || return $?\n    echo -n $\"Reloading $prog: \"\n    killproc $nginx -HUP\n    RETVAL=$?\n    echo\n}\n\nforce_reload() {\n    restart\n}\n\nconfigtest() {\n  $nginx -t -c $NGINX_CONF_FILE\n}\n\nrh_status() {\n    status $prog\n}\n\nrh_status_q() {\n    rh_status \u003e/dev/null 2\u003e\u00261\n}\n\ncase \"$1\" in\n    start)\n        rh_status_q \u0026\u0026 exit 0\n        $1\n        ;;\n    stop)\n        rh_status_q || exit 0\n        $1\n        ;;\n    restart|configtest)\n        $1\n        ;;\n    reload)\n        rh_status_q || exit 7\n        $1\n        ;;\n    force-reload)\n        force_reload\n        ;;\n    status)\n        rh_status\n        ;;\n    condrestart|try-restart)\n        rh_status_q || exit 0\n            ;;\n    *)\n        echo $\"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}\"\n        exit 2\nesac\n```\n\n4.8 (DO ONLY ONCE)* Set permission to make this script be executable \n```\nchmod +x /etc/init.d/nginx\nsudo systemctl enable nginx\n```\n\n4.9 (DO ONLY ONCE)* To make sure that Nginx starts and stops every time with the Droplet, add it to the default runlevels with the command:\n```\nsudo chkconfig nginx on\nsudo service nginx restart\n```\n\n4.10 Finally, to verify nginx version and opensssl that built by type\n```\nnginx -V\n```\n\n4.11 Start nginx \n```\nsudo systemctl start nginx\n```\n\nIf you see this error\n```\nnginx: [emerg] mkdir() \"/var/cache/nginx/client_temp\" failed (2: No such file or directory)\n```\n\nThen manually create the file /var/cache/nginx/client_temp.\n```\nsudo mkdir /var/cache/nginx\nsudo touch /var/cache/nginx/client_temp\n```\n\n*DO ONLY ONCE mean if you build newer version of nginx and have done these steps before, you can skip these\n\n\n#### Step 5 Setup NGINX Web Server \n\nFor using http2 you need to have certificate (SSL) installed\n\n5.0 To get maximum throughput in high concurrency you need to tune os configuration.\n\n```bash\n/etc/security/limits.conf\n#   web soft nofile 65535\n#   web hard nofile 65535\n#   /etc/default/nginx\n#   ULIMIT=\"-n 65535\"\n```\n\n5.1 Go to nginx global file directory\n\n```\ncd /etc/nginx/\nsudo vi nginx.conf\n```\n\n5.2 Config the file as below \n\n```nginx\nuser  nginx;\n\n_processes auto;\nworker_rlimit_nofile 65535;\nerror_log /var/log/nginx/error.log crit;\npid   /var/run/nginx.pid;\n\nevents {\n    worker_connections 2048; #     2048 * (If you have 2 cores) = max clients handle\n    use epoll; # use efficient long polling this method will accept many connections as possible\n    multi_accept on; # worker process will accept one new connection at a time\n}\n\nhttp {\n    sendfile                      on; # turn this off if you're running in a vm environment\n    tcp_nopush                    on;\n    tcp_nodelay                   on;\n    reset_timedout_connection     on;\n    server_tokens                 off;  \n    keepalive_requests            1000;\n    keepalive_timeout             60s;\n    send_timeout                  120s;\n\n    include                       /etc/nginx/mime.types;\n    default_type                 application/octet-stream;\n    \n    ##\n    # OpenFile Cache Settings\n    ##\n    open_file_cache              max=1000 inactive=20s; \n    open_file_cache_valid        30s; \n    open_file_cache_min_uses     2;\n    open_file_cache_errors       off;\n\n    ##\n    # Limit request per IP (DDoS prevention)\n    ##    \n    limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;\n    limit_req                          zone=one burst=10 nodelay;\n    limit_req_status                   403;\n\n    ##\n    # Buffer Limit Settings\n    ##\n    client_header_buffer_size    1k;\n    client_body_buffer_size      128k;\n    client_max_body_size         10m;\n    client_header_timeout        30s;\n    client_body_timeout          30s;\n    large_client_header_buffers  4 256k;\n    \n    ##\n    # Logging Settings\n    ##\n    access_log off; # Disable to improve I/O just enable only error\n\n    ##\n    # Proxy Cache Settings (If you're using NodeJS, ExpressJS, KoaJS)\n    ##\n    proxy_cache one;\n    proxy_cache_min_uses 3;\n    proxy_cache_revalidate on;\n    proxy_cache_bypass  $http_cache_control;\n    proxy_cache_path /var/nginx/cache levels=1:2 keys_zone=one:10m inactive=60m max_size=512m use_temp_path=off;\n    proxy_cache_key \"$host$request_uri$cookie_user\";\n    proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;\n    proxy_cache_valid any 1m;\n\n    ##\n    # Brotli Settings (If you not have brotli install, delete this config)\n    ##\n    #brotli on;\n    #brotli_static on;\n    #brotli_min_length 1000;\n    #brotli_buffers 32 8k;\n    #brotli_comp_level 6;\n    #brotli_types text/plain text/css text/javascript text/xml font/opentype application/javascript application/x-javascript application/json application/xml application/xml+rss application/ecmascript image/svg+xml;\n    \n    ##\n    # Gzip Settings (If have brotli installed, disable this config)\n    ##\n    gzip                        on;\n    gzip_vary                   on;\n    gzip_min_length             10240;\n    gzip_proxied                expired no-cache no-store private auth;\n    gzip_types                  text/plain text/css text/xml text/javascript application/x-javascript application/xml;\n    gzip_disable                msie6;\n\n    ##\n    # Virtual Block Host Configs\n    ##\n    server_names_hash_bucket_size 64;\n    include /etc/nginx/conf.d/*.conf;\n}\n```\n\n5.3 Save and test nginx config then restart nginx service\n\n```\nnginx -t\nsystemctl restart nginx.service\n```\n\n5.4 Go to sites-available and create the following file to build a block hosting\n\n```\ncd sites-available/\nvi \u003cyour-domain-name\u003e.conf\n```\n\n5.5 Config file as below\n\n```nginx\nserver {\n    listen 80 default_server;\n    listen [::]:80 default_server;\n    server_name \u003cyour-domain-name\u003e www.\u003cyour-domain-name\u003e;\n    return 301 https://$host$request_uri;\n}\n\nserver {\n    listen 443 ssl http2 reuseport;\n    listen [::]:443 ssl http2 reuseport;\n    server_name \u003cyour-domain-name\u003e;\n\n    root /var/www/\u003cweb-folder-name\u003e/html;\n    index index.html;\n    charset utf-8;\n\n    error_page  404     /404.html;\n    error_page  403     /403.html;\n    error_page  500 502 503 504 /50x.html;\n\n    location / {\n        limit_conn conn_limit_per_ip 10;\n        limit_req zone=req_limit_per_ip burst=10 nodelay;\n        try_files $uri $uri/ =404;\n    }\n\n    # If you using as proxy server (eg: NodeJS, ExpressJS, KoaJS)\n    #location / {\n      #proxy_http_version      1.1;\n      #proxy_set_header        Upgrade                 $http_upgrade;\n      #proxy_set_header        Connection              \"upgrade\";\n      #proxy_set_header        X-Real-IP               $remote_addr;\n      #proxy_set_header        X-Forwarded-For         $proxy_add_x_forwarded_for;\n      #proxy_set_header        Host                    $host;\n      #proxy_connect_timeout   60;\n      #proxy_send_timeout      60;\n      #proxy_read_timeout      60;\n      #proxy_redirect          off;\n      #proxy_buffers           8 32k;\n      #proxy_buffer_size       64k;\n\n      #proxy_pass              http://localhost:3000;\n    }\n    \n    # Load balancer nodes, if you're using docker or using as cluster, \n    # replace proxy_pass with http://io_nodes\n    #upstream io_nodes {\n      #ip_hash; # If you using websocket must use ip_hash to stick client to same server\n      #server localhost:3000;\n      #server localhost:3001;\n      #server localhost:3002;\n    #}\n    \n    # Html and data cache timeout (no cache)\n    location ~* \\.(?:manifest|appcache|html?)$ {\n        expires -1;\n        access_log off;\n    }\n\n    # Feed cache timeout\n    location ~* \\.(?:rss|atom)$ {\n        expires 1h;\n        access_log off;\n        add_header Cache-Control \"public\";\n    }\n\n    # Static files cache timeout\n    location ~* \\.(?:jpg|jpeg|gif|png|ico|webp|gz|svg|svgz|eot|woff|woff2|oft|avi|wmv|mp3|mp4|ogg|ogv|webm|xml|txt|json|csv|pdf)$ {\n        expires 1d;\n        access_log off;\n        add_header Cache-Control \"public\";\n    }\n     \n    # Style, Script files cache timeout\n    location ~* \\.(?:css|js)$ {\n        expires 7d;\n        access_log off;\n        add_header Cache-Control \"public\";\n    }\n     \n    # Deny scripts inside writable directories\n    location ~* /(img|cache|media|logs|tmp|image|images)/.*.(php|pl|py|jsp|asp|sh|cgi)$ {\n        return 403;\n    }\n\n    # SSL Certificate config\n    ssl_certificate /etc/ssl/\u003cyourweb-ssl-folder\u003e/cert.crt;\n    ssl_certificate_key /etc/ssl/\u003cyourweb-ssl-folder\u003e/privkey.key;\n    ssl_trusted_certificate /etc/ssl/\u003cyourweb-ssl-folder\u003e/trustchain.crt;\n    ssl_session_timeout 60m;\n    ssl_session_cache shared:SSL:10m;\n    ssl_session_tickets off;\n\n    # Diffie-Hellman parameter for DHE ciphersuites, recommended 4096 bits\n    # to generate your dhparam.pem file, run $ openssl dhparam -out /etc/nginx/ssl/\u003cyour-domain-name\u003e/dhparam.pem 4096\n    ssl_dhparam  /etc/ssl/\u003cyourweb-ssl-folder\u003e/dhparam.pem;\n\n    # SSL Key exchanges\n    ssl_protocols TLSv1.3 TLSv1.2; # !! TLS 1.3 Requires openssl \u003e= 1.1.1 and nginx \u003e= 1.13.0 !!\n    ssl_ecdh_curve prime256v1:secp384r1:secp521r1;\n    ssl_ciphers 'TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-256-GCM-SHA384:TLS13-AES-128-GCM-SHA256:EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';\n    ssl_prefer_server_ciphers on;\n\n    # OCSP Stapling - fetch OCSP records from URL in ssl_certificate and cache them for faster handshake\n    ssl_stapling on;\n    ssl_stapling_verify on;\n    \n    # DNS Resolver - to lookup your upstream domain name URL\n    resolver 1.1.1.1 8.8.8.8 valid=300s ipv6=off;\n    resolver_timeout 10s;\n\n    # Security Header\n    add_header Strict-Transport-Security \"max-age=31536000; includeSubdomains; preload\";\n    add_header Referrer-Policy no-referrer-when-downgrade;\n    add_header X-Content-Type-Options nosniff;\n    add_header X-Frame-Options SAMEORIGIN;\n    add_header X-XSS-Protection \"1; mode=block\";\n    add_header Content-Security-Policy upgrade-insecure-requests;\n    # Please add you own resource domain to this custom CSP!! and delete the line upper.\n    # add_header Content-Security-Policy \"default-src 'none'; frame-ancestors 'none'; base-uri 'none'; child-src 'none'; object-src 'none'; form-action 'self'; script-src 'self' https://storage.googleapis.com https://www.googletagmanager.com https://www.google-analytics.com https://apis.google.com https://cdnjs.cloudflare.com; img-src 'self' https: data: *.googleusercontent.com; style-src 'self' unsafe-inline https:; font-src 'self' https: data:; frame-src 'self' https:; connect-src 'self' https:; worker-src 'self';\";\n}\n\n    # Public Key Pinning Extension for HTTP (HPKP) - OPTIONAL\n    # to generate use one of these and put base64 text in pin-sha256:  \n    # $ openssl rsa -in my-website.key -outform der -pubout | openssl dgst -sha256 -binary | base64\n    # $ openssl req -in my-website.csr -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | base64\n    add_header Public-Key-Pins 'pin-sha256=\"\u003cbase64+primary==\u003e\"; pin-sha256=\"\u003cbase64+backup==\u003e\"; max-age=31536000; includeSubDomains'; \n```\n\n!!! In order to generate base64 for backup key, you need to generate a backup certificates set from CA. !!!\nLEARN MORE: about HPKP: https://developer.mozilla.org/en-US/docs/Web/Security/Public_Key_Pinning\n\nLEARN MORE: about configuration: https://mozilla.github.io/server-side-tls/ssl-config-generator/\n\n!!! For website that include Facebook Sharing (FB.UI) using X-Frame-Options can refused to display. \nSolution: is set target=\"_top\" on the link or window.top.location=\u003cFBAppNameSpaces\u003e\n    \n!!! For website that include Youtube iFrame using X-Frame-Options can refused to display too.\nSolution: try replace https://www.youtube.com/watch?v= with https://www.youtube.com/embed/\n\n!!! If you're using Facebook Sharing or Embedded frame eg: youtube, vimeo, facebook login button or codepen you need to set X-Frame-Options to SAMEORIGIN otherwise it will refuse to load content from external iframe.\n\n!!! Learn more about Socket Sharding in NGINX Release 1.9.1 (reuseport)\nhttps://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1/\n\nTIP: Resolver in Nginx is a load-balancer that resolves an upstream domain name asynchronously. It chooses one IP from its buffer according to round-robin for each request. Its buffer has the latest IPs of the backend domain name. At every interval (one second by default), it resolves the domain name. If it fails to resolve the domain name, the buffer retains the last successfully resolved IPs.\n\nssl_ciphers are reference from: https://blog.sandchaschte.ch/en/latest-nginx-with-tlsv1-3-and-brotli\n\n5.6 Enable config file by symbolic them\n```\ncd /etc/nginx/sites-enabled/\nls -s /etc/nginx/sites-available/\u003cyour-domain-name\u003e.conf /etc/nginx/sites-enabled/\n```\n\n5.7 Save and test nginx config then restart nginx service\n```\nnginx -t\nsystemctl restart nginx.service\n```\n\n5.8 Test your website SSL\n\nhttps://observatory.mozilla.org/\nhttps://www.ssllabs.com/ssltest/\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://cdn.rawgit.com/jukbot/setup-nginx-webserver/21a211ec/observation_mozilla.png\" alt=\"MOZILLA_OBSERVVATORY_result\"/\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://cdn.rawgit.com/jukbot/setup-webserver-centos7/12a2c363/ssllab_result_.png\" alt=\"SSLLAB_result\"/\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://cdn.rawgit.com/jukbot/setup-webserver-centos7/12a2c363/handshake_result.png\" alt=\"handshake_Result\"/\u003e\n\u003c/p\u003e\n\nRead more about 7 Tips for Faster HTTP/2 Performance\nhttps://www.nginx.com/blog/7-tips-for-faster-http2-performance/\n\n\n#### Step 6: Config SELinux to allow NGINX process (FOR ENHANCED SECURITY)\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://github.com/jukbot/setup-webserver-centos7/blob/master/selinux_diagram.png\" alt=\"SELinux_diagram\"/\u003e\n\u003c/p\u003e\n \n \n#### Introduction\n\nSecurity Enhanced Linux or SELinux is an advanced access control mechanism built into most modern Linux distributions. \nMany system administrators find SELinux a somewhat uncharted territory. The topic can seem daunting and at times quite confusing. \n\nHowever, a properly configured SELinux system can greatly reduce security risks, and knowing a bit about it can help you troubleshoot access-related error messages. In this section we will guide the basic config of SELinux for Nginx process\nWe will also see a few practical instances of putting SELinux in action.\n\n#### SELinux Modes\nFirst off, a quick overview of the three different SELinux modes. SELinux can be in enforcing, permissive, or disabled mode.\n\n| Policy Mode | Detail | \n|---------|---------------|\n| Enforcing | This is the default. In enforcing mode, if something happens on the system that is against the defined policy, the action will be both blocked and logged. |\n| Permissive | This mode will not actually block or deny anything from happening, however it will log anything that would have normally been blocked in enforcing mode. It’s a good mode to use if you perhaps want to test a Linux system that has never used SELinux and you want to get an idea of any problems you may have. No system reboot is needed when swapping between permissive and enforcing modes. |\n| Disabled | Disabled is completely turned off, nothing is logged at all. In order to swap to the disabled mode, a system reboot will be required. Additionally if you are switching from disabled mode to either permissive or enforcing modes a system reboot will also be required. |\n\n#### View current SELinux Status \n\nCentOS/RHEL use SELinux in enforcing mode by default, there are a few ways that we can check and confirm this. \n\nRun command sestatus to view current SELinux mode\n\n```shell\n$ sestatus\nSELinux status:                 enabled\nSELinuxfs mount:                /sys/fs/selinux\nSELinux root directory:         /etc/selinux\nLoaded policy name:             targeted\nCurrent mode:                   enforcing\nMode from config file:          enforcing\nPolicy MLS status:              enabled\nPolicy deny_unknown status:     allowed\nMax kernel policy version:      28\n````\n\nAs shown above both of these show that we are currently in enforcing mode.\n\nNote: SELinux is incredibly valuable as part of an overall Linux system security strategy, and we recommend leaving it enabled in enforcing mode in production environments where possible. If a particular application or package does not work properly with SELinux customized allowances can be made which is the preferred option compared to simply disabling the whole thing.\n\n#### Let's config our policy\n\nIn this section, we will be running the commands as the root user unless otherwise stated. If you don't have access to the root account and use another account with sudo privileges, you need to precede the commands with the sudo keyword.\n\n6.1 First, we'll install selinux manager\n```\nsudo yum install policycoreutils-python\n```\n\nBy default, web server will not have permision to connect to socket directly, in this case if we want to use it as reverse proxy but SELinux not allow to use socket. \n\nMost people will disable SELinux policy to fix this issue. In the worst case if other application that not Nginx has been hacked from backdoor the SELinux will keep log and process report. Which you can view using audit2allow as follow: \n\n6.2 Export audit of nginx process and export as policy package (.pp) file\n```\nsudo cat /var/log/audit/audit.log | grep nginx | grep denied | audit2allow -m nginxlocalconf \u003e nginxlocalconf.pp\n```\n\n6.3 Then install our exported policy package by command\n```\nsemodule -i nginxlocalconf.pp\n```\n\nDone, after installed this will append to default system policy in SELinux. Which allow nginx to access the socket safely.\n\nReference: \n- https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-open-source/\n- https://gist.github.com/plentz/6737338\n- https://www.digitalocean.com/community/tutorial_series/an-introduction-to-selinux-on-centos-7\n- https://www.rootusers.com/how-to-enable-or-disable-selinux-in-centos-rhel-7/\n- https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html-single/7.4_release_notes/index\n- https://www.nginx.com/resources/wiki/start/topics/examples/SSL-Offloader/\n- https://gist.github.com/v0lkan/90fcb83c86918732b894\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjukbot%2Fsetup-nginx-webserver","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjukbot%2Fsetup-nginx-webserver","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjukbot%2Fsetup-nginx-webserver/lists"}