HTTPS for Nginx on RHEL, CentOS, and Rocky

Last Updated:

Verification

These commands were tested on default installations of CentOS Stream 8 and 9 in May 2022. If you experience issues, Contact Ryan and report an issue

(Optional) Upgrade Packages

Make sure your machine has the latest packages installed and reboot.

  
    sudo yum update -y;
    sudo reboot;
  

Upload Site Files

For example purposes, we'll add one static file. You can download your own site's files instead if you have some.

  
    sudo mkdir -p /usr/share/nginx/html/example.com/public;
    echo "

HTTPS Site

" | sudo tee /usr/share/nginx/html/example.com/public/index.html;

Generate Diffie-Hellman Parameters

We generate a new set of parameters unique to your machines. This improves security because usually a default set of DH parameters are used by everyone that installs Nginx. We'll use this file in a little bit.

  
    # Generate Diffie-Hellman Parameters
    sudo openssl dhparam -out /etc/pki/tls/dhparam.pem 2048;
  

Copy TLS Certificate Files

Here we copy the needed TLS key and certificate files from previous lessons. Then we ensure the permissions are correct on both files. You might need to upload your certificate files onto the machine if you bought a certificate or generated a free certificate on another machine.

  
    # Edit the file names to something that
    # makes sense in your situation.

    # Copy Your TLS Key
    cp MY_CERTIFICATE.key /etc/pki/tls/private/MY_CERTIFICATE.key;
    chmod 600 /etc/pki/tls/private/MY_CERTIFICATE.key;

    # Copy Your TLS Certificate
    cp MY_CERTIFICATE.pem /etc/pki/tls/certs/MY_CERTIFICATE.pem;
    chmod 644 /etc/pki/tls/certs/MY_CERTIFICATE.pem;
  

Installing Nginx

We now install Nginx via EPEL (Extra Packages for Enterprise Linux)

  
    # Install EPEL Repository
    sudo yum install -y epel-release;

    # Install Nginx
    sudo yum install -y nginx;

    # Want to Check Nginx Version?
    # nginx -v;
    # nginx version: nginx/1.14.1

    # Back up the default nginx.conf file (we'll edit it soon)
    sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.original;

    # Blank out the original file
    echo "" | sudo tee /etc/nginx/nginx.conf;
  

Edit Nginx Configuration

The provided Nginx configuration is not very modular and has the default site hard-coded. Instead, we'll load files in /etc/nginx/conf.d/ and these edits make it possible.

  
# Filename: /etc/nginx/nginx.conf

# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
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;
    keepalive_timeout   65;
    types_hash_max_size 4096;
    server_tokens       off;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;
}
  

HTTP to HTTPS Redirect

For our first site configuration, we redirect any insecure HTTP traffic on port 80 to HTTPS. Pay close attention to the highlighted lines and make changes so it matches your domain.

  
    # Filename: /etc/nginx/conf.d/example.com.http.conf
    server {
      listen       80;
      server_name  example.com;
      charset      utf-8;
      root         /usr/share/nginx/html/example.com/public;
      index        index.html index.htm;

      # Redirect to HTTPS
      return       301  https://example.com$request_uri;
    }
  

HTTPS Configuration

Now we add the main HTTPS site configuration. Here's the full configuration file, and we'll break it down section by section. Pay close attention to the highlighted lines and make changes so it matches your domain.

Lines 17-20: For enhanced security at the risk of your site breaking for some visitors, you can use the stronger ciphers instead.

Line 24: We're specifying Nginx should use the unique DH Parameters we generated earlier.

Line 30: When you're sure everything is working, you can enable this line to increase your site's grade on Qualys' SSLLabs from an "A" to an "A+" rating.

  
    # Filename: /etc/nginx/conf.d/example.com.https.conf
    server {
        listen       443 ssl;
        server_name  example.com;
        charset      utf-8;
        root         /usr/share/nginx/html/example.com/public;
        index        index.html index.htm;

        # SSL/TLS Settings
        ssl_protocols              TLSv1.2 TLSv1.3;
        ssl_certificate            /etc/pki/tls/certs/MY_CERTIFICATE.pem;
        ssl_certificate_key        /etc/pki/tls/private/MY_CERTIFICATE.key;
        ssl_session_timeout        1d;
        ssl_session_cache          shared:SSL:50m;
        ssl_session_tickets        off;
        ssl_prefer_server_ciphers  on;
        ssl_ciphers                'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256';
        # For better security, you can use the below strong ciphers instead
        # But beware, it might break the site for some of your visitors
        #ssl_ciphers               'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256';

        # Generate with:
        # openssl dhparam -out /etc/pki/tls/dhparam.pem 2048;
        ssl_dhparam /etc/pki/tls/dhparam.pem;

        # Optional
        # Forces TLS for all visitors for 1 year
        # Only enable this when you are sure everything is working well
        # Required for an "A+" Grade
        #add_header 'Strict-Transport-Security' 'max-age=31536000; includeSubDomains; preload' always;

    }
  

Testing Our Configuration

It's always a good idea to check our configurations and see if there are any errors. We do this with the command "nginx -t" (the "t" is for "test").

  
    # Test the Nginx configuration
    sudo nginx -t;

    # Output should be similar to:
    # nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
    # nginx: configuration file /etc/nginx/nginx.conf test is successful
  

Starting Nginx

We now need to make sure Nginx is running. First, we make sure Nginx is "enabled" which means Nginx will start on boot of the machine. Then, we "restart" Nginx which will restart it if it's running or if it's not running, start it. We prefer "restart" because it works in either case.

  
    # Run Nginx automatically at boot by "enabling" it
    sudo systemctl enable nginx;

    # Start or Restart Nginx Now
    sudo systemctl restart nginx;
  

You're Done!

Your new site should be available and running. To test it in your browser, make sure you set up a DNS "A" Record on your domain that contains your machine's IP. When you visit the domain, the site should load correctly and should also be ready to test on Qualys SSLLabs where you'll get an "A" rating! (or "A+" if you enabled the setting in the configuration).

Tags: