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
sudoaccess - One or more domain names pointing to your server’s IP address, or the ability to test with
curlusing 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 thehttpblock that includes all conf.d files./etc/nginx/conf.d/— Drop-in directory for virtual host (server block) configuration files. All.conffiles 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.