Nginx (pronounced “engine-x”) is the most widely deployed web server in the world, powering everything from small personal websites to the largest content delivery networks. On RHEL 9, Nginx is available from the AppStream repository and integrates natively with SELinux, firewalld, and systemd. Its event-driven, non-blocking architecture means a single Nginx worker process can handle thousands of concurrent connections while consuming far less memory than thread-per-connection alternatives like Apache. This guide covers installing Nginx from the RHEL 9 AppStream, configuring the firewall and SELinux for web traffic, testing the default installation, and setting up a basic server block to serve a website.
Prerequisites
- RHEL 9 server with root or sudo access
- A registered and subscribed RHEL 9 system (or AlmaLinux/Rocky Linux equivalent)
- Port 80 and 443 accessible from the network
Step 1 — Install Nginx
dnf install -y nginx
The AppStream repository provides the current stable Nginx release. Verify the installed version:
nginx -v
Step 2 — Start and Enable Nginx
# Start Nginx and enable it to start at boot
systemctl enable --now nginx
# Verify it is running
systemctl status nginx
Step 3 — Open Firewall Ports
# Allow HTTP (port 80) and HTTPS (port 443)
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload
# Verify
firewall-cmd --list-services
Step 4 — Verify the Default Page
Open a browser and navigate to your server’s IP address. You should see the RHEL 9 Nginx welcome page. Alternatively, test from the server:
curl -I http://localhost
Step 5 — Understand the Nginx Directory Structure
/etc/nginx/nginx.conf— the main configuration file/etc/nginx/conf.d/— drop-in server block configuration files/usr/share/nginx/html/— default web root/var/log/nginx/access.log— access log/var/log/nginx/error.log— error log
Step 6 — Configure the Main nginx.conf
vi /etc/nginx/nginx.conf
user nginx;
worker_processes auto; # Automatically set to number of CPU cores
error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024; # Max connections per worker
use epoll; # Use efficient epoll event model
multi_accept on;
}
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; # Hide Nginx version in headers
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
}
Step 7 — Create a Server Block for Your Site
# Create the web root
mkdir -p /var/www/example.com/html
# Set correct ownership
chown -R nginx:nginx /var/www/example.com/
# Create a test page
echo 'Welcome to example.com on RHEL 9
' > /var/www/example.com/html/index.html
# Set SELinux context
semanage fcontext -a -t httpd_sys_content_t '/var/www/example.com(/.*)?'
restorecon -Rv /var/www/example.com/
vi /etc/nginx/conf.d/example.com.conf
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example.com/html;
index index.html index.php;
access_log /var/log/nginx/example.com.access.log main;
error_log /var/log/nginx/example.com.error.log warn;
location / {
try_files $uri $uri/ =404;
}
}
# Test configuration syntax
nginx -t
# Reload Nginx to apply changes
systemctl reload nginx
Step 8 — SELinux Considerations
RHEL 9 runs SELinux in enforcing mode by default. Several common Nginx tasks require SELinux booleans or context changes:
# Allow Nginx to connect to upstream backends (for reverse proxy)
setsebool -P httpd_can_network_connect 1
# Allow Nginx to connect to databases
setsebool -P httpd_can_network_connect_db 1
# Allow Nginx to serve files from non-standard directories
semanage fcontext -a -t httpd_sys_content_t '/custom/webroot(/.*)?'
restorecon -Rv /custom/webroot/
# Check what SELinux is blocking (if Nginx fails unexpectedly)
ausearch -c nginx -m avc --start today | audit2allow -a
Step 9 — Manage Nginx with systemd
systemctl start nginx
systemctl stop nginx
systemctl restart nginx # Full restart (brief downtime)
systemctl reload nginx # Graceful reload (zero downtime)
systemctl status nginx
Verification Checklist
# Nginx is running
systemctl is-active nginx
# Ports are open
firewall-cmd --list-services | grep -E 'http|https'
# Configuration is valid
nginx -t
# Test response
curl -si http://localhost | head -5
Conclusion
Nginx is installed and running on your RHEL 9 server with firewall and SELinux configured correctly. The server block in /etc/nginx/conf.d/ is serving your site, and the main configuration has sensible performance defaults including worker_processes auto and server_tokens off.
Next steps: How to Install Apache HTTP Server on RHEL 9, How to Configure Nginx Server Blocks on RHEL 9, and How to Secure Nginx with Let’s Encrypt on RHEL 9.