How to Configure Nginx Server Blocks (Virtual Hosts) on RHEL 7

Nginx server blocks — the equivalent of Apache virtual hosts — allow a single Nginx instance to serve multiple websites on the same server by routing requests based on the domain name or IP address. This is one of the most common Nginx configurations in production environments, enabling efficient use of server resources. On RHEL 7, server block configuration files are placed in the /etc/nginx/conf.d/ directory and loaded automatically by the main nginx.conf file. This tutorial walks through creating server block configurations, testing them, handling SELinux considerations, and verifying that each site is served correctly.

Prerequisites

  • Nginx installed and running on RHEL 7 (see the Nginx installation tutorial)
  • Root or sudo access
  • One or more domain names pointing to your server’s IP address, or the ability to test with curl using a Host header
  • Basic understanding of DNS and web server concepts

Step 1: Understand the Configuration Directory Structure

Nginx on RHEL 7 uses the following layout for configuration files:

  • /etc/nginx/nginx.conf — Main configuration file; global settings and the http block that includes all conf.d files.
  • /etc/nginx/conf.d/ — Drop-in directory for virtual host (server block) configuration files. All .conf files here are loaded automatically.
  • /etc/nginx/default.d/ — Drop-in directory for location block snippets applied to the default server.

Verify the include directive is present in the main config:

grep "conf.d" /etc/nginx/nginx.conf

You should see a line similar to:

    include /etc/nginx/conf.d/*.conf;

Step 2: Create Web Root Directories for Each Site

Create a document root directory for each site you intend to host. Replace example1.com and example2.com with your actual domain names:

sudo mkdir -p /var/www/example1.com/html
sudo mkdir -p /var/www/example2.com/html

Set appropriate ownership so Nginx can read the files:

sudo chown -R nginx:nginx /var/www/example1.com
sudo chown -R nginx:nginx /var/www/example2.com

Create test index pages for each site:

echo "<h1>Welcome to example1.com</h1>" | sudo tee /var/www/example1.com/html/index.html
echo "<h1>Welcome to example2.com</h1>" | sudo tee /var/www/example2.com/html/index.html

Step 3: Set the Correct SELinux Context

Because the web roots are outside the default /usr/share/nginx/html path, SELinux will deny Nginx access to them unless you set the correct file context. Apply the httpd_sys_content_t type recursively:

sudo semanage fcontext -a -t httpd_sys_content_t "/var/www/example1.com(/.*)?"
sudo semanage fcontext -a -t httpd_sys_content_t "/var/www/example2.com(/.*)?"
sudo restorecon -Rv /var/www/example1.com
sudo restorecon -Rv /var/www/example2.com

Alternatively, use chcon for a quick non-persistent fix while testing:

sudo chcon -R -t httpd_sys_content_t /var/www/example1.com
sudo chcon -R -t httpd_sys_content_t /var/www/example2.com

Step 4: Create the Server Block Configuration Files

Create a configuration file for the first site. The filename should clearly identify the site:

sudo vi /etc/nginx/conf.d/example1.com.conf

Add the following server block content:

server {
    listen       80;
    server_name  example1.com www.example1.com;

    root   /var/www/example1.com/html;
    index  index.html index.htm;

    access_log  /var/log/nginx/example1.com.access.log  main;
    error_log   /var/log/nginx/example1.com.error.log   warn;

    location / {
        try_files $uri $uri/ =404;
    }

    error_page  404              /404.html;
    error_page  500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

Now create the configuration file for the second site:

sudo vi /etc/nginx/conf.d/example2.com.conf
server {
    listen       80;
    server_name  example2.com www.example2.com;

    root   /var/www/example2.com/html;
    index  index.html index.htm;

    access_log  /var/log/nginx/example2.com.access.log  main;
    error_log   /var/log/nginx/example2.com.error.log   warn;

    location / {
        try_files $uri $uri/ =404;
    }

    error_page  404              /404.html;
    error_page  500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

Step 5: Disable or Modify the Default Server Block

The default Nginx configuration on RHEL 7 includes a catch-all server block in the main nginx.conf file. If you want requests to undefined server names to return a 444 (no response) or redirect to a specific site, you can add a default catch-all server block. Create a dedicated file:

sudo vi /etc/nginx/conf.d/default_catchall.conf
server {
    listen       80 default_server;
    server_name  _;
    return       444;
}

This block will silently drop connections that do not match any defined server_name, which is useful for blocking automated scanners that probe by IP address.

Step 6: Test the Nginx Configuration

Always validate the configuration syntax before reloading Nginx:

sudo nginx -t

Successful output:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

If there are errors, Nginx will report the exact file and line number. Fix all reported issues before proceeding.

Step 7: Reload Nginx to Apply the Configuration

Reload Nginx to apply the new server blocks without interrupting active connections:

sudo systemctl reload nginx

Step 8: Check the SELinux Boolean for Network Connections

If Nginx is acting as a reverse proxy or needs to make outbound network connections (for example, to a backend application server), you must enable the httpd_can_network_connect SELinux boolean:

sudo setsebool -P httpd_can_network_connect on

To verify the current state of this boolean:

getsebool httpd_can_network_connect

For static file serving only, this boolean is not required.

Step 9: Test Virtual Hosts with curl

If DNS is not yet configured for your test domains, you can simulate name-based virtual hosting using the -H flag in curl to send a custom Host header:

curl -H "Host: example1.com" http://localhost

Expected output:

<h1>Welcome to example1.com</h1>

Test the second site:

curl -H "Host: example2.com" http://localhost

Expected output:

<h1>Welcome to example2.com</h1>

If you have actual DNS entries pointing to your server, you can test directly with:

curl http://example1.com
curl http://example2.com

Step 10: Review Per-Site Log Files

Each server block above defines its own access and error log paths. Monitor them independently for per-site debugging:

sudo tail -f /var/log/nginx/example1.com.access.log
sudo tail -f /var/log/nginx/example1.com.error.log

Having separate log files per virtual host makes it much easier to isolate traffic and errors for individual sites on a shared server.

Conclusion

You have configured multiple Nginx server blocks on RHEL 7, enabling a single server instance to host several websites simultaneously. Each site has its own document root, log files, and configuration file in /etc/nginx/conf.d/. You have validated the configuration with nginx -t, applied SELinux contexts to the custom web roots, and verified that each virtual host responds correctly using curl with a custom Host header. The next natural step is to secure each site with HTTPS by obtaining SSL/TLS certificates from Let’s Encrypt using Certbot.