skip to Main Content

I have this nginx.conf configuration file inherited from a github project and i’d like some people to explain me what is doing what:

upstream hello_django {
    server web:8000;
}

server {
    listen 80;
    server_name react-wagtail-api.accordbox.com;
    location / {
        proxy_pass http://hello_django;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
        client_max_body_size 20M;
    }
    location /static/ {
        alias /app/static/;
    }
    location /media/ {
        alias /app/media/;
    }
}

server {
    listen 80;
    server_name react-wagtail.accordbox.com;
    location / {
      root   /usr/share/nginx/html/build;
      index  index.html index.htm;
      try_files $uri $uri/ /index.html;
    }
}

with

upstream hello_django {
        server web:8000;
    }

is web a service (elswhere there is a docker-compose container name which is web… is it a ref to that? ) ?
What does upstream define exactly?

with

server_name react-wagtail-api.accordbox.com;

what happens if i dont define a server_name for example in case i dont have yet a domain? is server_name the domain typed in the adress bar of the browser? can i define it as the local ip and let my domain name provider do the redirect? can i define it as the internet ip of the server and let my domain name provider do the redirect?

As there are two servers on the same port, can i define for example server_name my_internet_ip/app1 and server_name my_internet_ip/app2 to serve two servers on port 80?

2

Answers


  1. web service in your case resolves to some IP, same with server_name. You can read more about upstreams here, same for server_name directive.

    Login or Signup to reply.
  2. Is web a service (elsewhere there is a docker-compose container name which is web… is it a ref to that?)

    Generally, web here is an upstream domain name (can be also specified via IP address or UNIX socket path). However, when this is executed within the docker-compose context, at the nginx startup time it will be resolved to the web container internal IP using docker internal domain name resolving system.

    What does upstream define exactly?

    For this particular configuration, there will be no difference using either

    upstream hello_django {
        server web:8000;
    }
    server {
        ...
        proxy_pass http://hello_django;
    

    or specifying an upstream address directly in the proxy_pass directive:

    server {
        ...
        proxy_pass http://web:8000;
    

    Really useful upstream use cases include failover (example) or load balancing (example). Read the ngx_http_upstream_module documentation to find out all the available features.

    What happens if i don’t define a server_name for example in case i don’t have yet a domain?

    To understand this part make sure you read the following two chapters from the official documentation:

    You can omit the server_name directive from the server block at all. For any HTTP request arriving at the TCP port where nginx is listening, one of the defined server blocks (usually the very first one appearing in the configuration, unless being specified explicitly using default_server parameter of listen directive) will act as the default server if more appropriate server block won’t be found. The Host HTTP request header value is used to choose the most suitable server block here, being compared with the specified server_name for the server block, and it will be exactly what you typed at the browser address bar (assuming IP address/domain name being typed will actually point to the nginx server). That means there is no sense to specify the same server name for different server blocks listening on the same TCP ports – the first one will always be chosen to process such a request, and the nginx will complain with the

    nginx: [warn] conflicting server name "..." on 0.0.0.0:80, ignored
    

    warning message. For the developing purposes you can add the required domain names to the hosts system file, pointing them to your local machine, e.g.

    127.0.0.1  react-wagtail.accordbox.com
    127.0.0.1  react-wagtail-api.accordbox.com
    

    This way you will be able to use those domains from your local browser, the generated HTTP requests will contain the proper Host header and will be processed with your local nginx server instance.

    As there are two servers on the same port, can i define for example server_name my_internet_ip/app1 and server_name my_internet_ip/app2 to serve two servers on port 80?

    No. Looks like you don’t understand the internals of HTTP protocol. At the low level HTTP request will be something like

    GET /app1 HTTP/1.1
    Host: my_internet_ip
    ...
    

    As you can see the host name and the request URL path are two completely different things. Usually this kind of tasks being solved using several location blocks:

    server {
        server_name example.com;
        location /app1/ {
            ...
        }
        location /app2/ {
            ...
        }
    }
    

    However it will require support from the underlying web apps. Two available options are

    • Referring assets using relative URIs, e.g.

      <link rel="stylesheet" type="text/css" href="style.css">
      

      or

      <link rel="stylesheet" type="text/css" href="./style.css">
      

      but not the using absolute URIs like

      <link rel="stylesheet" type="text/css" href="/style.css">
      
    • Using the same URI prefix as specified in the location directive, e.g.

      <link rel="stylesheet" type="text/css" href="/app1/style.css">
      

    The reason should be obvious – every request for any first or second app assets should start with the /app1/ or /app2/ prefix for being handled with the proper location block.

    As you can see, I’m using /app1/ and /app2/ suffixes here rather than /app1 and /app2. This is a very common mistake made by many people, to not understand the difference between those two. While it may seems to be an insignificant, in fact those two are drastically different in terms of browsing context which will be / in first case and /app1/ or /app2/ in second case. Unless you are proxying some kind of API endpoint but a whole web application, you probably want the second one. To make it more easy, a location directive special behavior provided by nginx:

    If a location is defined by a prefix string that ends with the slash character, and requests are processed by one of proxy_pass, fastcgi_pass, uwsgi_pass, scgi_pass, memcached_pass, or grpc_pass, then the special processing is performed. In response to a request with URI equal to this string, but without the trailing slash, a permanent redirect with the code 301 will be returned to the requested URI with the slash appended. If this is not desired, an exact match of the URI and location could be defined like this:

    location /user/ {
        proxy_pass http://user.example.com;
    }
    
    location = /user {
        proxy_pass http://login.example.com;
    }
    

    Although we can override the browsing context using the <base href="..."> HTML tag, I strongly recommend to not use this workaround and use a proper URI prefixes for your proxied web apps instead.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search