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 availability — nginx -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