Nginx is a high-performance web server that also excels as a reverse proxy, sitting in front of application servers and forwarding client requests to backend services running on internal ports. Using Nginx as a reverse proxy on RHEL 8 allows you to serve Node.js, Python, Java, or any HTTP-based application behind a clean public-facing endpoint while benefiting from Nginx’s connection handling, SSL termination, and buffering capabilities. This tutorial covers installing Nginx, configuring a reverse proxy with proper headers, enabling SELinux permissions, and tuning upstream backends.

Prerequisites

  • A RHEL 8 server with sudo access
  • Nginx installed and enabled (dnf install nginx)
  • A backend application listening on a local port (e.g., 127.0.0.1:3000)
  • Port 80 (and optionally 443) open in firewalld
  • SELinux in enforcing mode (default on RHEL 8)

Step 1 — Install Nginx and Configure the Firewall

Install Nginx from the AppStream repository and open the necessary firewall ports.

sudo dnf install -y nginx
sudo systemctl enable --now nginx
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

Step 2 — Configure the Reverse Proxy location Block

Create a dedicated server block configuration file for your site. The location / block uses proxy_pass to forward all requests to your backend application. The proxy_set_header directives pass important client information to the upstream service.

sudo nano /etc/nginx/conf.d/myapp.conf

Add the following configuration:

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

    location / {
        proxy_pass         http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header   Host              $host;
        proxy_set_header   X-Real-IP         $remote_addr;
        proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
        proxy_set_header   Upgrade           $http_upgrade;
        proxy_set_header   Connection        "upgrade";
        proxy_buffering    on;
        proxy_buffer_size  16k;
        proxy_buffers      8 16k;
    }
}

Test the configuration syntax and reload Nginx:

sudo nginx -t
sudo systemctl reload nginx

Step 3 — Configure an Upstream Block for Multiple Backends

If your application runs on multiple backend instances, define an upstream block to group them. Nginx will distribute requests across the listed servers using round-robin by default.

upstream myapp_backend {
    server 127.0.0.1:3000;
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;
    keepalive 32;
}

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass       http://myapp_backend;
        proxy_set_header Host            $host;
        proxy_set_header X-Real-IP       $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

The keepalive 32 directive maintains a pool of persistent connections to the upstream servers, reducing connection overhead for high-traffic applications.

Step 4 — Allow Network Connections with SELinux

On RHEL 8, SELinux is enforcing by default and will block Nginx from making outbound connections to backend services unless you explicitly permit it. Without this step, you will see 502 Bad Gateway errors even though the configuration is syntactically correct.

sudo setsebool -P httpd_can_network_connect 1
getsebool httpd_can_network_connect

The -P flag makes the change persistent across reboots. Verify the boolean is set to on.

Step 5 — Configure Proxy Timeout Settings

For applications with long-running requests, increase the default proxy timeouts to prevent Nginx from closing connections prematurely and returning 504 Gateway Timeout errors to clients.

    proxy_connect_timeout  60s;
    proxy_send_timeout     120s;
    proxy_read_timeout     120s;
    send_timeout           120s;

Add these directives inside the location / block or in the http context of /etc/nginx/nginx.conf to apply them globally. After editing, always validate and reload:

sudo nginx -t && sudo systemctl reload nginx

Step 6 — Test the Reverse Proxy

Confirm that requests are being forwarded correctly to your backend by sending a request with curl and inspecting the response headers.

curl -I http://example.com
curl -v http://example.com 2>&1 | head -40

The response should come from your backend application. If your backend sets a custom header (such as X-Powered-By), it will appear in the curl output, confirming that the proxying is working end-to-end.

Conclusion

Nginx is now configured as a reverse proxy on your RHEL 8 server, forwarding requests to a backend application while handling the SELinux policy requirements that are unique to this enterprise Linux distribution. The upstream block gives you flexibility to scale to multiple backend instances, and the proxy header directives ensure your application receives accurate client information. With buffering and timeout tuning in place, the proxy layer is ready for production traffic.

Next steps: How to Secure Nginx with Let’s Encrypt on RHEL 8, How to Configure Nginx Load Balancing on RHEL 8, and How to Enable HTTP/2 with Nginx on RHEL 8.