Fix Common nginx [emerg] Errors in a Django Config

Fix nginx [emerg] errors that stop Nginx from starting or reloading for a Django site: unknown directive, directive is not allowed here, host not found in upstream, cannot load certificate, and unexpected end of file.

Problem statement

You edited the site config, reloaded, and Nginx refused:

nginx: [emerg] unknown directive "proxy_pas" in /etc/nginx/sites-enabled/django:14
nginx: configuration file /etc/nginx/nginx.conf test failed

An [emerg] message is fatal. On reload, Nginx keeps running with the old configuration, so the site stays up but your change is not applied. On restart or after a reboot, Nginx does not start at all and every request fails. The message always includes a file and line number, and the handful of errors below cover nearly every case in a Django setup.

What an emerg error doesYou edit configsite file changesnginx -t failsemerg with line no.Reloadold config keptRestartNginx downAlways run nginx -t before reload; a failed restart takes the whole site down.
  1. Run sudo nginx -t and read the file and line number in the message.
  2. unknown directive is a typo or a module that is not installed.
  3. directive is not allowed here means it is in the wrong block (http, server, or location).
  4. host not found in upstream means a hostname in proxy_pass or upstream cannot be resolved at startup.
  5. cannot load certificate means a wrong path or missing file, often after Certbot changes.
  6. unexpected end of file or unexpected "}" means unbalanced braces or a missing semicolon.

Step-by-step solution

1. Always test before reloading

sudo nginx -t && sudo systemctl reload nginx

Chaining with && means the reload only runs on a passing test. To see the full merged config with file names, use sudo nginx -T.

2. unknown directive

[emerg] unknown directive "proxy_pas" in /etc/nginx/sites-enabled/django:14
[emerg] unknown directive "brotli" in /etc/nginx/nginx.conf:30

The first is a typo. The second is a directive from a module your Nginx build does not include. Install the module package (for Brotli on Debian or Ubuntu, libnginx-mod-http-brotli-filter and -static where available) or remove the directive. Invisible characters copied from web pages, such as non-breaking spaces, also produce this error; retype the line.

3. directive is not allowed here

[emerg] "proxy_pass" directive is not allowed here in /etc/nginx/sites-enabled/django:9
[emerg] "server" directive is not allowed here in /etc/nginx/conf.d/django.conf:1

Every directive has allowed contexts. proxy_pass belongs in location; server blocks belong in http, which is where files in conf.d and sites-enabled are included. The second error typically means a site file was included from the wrong place, or a full nginx.conf (with its own http {}) was dropped into conf.d.

each directive lives in a specific blockmain (nginx.conf top)user, worker_processes, eventshttpgzip, upstream, include sites,serverserverlisten, server_name,ssl_certificatelocationproxy_pass, alias, try_filesDirective is not allowed here means it is one layer too high or too lowdjango-deployment.com
Site files are included inside http, so they contain server blocks and nothing above them.

4. host not found in upstream

[emerg] host not found in upstream "web:8000" in /etc/nginx/conf.d/django.conf:3

Nginx resolves hostnames in proxy_pass and upstream once, at startup. If the name does not resolve then, Nginx will not start. Common cases:

  • Docker Compose: the Nginx container starts before the web service exists on the network, or they are on different networks. Put them on the same network and add depends_on: [web].
  • A typo or a decommissioned host.
  • Kubernetes Service names used outside the cluster.

To let Nginx start and resolve later, use a variable with a resolver (Docker's embedded DNS is 127.0.0.11):

resolver 127.0.0.11 valid=10s;
location / {
    set $django http://web:8000;
    proxy_pass $django;
}

5. cannot load certificate

[emerg] cannot load certificate "/etc/letsencrypt/live/example.com/fullchain.pem":
BIO_new_file() failed (SSL: error:80000002:system library::No such file or directory)

The path is wrong or the certificate was never issued. Check with sudo ls -l /etc/letsencrypt/live/ and sudo certbot certificates. If Certbot created example.com-0001 after a reissue, the config still points at the old directory. Point it at the directory Certbot lists, or consolidate certificates with certbot --cert-name.

6. Unbalanced braces and missing semicolons

[emerg] unexpected end of file, expecting "}" in /etc/nginx/sites-enabled/django:42
[emerg] unexpected "}" in /etc/nginx/sites-enabled/django:30
[emerg] invalid number of arguments in "proxy_set_header" directive

Each { needs a }, and every simple directive ends with ;. A missing semicolon often surfaces as "invalid number of arguments" on the next line, because Nginx reads both lines as one directive.

message to fix[emerg] messageUsual fixunknown directivetypo, invisible character,or module not installeddirective is not allowed heremove it to http, server, or locationhost not found in upstreamname not resolvable atstartup; network or resolvercannot load certificatewrong live/ directory;check certbot certificatesunexpected end of file or }unbalanced braces ora missing semicolonThe file and line number in the message point at, or just after, the mistakedjango-deployment.com
Fix the first error reported; later ones are often side effects of it.

Verification check: sudo nginx -t prints syntax is ok and test is successful, sudo systemctl reload nginx exits cleanly, and curl -I https://example.com returns a response from Django.

Explanation

Nginx parses its whole configuration tree before applying any of it. A reload starts new worker processes with the new configuration only if parsing succeeds; otherwise the master keeps the old workers. That makes reload safe and restart dangerous, because a restart stops the running server before discovering that the new configuration cannot load. Running nginx -t in deploy scripts and configuration management catches errors before they ever reach a running server.

Edge cases / notes

  • Permissions. [emerg] open() "/etc/nginx/sites-enabled/django" failed (13: Permission denied) or failing to open log files means file permissions or SELinux contexts; see the Rocky Linux SELinux guide for the latter.
  • Port already in use. bind() to 0.0.0.0:80 failed (98: Address already in use) is also [emerg] and has its own fix.
  • Config management. Have Ansible or your deploy script validate with nginx -t -c against the new file before moving it into place.
  • Docker images run nginx -g 'daemon off;'; an [emerg] makes the container exit immediately. Check docker logs nginx.

Next steps

FAQ

Does a failed reload take my site down?

No. Nginx keeps the old configuration. A failed restart or boot does take it down.

Why does the error point at the wrong line?

A missing semicolon or brace is often reported on the following line, where parsing finally fails.

How do I see the full configuration Nginx loads?

Run sudo nginx -T. It prints every included file with its path.

Why does Nginx in Docker fail with host not found?

The upstream container name was not resolvable when Nginx started. Use a shared network, depends_on, or a resolver with a variable.

Keep going