How to install NGINX Web Server on RHEL 8 - nomorespice/rhel8-howto GitHub Wiki

Nginx is a web server which can also be used as a reverse proxy, load balancer, mail proxy and HTTP cache. This procedure will guide you through the installation process on a Red Hat Enterprise Linux 8 server.

This document assumes that:

  • you installed the RHEL 8 x64 Operating System according to How to install RHEL 8 via kickstart
  • you are performing these tasks as root
  • you are performing these tasks in order, as some tasks require others to be completed first

Add and disable the EPEL repository and install required software

dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
yum-config-manager --disable epel
dnf -y install nginx

Configure the /etc/nginx/nginx.conf main configuration file

Be sure to modify this file with the correct number of available CPUs and affinity.

/bin/cat <<\EOT >/etc/nginx/nginx.conf
user nginx;
worker_processes    2;
worker_cpu_affinity 0101 1010;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;
    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    types_hash_max_size 2048;
    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;
    large_client_header_buffers 2 1k;
    client_max_body_size 100K;
    client_body_timeout 10;
    client_header_timeout 10;
    keepalive_timeout 10;
    send_timeout 10;
    limit_conn_zone $binary_remote_addr zone=limitperip:10m;
    limit_req_zone $binary_remote_addr zone=ratelimit:10m rate=5r/s;
    include /etc/nginx/conf.d/*.conf;
}
EOT

Create a self-signed certificate for the default server

Be sure to replace the STATE, CITY and ORG when creating the default SSL certificate.

mkdir -p /etc/nginx/ssl/default/
openssl req -new -newkey rsa:4096 -days 2000 -nodes -x509 -subj "/C=US/ST=STATE/L=CITY/O=ORG/CN=default" -keyout /etc/nginx/ssl/default/default.key -out /etc/nginx/ssl/default/default.pem
openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048
openssl x509 -pubkey < /etc/nginx/ssl/default/default.pem | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64

Create the /etc/nginx/conf.d/default.conf default server configuration file

Be sure to update the PUBLIC-KEY-PIN with the output of the last command above

  • Also update the allow section and include your IP addresses you which to allow to connect
/bin/cat <<\EOT >/etc/nginx/conf.d/default.conf
server {
    listen 443 ssl http2 default_server;
    server_name _;

    ssl_certificate /etc/nginx/ssl/default/default.pem;
    ssl_certificate_key /etc/nginx/ssl/default/default.key;
    ssl_dhparam /etc/nginx/ssl/dhparam.pem;
    ssl_session_cache shared:SSL:20m;
    ssl_session_timeout 10m;
    ssl_prefer_server_ciphers       on;
    ssl_protocols TLSv1.2;
    ssl_ciphers ALL:!EXP:!NULL:!ADH:!LOW:!SSLv2:!SSLv3:!MD5:!RC4;
    ssl_session_tickets off;
    add_header Public-Key-Pins 'pin-sha256="base64+primary==PUBLIC-KEY-PIN"; max-age=5184000';

    add_header Strict-Transport-Security "max-age=15768000;";
    add_header X-Frame-Options SAMEORIGIN;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header Content-Security-Policy "default-src 'self'";
    add_header Referrer-Policy "no-referrer";
    server_tokens off;
    limit_conn limitperip 10;

    if ( $request_method !~ ^(GET|HEAD|POST)$ ) {
        return 444;
    }

    location = / {
        limit_req zone=ratelimit burst=10 nodelay;
        allow 10.0.0.0/8;
        deny all;
        return 404;
    }
   location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires max;
        log_not_found off;
    }

    error_page 404 /404.html;
    location = /404.html {
        root /var/www/;
        internal;
    }

    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /var/www/;
        internal;
    }
}
EOT

Disable the default Nginx html error pages and create generic error pages

/bin/cat <<\EOT >/var/www/404.html
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head> 
 <title>Page not found</title> 
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
 <body> 
 <h1><strong>Page not found</strong></h1> 
 </body> 
</html>
EOT

/bin/cat <<\EOT >/var/www/50x.html
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head> 
 <title>Page error</title> 
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
 <body> 
 <h1><strong>Page error</strong></h1> 
 </body> 
</html>
EOT

/sbin/restorecon -Rv /var/www/*

Install and execute the certbot script to create an SSL certificate for the website

Be sure to replace the STATE, CITY and ORG when creating the default SSL certificate. Also replace host.example.com with your host and domain.

yum -y --enablerepo=epel install certbot
certbot certonly --manual -d host.example.com --preferred-challenges dns
mkdir /etc/nginx/ssl/host.example.com
ln -s /etc/letsencrypt/live/host.example.com/privkey.pem /etc/nginx/ssl/host.example.com/server.key
ln -s /etc/letsencrypt/live/host.example.com/fullchain.pem /etc/nginx/ssl/host.example.com/server.crt
openssl x509 -pubkey < /etc/nginx/ssl/host.example.com/server.crt | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64

Create the /etc/nginx/conf.d/host.example.com.conf server configuration file

As before, be sure to update the PUBLIC-KEY-PIN with the output of the last command above.

  • Also update the allow section and include your IP addresses you which to allow to connect.
  • Finally, replace host.example.com with your host and domain.
/bin/cat << EOT >/etc/nginx/conf.d/host.example.com.conf
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name host.example.com;

    ssl on;
    ssl_certificate /etc/nginx/ssl/host.example.com/server.crt;
    ssl_certificate_key /etc/nginx/ssl/host.example.com/server.key;
    ssl_dhparam /etc/nginx/ssl/dhparam.pem;
    ssl_session_cache shared:SSL:20m;
    ssl_session_timeout 10m;
    ssl_prefer_server_ciphers on;
    ssl_protocols TLSv1.2;
    ssl_ciphers ALL:!EXP:!NULL:!ADH:!LOW:!SSLv2:!SSLv3:!MD5:!RC4;
    ssl_session_tickets off;
    add_header Public-Key-Pins 'pin-sha256="base64+primary==PUBLIC-KEY-PIN"; max-age=5184000';

    add_header Strict-Transport-Security "max-age=15768000;";
    add_header X-Frame-Options SAMEORIGIN;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header Content-Security-Policy "default-src 'self'";
    add_header Referrer-Policy "no-referrer";
    server_tokens off;
    limit_conn limitperip 10;

    if ( \$request_method !~ ^(GET|HEAD|POST)$ ) {
        return 444;
    }

    root /var/www/html;

    location / {
        index index.php index.html index.htm;
        limit_req zone=ratelimit burst=10 nodelay;
	allow 10.0.0.0/8;
        deny    all;
    }

    location ~ \.php\$ {
        try_files 	\$uri =404;
        fastcgi_pass 	unix:/run/php-fpm/www.sock;
        fastcgi_index 	index.php;
        fastcgi_param 	SCRIPT_FILENAME \$document_root\$fastcgi_script_name;
        include 	fastcgi_params;
    }

    error_page 404 /404.html;
    location = /404.html {
        root /var/www;
        internal;
    }
    
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /var/www;
        internal;
    }
}
EOT

Add and disable the REMI repository and install the latest PHP packages

yum install http://rpms.remirepo.net/enterprise/remi-release-7.rpm
yum-config-manager -q --disable remi-safe
yum -y --enablerepo=remi-php74 --enablerepo=epel --enablerepo=remi-safe install php-fpm php-opcache php-cli php-gd php-curl php-mysql

Configure the PHP-FPM service

/bin/sed -i "s/^user = apache/user = nginx/" /etc/php-fpm.d/www.conf
/bin/sed -i "s/^group = apache/group = nginx/" /etc/php-fpm.d/www.conf
/bin/sed -i 's/^listen = 127.0.0.1:9000/listen = \/run\/php-fpm\/www.sock/' /etc/php-fpm.d/www.conf
/bin/sed -i "s/^;listen.owner = nobody/listen.owner = nginx/" /etc/php-fpm.d/www.conf
/bin/sed -i "s/^;listen.group = nobody/listen.group = nginx/" /etc/php-fpm.d/www.conf
/bin/chown -R root:nginx /var/lib/php
setsebool httpd_execmem on
systemctl enable php-fpm
systemctl start php-fpm

Once your content is created under the web root directory, restore the SELinux context on those files

Only required if SELinux is enforcing on your system.

/sbin/restorecon -Rv /var/www/html/*

Optional - Enable nginx secure links

This step is optional

  • Be sure to modify the SECRET

Insert the following configuration into the "server" section of the /etc/nginx/conf.d/host.example.com.conf file

    location /files/ {
    secure_link_secret SECRET;
    if ($secure_link = "") { return 403; }
    rewrite ^ /secure/$secure_link;
    }

Create a test file and generate the hash

mkdir /var/www/html/secure
echo "Hello World" > /var/www/html/secure/file.txt
chown nginx:nginx /var/www/html/secure/file.txt
chmod 644 /var/www/html/secure/file.txt
restorecon -v /var/www/html/secure/*
echo -n '/var/www/html/secure/file.txt' | openssl md5 -hex

Use the generated hash to build a link to your secure file

https://HOSTNAME.EXAMPLE.COM/files/7f70a978876be3d1652a2fa161d9242d/file.txt

Enable and start the nginx service

systemctl --now enable nginx
⚠️ **GitHub.com Fallback** ⚠️