Filters
How to search
  • Plain words find names, texts and examples.
  • "two words" finds the exact phrase.
  • --name or -x finds an option.
  • #word looks only inside commands.
  • @grep finds lessons and labs that use grep.
  • Filters: cat:network · in:labs · in:notes · level:rhcsa · ch:8 · root:yes. Put ! before a word to leave it out. OR between words means one of them.
  • ↑ ↓ to move · Enter to open · Esc to close · / to search

nginx

A fast web server, reverse proxy, load balancer and TLS terminator — the most used front door for web apps and APIs.

Level
DevSecOps service
Group
Web
Needs root
Yes
Package
nginx

What it does

nginx serves static files and passes requests to app servers (PHP-FPM, Python, Node, containers). It ends TLS (HTTPS), balances load over several backends, caches, limits request rates and adds security headers. On RHEL the service is nginx.service; it listens on ports 80 and 443.

The main config is /etc/nginx/nginx.conf; sites go in /etc/nginx/conf.d/*.conf. Always test the config with nginx -t before a reload. With SELinux, nginx may only use labelled ports and file contexts (httpd_sys_content_t, http_port_t) and needs httpd_can_network_connect to proxy to apps.

How to write it

nginx [-t] [-T] [-s signal] [-c file] [-g directives]
systemctl {start|reload|status} nginx

Main parts

Config blocks

http { … }
Settings for all web traffic.
server { … }
One virtual host (listen port, server_name, TLS).
location PATH { … }
Rules for some URLs (root, proxy_pass, headers).
upstream NAME { … }
A group of backend servers for load balancing.
stream { … }
TCP/UDP proxying (databases, other protocols).

Options 10

Most used

Command-line options

-t
Test the configuration and exit.
-T
Test and print the whole configuration (all included files).
-s SIGNAL
Send a signal to the master process: reload, reopen, stop, quit.
-c FILE
Use another configuration file.
-g DIRECTIVES
Set global directives on the command line.
-p PREFIX
Set the prefix path.
-e FILE
Use another error log file (stderr possible).
-q
Show only errors during the config test.
-v / -V
Show the version / the version and build options (modules).
-h, -?
Show help.

Examples 11

$ run as a normal user# run as root (or with sudo)

  1. 1Install, open the firewall and start

    dnf install -y nginx
    firewall-cmd --add-service={http,https} --permanent && firewall-cmd --reload
    systemctl enable --now nginx
    curl -I http://localhost/
  2. 2Test and reload after a change

    nginx -t
    nginx: configuration file /etc/nginx/nginx.conf test is successful
    systemctl reload nginx

    reload keeps open connections; a broken config is refused, the old one keeps running.

  3. 3Serve a static site

    cat /etc/nginx/conf.d/site.conf
    server {
        listen 80;
        server_name www.example.com;
        root /srv/www/site;
        index index.html;
    }
    semanage fcontext -a -t httpd_sys_content_t '/srv/www(/.*)?' && restorecon -Rv /srv/www
  4. 4Reverse proxy to an app on port 8080

    cat /etc/nginx/conf.d/app.conf
    server {
        listen 80;
        server_name app.example.com;
        location / {
            proxy_pass http://127.0.0.1:8080;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
    setsebool -P httpd_can_network_connect on
  5. 5HTTPS with a certificate and HTTP redirect

    cat /etc/nginx/conf.d/tls.conf
    server { listen 80; server_name shop.example.com; return 301 https://$host$request_uri; }
    server {
        listen 443 ssl;
        http2 on;
        server_name shop.example.com;
        ssl_certificate     /etc/pki/tls/certs/shop.crt;
        ssl_certificate_key /etc/pki/tls/private/shop.key;
        ssl_protocols TLSv1.2 TLSv1.3;
        add_header Strict-Transport-Security "max-age=31536000" always;
    }
  6. 6Load-balance three app servers

    cat /etc/nginx/conf.d/lb.conf
    upstream app { least_conn; server 10.30.2.11:8080; server 10.30.2.12:8080; server 10.30.2.13:8080 max_fails=3 fail_timeout=30s; }
    server { listen 80; location / { proxy_pass http://app; } }
  7. 7Limit request rates (brute force, scrapers)

    cat /etc/nginx/conf.d/limits.conf
    limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
    server { location /login { limit_req zone=login burst=5 nodelay; proxy_pass http://127.0.0.1:8080; } }
  8. 8Add security headers and hide the version

    cat /etc/nginx/conf.d/security.conf
    server_tokens off;
    add_header X-Content-Type-Options nosniff always;
    add_header X-Frame-Options DENY always;
    add_header Referrer-Policy strict-origin-when-cross-origin always;
  9. 9Read the logs

    tail -f /var/log/nginx/access.log /var/log/nginx/error.log
    awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
    journalctl -u nginx -n 30
  10. 10Show the full active configuration

    nginx -T | grep -E "server_name|listen|proxy_pass"
  11. 11Run nginx in a container

    podman run -d --name web -p 8080:8080 -v ./site:/usr/share/nginx/html:ro,Z docker.io/nginxinc/nginx-unprivileged:1.27

Watch out

  • nginx -t before every reload — a typo with restart takes the site down.
  • With SELinux: non-standard ports need semanage port -a -t http_port_t; proxying to apps needs httpd_can_network_connect.
  • Do not expose autoindex on or .git/.env files: location ~ /\. { deny all; }.

Files

/etc/nginx/nginx.conf
Main configuration.
/etc/nginx/conf.d/*.conf
Sites and extra settings.
/var/log/nginx/
access.log and error.log.
/usr/share/nginx/html
Default web root.

Tips to remember

  • Test TLS with curl -vI https://HOST and SSL Labs; aim for TLS 1.2+ only.
  • Put shared proxy headers in a snippet file and include it in every location.

Exit codes

0Success (config OK).
1Error (config test failed, signal not sent).