You made a quick change to your Nginx configuration, ran nginx -t to test it, and got an error. The message isn't always clear about what's wrong, and you're not sure if it's a syntax error, missing semicolon, or something else entirely. Let's systematically debug Nginx configuration errors.
Understanding nginx -t Output
When configuration has errors, nginx -t shows:
nginx: [emerg] unknown directive "server_name" in /etc/nginx/sites-enabled/example.com:12
nginx: configuration file /etc/nginx/nginx.conf test failedOr sometimes:
nginx: [emerg] unexpected "}" in /etc/nginx/sites-enabled/example.com:25
nginx: configuration file /etc/nginx/nginx.conf test failedThe severity levels are: - emerg - Fatal error, Nginx won't start - alert - Serious issue, needs fixing - crit - Critical, will cause problems - error - Error condition - warn - Warning, might work but should fix
Step 1: Get Detailed Error Location
The error message tells you the file and line number. Let's get more context:
```bash # Basic test nginx -t
# More verbose output nginx -T 2>&1 | less
# Show line numbers in config cat -n /etc/nginx/sites-enabled/example.com | sed -n '10,30p' ```
If the error mentions line 25, view lines around it:
sed -n '20,30p' /etc/nginx/sites-enabled/example.comStep 2: Fix Missing Semicolons
The most common error. Nginx requires semicolons after every directive:
Error:
``
nginx: [emerg] unexpected "}" in /etc/nginx/sites-enabled/example.com:10
Broken config:
``nginx
server {
listen 80
server_name example.com # Missing semicolon!
}
Fixed:
``nginx
server {
listen 80;
server_name example.com;
}
The error points to the line after the missing semicolon. Check the preceding lines.
Step 3: Fix Unknown Directive Errors
Error:
``
nginx: [emerg] unknown directive "server_name" in /etc/nginx/sites-enabled/example.com:5
This usually means the directive is in the wrong context:
Broken config: ```nginx http { server_name example.com; # Wrong! server_name must be in server block
server { listen 80; } } ```
Fixed:
``nginx
http {
server {
listen 80;
server_name example.com;
}
}
Check directive context in documentation: ```bash # Check if module is loaded nginx -V 2>&1 | grep -o "with-[^ ]*" | tr ' ' '\n'
# Or check loaded modules ls /etc/nginx/modules-enabled/ ```
Step 4: Fix Brace Mismatch
Unmatched braces cause confusing errors:
Error:
``
nginx: [emerg] unexpected end of file, expecting "}" in /etc/nginx/nginx.conf:85
Or:
``
nginx: [emerg] unexpected "}" in /etc/nginx/sites-enabled/example.com:25
Debug technique: ```bash # Count opening and closing braces grep -o '{' /etc/nginx/nginx.conf | wc -l grep -o '}' /etc/nginx/nginx.conf | wc -l
# They should be equal ```
Visual debugging with indentation: ```bash # Indent config to see structure apt-get install indent # Debian/Ubuntu # or yum install indent # RHEL/CentOS
indent -linux -i4 /etc/nginx/sites-enabled/example.com ```
Manual check:
``nginx
http {
server {
location / {
# content
} # closes location
} # closes server
} # closes http
Step 5: Fix Include Errors
Error:
``
nginx: [emerg] open() "/etc/nginx/sites-enabled/missing-file.conf" failed (2: No such file or directory)
Check includes:
```bash # Find all include statements grep -r "include" /etc/nginx/nginx.conf
# Check if files exist ls -la /etc/nginx/sites-enabled/ ls -la /etc/nginx/conf.d/ ```
Fix by either: - Creating the missing file - Removing the include statement - Commenting out the include
Step 6: Fix Port Binding Issues
Error:
``
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
Check what's using the port:
# Find process on port 80
ss -tlnp | grep :80
netstat -tlnp | grep :80
lsof -i :80If another process is using the port:
```bash # Identify the process ps aux | grep $(lsof -t -i:80)
# Stop the conflicting service systemctl stop apache2 # if Apache is running # or systemctl stop httpd ```
If Nginx itself has a duplicate:
```bash # Check all listen directives grep -r "listen 80" /etc/nginx/
# Check for default server conflicts grep -r "default_server" /etc/nginx/ ```
Only one default_server per port is allowed.
Step 7: Fix SSL Certificate Errors
Error:
``
nginx: [emerg] cannot load certificate "/etc/nginx/ssl/missing.crt": BIO_new_file() failed (SSL: error:02001002:system library:fopen:No such file or directory)
Or:
``
nginx: [emerg] SSL_CTX_load_verify_locations("/etc/nginx/ssl/cert.crt") failed (SSL: error:02001002:system library:fopen:No such file or directory)
Check certificate files:
```bash # Check files exist ls -la /etc/nginx/ssl/
# Check paths in config grep -r "ssl_certificate" /etc/nginx/
# Verify certificates openssl x509 -in /etc/nginx/ssl/example.com.crt -text -noout ```
Common mistakes:
```nginx # Wrong: relative path ssl_certificate ssl/example.com.crt;
# Correct: absolute path ssl_certificate /etc/nginx/ssl/example.com.crt;
# Wrong: swapped cert and key ssl_certificate /etc/nginx/ssl/example.com.key; ssl_certificate_key /etc/nginx/ssl/example.com.crt;
# Correct ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; ```
Step 8: Fix Upstream Errors
Error:
``
nginx: [emerg] host not found in upstream "backend" in /etc/nginx/conf.d/upstream.conf:5
Broken config:
``nginx
upstream backend {
server backend-server:3000; # DNS can't resolve at startup
}
Solutions:
- 1.Use IP address:
- 2.```nginx
- 3.upstream backend {
- 4.server 192.168.1.100:3000;
- 5.}
- 6.
` - 7.Use a resolver for dynamic DNS:
- 8.```nginx
- 9.resolver 8.8.8.8;
location / { set $upstream http://backend-server:3000; proxy_pass $upstream; } ```
- 1.Ensure hosts file or DNS is configured:
- 2.```bash
- 3.# Check resolution
- 4.getent hosts backend-server
- 5.ping backend-server
- 6.
`
Step 9: Fix Variable and Map Errors
Error:
``
nginx: [emerg] unknown variable "$upstream_addr" in /etc/nginx/nginx.conf:45
Check if variable exists in the correct context:
# Some variables only exist in certain contexts
log_format main '$remote_addr - $upstream_addr'; # $upstream_addr only exists after proxy_passMap directive errors:
``nginx
# Broken: missing default
map $uri $myvar {
/api backend1;
/web backend2;
# missing default
}
Fixed:
``nginx
map $uri $myvar {
default backend_default;
/api backend1;
/web backend2;
}
Step 10: Debug Complex Configurations
For complex configs with many includes:
```bash # Dump complete parsed configuration nginx -T 2>&1 | less
# Find the actual problematic line nginx -T 2>&1 | grep -A 5 -B 5 "problem_text"
# Check configuration hierarchy find /etc/nginx -name "*.conf" -exec echo "=== {} ===" \; -exec cat {} \; ```
Validate step by step:
```bash # Test only main config nginx -t -c /etc/nginx/nginx.conf
# Temporarily disable all includes mkdir /etc/nginx/sites-disabled mv /etc/nginx/sites-enabled/* /etc/nginx/sites-disabled/ nginx -t
# Add back one by one mv /etc/nginx/sites-disabled/default /etc/nginx/sites-enabled/ nginx -t # Repeat until you find the bad file ```
Common Error Patterns Quick Reference
| Error Message | Likely Cause | Fix |
|---|---|---|
unexpected "}" | Missing semicolon above | Add semicolon |
unexpected end of file | Missing closing brace | Count braces, add missing |
unknown directive | Wrong context or missing module | Move to correct block or install module |
directive is not allowed | Wrong nesting level | Check directive documentation |
bind() failed | Port in use | Stop conflicting service or change port |
no such file or directory | Missing include or SSL file | Create file or fix path |
host not found in upstream | DNS resolution failure | Use IP or fix DNS |
permission denied | Config file permissions | chmod 644 and chown root:root |
Verification Process
After fixing:
```bash # 1. Test syntax nginx -t
# 2. Show parsed config (verify changes) nginx -T | less
# 3. Reload if test passes nginx -t && systemctl reload nginx
# 4. Check status systemctl status nginx
# 5. Verify listening ss -tlnp | grep nginx ```
Prevent Configuration Errors
Create a pre-commit hook:
#!/bin/bash
# .git/hooks/pre-commit
nginx -t
if [ $? -ne 0 ]; then
echo "Nginx configuration test failed. Commit aborted."
exit 1
fiOr use a CI check:
# .github/workflows/nginx-lint.yml
name: Nginx Lint
on: [push]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Nginx
run: sudo apt-get install nginx
- name: Copy configs
run: sudo cp -r nginx/* /etc/nginx/
- name: Test config
run: sudo nginx -tConfiguration errors are almost always syntax mistakes—missing semicolons, mismatched braces, or wrong contexts. When in doubt, strip the config down to basics and add pieces back one at a time.