Nginx Upstream Configuration: Why HTTP Prefixes Cause “Invalid Host” Error


2 views

When configuring Nginx upstream servers, many developers (myself included) instinctively include the http:// protocol prefix in the server definitions. This seems logical since we're dealing with HTTP services, but Nginx actually treats this as a configuration error.

# This will FAIL
upstream api_servers {
  server http://192.168.49.4:49155;
  server http://192.168.49.4:49156;
}

The proper way to define upstream servers is to simply use the IP:port combination without any protocol specification:

# Correct configuration
upstream api_servers {
  server 192.168.49.4:49155;
  server 192.168.49.4:49156;
}

Nginx upstream modules are designed to handle various types of backends, not just HTTP. The upstream directive is protocol-agnostic - it's the proxy_pass directive that determines the protocol being used. When you specify http:// in the upstream definition, Nginx interprets this as part of the hostname, which violates its syntax rules.

Here's a complete working configuration for proxying to Docker containers:

upstream docker_backends {
  server 192.168.49.4:49155;
  server 192.168.49.4:49156;
}

server {
  listen 80;
  server_name api.example.com;
  
  location / {
    proxy_pass http://docker_backends;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
  }
}

You can enhance your upstream configuration with additional parameters:

upstream load_balanced_servers {
  server 192.168.49.4:49155 weight=3;
  server 192.168.49.4:49156;
  keepalive 32;
}

This configuration gives the first server more weight in load balancing and maintains persistent connections.

If you're still encountering issues:

  • Always test your configuration with nginx -t
  • Check that your Docker containers are properly exposed on the specified ports
  • Verify network connectivity between Nginx and your containers
  • Examine Nginx error logs (/var/log/nginx/error.log) for detailed messages

When configuring Nginx as a reverse proxy for Docker containers, many developers (including myself) instinctively include http:// prefixes in upstream server definitions. However, this leads to configuration errors:

upstream api_servers {
  server http://192.168.49.4:49155;  # This will fail
  server http://192.168.49.4:49156;  # This will fail
}

Nginx responds with:

nginx: [emerg] invalid host in upstream "http://192.168.49.4:49155"

The upstream directive in Nginx has specific syntax requirements:

  • Server addresses should be specified as host:port or IP:port
  • Protocol prefixes (http://, https://) are not supported in upstream blocks
  • Nginx automatically uses HTTP protocol for upstream connections

The working version simply removes the protocol prefix:

upstream api_servers {
  server 192.168.49.4:49155;
  server 192.168.49.4:49156;
}

Here are some common variations:

# With load balancing
upstream backend {
  server 10.0.0.1:8080 weight=5;
  server 10.0.0.2:8080;
  server unix:/tmp/backend.sock;
}

# With failover settings
upstream resilient_backend {
  server primary.example.com:80 max_fails=3 fail_timeout=30s;
  server backup.example.com:80 backup;
}

For HTTPS upstreams, configure SSL separately:

upstream secure_backend {
  server secure.example.com:443;
}

server {
  location / {
    proxy_pass https://secure_backend;
    proxy_ssl_verify on;
    proxy_ssl_name $proxy_host;
  }
}

When encountering upstream issues:

  1. Always test configuration with nginx -t
  2. Check error logs (/var/log/nginx/error.log)
  3. Use curl -v to test direct connections to upstream servers
  4. Verify network connectivity between Nginx and upstream