2026-03-30 · NginxDevOpsLinuxReverse Proxy

How to Test Your Nginx Config Before Reloading (nginx -t and Beyond)

nginx -t checks syntax. It does not check whether your upstreams are alive, your SSL certs are valid, or your config actually does what you intended. Here is the full testing workflow — and what to do after the test passes.

Every Nginx change carries the same risk: you edit the config, reload, and find out you broke something only after traffic starts hitting errors. nginx -t exists to catch this before it happens — but most people don't know everything it does and doesn't catch.

The basics: nginx -t

sudo nginx -t

This validates your entire Nginx configuration — all included files, all server blocks, all upstream definitions. If the syntax is clean you see:

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

If there's an error:

nginx: [emerg] unknown directive "servr_name" in /etc/nginx/sites-enabled/mysite:3
nginx: configuration file /etc/nginx/nginx.conf test failed

The error tells you the exact file and line number. Fix it there, run nginx -t again before reloading.

Always pair nginx -t with the reload

# The safe pattern — test then reload:
sudo nginx -t && sudo systemctl reload nginx

# The unsafe pattern — skip the test:
sudo systemctl reload nginx

The && means the reload only runs if the test passes. If nginx -t fails, the reload never executes and your running Nginx stays untouched. Make this muscle memory.

reload vs restart: Use systemctl reload nginx not restart. Reload applies the new config without dropping existing connections. Restart kills Nginx and starts it fresh — briefly interrupts active connections.

What nginx -t catches

Syntax errors — missing semicolons, typos in directive names, unclosed blocks. It catches these reliably.

Include file errors — if a file referenced with include doesn't exist or has a syntax error, nginx -t catches it.

Invalid directive values — wrong argument types, out-of-range values, incompatible directive combinations.

What nginx -t does NOT catch

This is the part people get burned by:

Upstream availabilitynginx -t does not check whether upstream servers are reachable. A proxy_pass http://127.0.0.1:3000 pointing to a stopped container passes the test fine. You only find out it's broken when requests start returning 502.

SSL certificate validity — it checks that the certificate file exists and is readable, but not whether the certificate is expired, matches the domain, or has a valid chain.

DNS resolution — upstream hostnames in proxy_pass are not resolved at test time.

Logic errors — a valid but wrong configuration passes the test. Wrong proxy_pass port, missing security headers, incorrect redirect chains — all pass nginx -t perfectly.

Test a specific config file

# Test a specific config file instead of the default:
sudo nginx -t -c /path/to/nginx.conf

# Useful when testing a new config before moving it into place:
sudo nginx -t -c /tmp/new-nginx.conf

Check which config files are loaded

# See the full config with all includes expanded:
sudo nginx -T

# Pipe to grep to find specific settings:
sudo nginx -T | grep -i "server_name|listen|proxy_pass"

# Check what's included:
sudo nginx -T | grep "# configuration file"

nginx -T (capital T) dumps the entire effective configuration — every include file expanded inline. Useful for auditing what Nginx is actually running versus what you think it's running.

Debug mode for more detail

# Run nginx in debug mode to see config parsing:
sudo nginx -t -e /dev/stderr 2>&1 | head -50

Validate before and after every change

The workflow that prevents every "I just broke prod" incident:

# 1. Make your change
nano /etc/nginx/sites-available/mysite

# 2. Test before touching anything live
sudo nginx -t

# 3. Only reload if test passes
sudo nginx -t && sudo systemctl reload nginx

# 4. Verify the change took effect
curl -sI https://yourdomain.com | grep -E "Server|X-Frame|Strict"

Reload vs restart — when to use each

# Use reload for config changes (zero downtime):
sudo systemctl reload nginx

# Use restart only when:
# - Adding new modules
# - Changing worker_processes
# - SSL certificate replacement (some versions)
sudo systemctl restart nginx

Check Nginx error logs after reload

Even after a successful reload, check the error log for runtime issues that the config test couldn't catch:

# Watch the error log in real time after reload:
sudo tail -f /var/log/nginx/error.log

# Check for upstream errors in the last 100 lines:
sudo tail -100 /var/log/nginx/error.log | grep -E "upstream|connect|refused"

Audit your full config for common issues

Beyond syntax validation, there are configuration issues nginx -t will never catch — dangling proxy_pass targets, missing SSL redirects, duplicate CORS headers, deprecated Traefik labels. These require a semantic audit, not just a syntax check.

Paste your nginx.conf to detect dangling routes, missing SSL redirects, and CORS header issues — the things nginx -t can't catch.

Open Reverse Proxy Mapper →

Quick reference

# Test config syntax:
sudo nginx -t

# Test then reload (safe pattern):
sudo nginx -t && sudo systemctl reload nginx

# Dump full effective config:
sudo nginx -T

# Test specific config file:
sudo nginx -t -c /path/to/nginx.conf

# Check error log after reload:
sudo tail -50 /var/log/nginx/error.log

Related guides