0

Update

The details in this question are getting long, but I think it narrows down to this:

For some reason the host name matters to Nginx when it's trying to figure out whether to proxy the request. If the host name is set to git.example.com the request does not seem to go through, but if it's set to 203.0.113.2 then it goes through. Why does the host name matter?

Filed an issue with Nginx here And docker compose

Start of original question

When I type in the IP address of the reverse proxy directly into my browser bar, it does perform the redirect.

When using a URL that is resolved via the /etc/hosts entry 203.0.113.2 git.example.com the "Welcome to Ngnix page" is shown. Any ideas? This is the configuration:

server {
    listen 203.0.113.2:80 default_server;
    server_name 203.0.113.2 git.example.com;

    proxy_set_header X-Real-IP  $remote_addr; # pass on real client IP

    location / {
        proxy_pass http://203.0.113.1:3000;
    }
}

This is the docker-compose.yml file that is used to launch the whole thing:

version: '3'
services:
  gogs-nginx:
    build: ./proxy
    ports:
      - "80:80"
    networks:
      mk1net:
        ipv4_address: 203.0.113.2
  gogs:
    image: gogs/gogs
    ports:
      - "3000:3000"
    volumes: 
      - gogs-data:/data
    networks: 
      mk1net:
        ipv4_address: 203.0.113.3
volumes:
  gogs-data:
    external: true
networks:
  mk1net:
    ipam:
      config:
        - subnet: 203.0.113.0/24

One interesting thing is that I can navigate to for example:

http://203.0.113.2/issues

The log for the above URL is:

gogs-nginx_1 | 203.0.113.1 - - [07/Oct/2018:11:28:06 +0000] "GET / HTTP/1.1" 200 38825 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36" "-"

If I then change 203.0.113.2 with git.example.com (So that the url ends up being git.example.com I get Nginxs "404 not found" page, and the log says:

gogs-nginx_1 | 2018/10/07 11:31:34 [error] 8#8: *10 open() "/usr/share/nginx/html/issues" failed (2: No such file or directory), client: 203.0.113.1, server: localhost, request: "GET /issues HTTP/1.1", host: "git.example.com"

If I only use http://git.example.com as the URL I get the NGINX welcome page, and the following log:

gogs-nginx_1 | 203.0.113.1 - - [07/Oct/2018:11:34:39 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36" "-"

It looks like Nginx understands that the request is for the proxy because it logs the IP of the proxy, but it does not redirect to the proxy and returns a 304 ...

Using Curl to perform requests

Using curl with a host name parameter that targets the proxy like this:

curl -H 'Host: git.example.com' -si http://203.0.113.2

Results in the Nginx welcome page:

    ole@mki:~/Gogs/.gogs/docker$ curl -H 'Host: git.example.com' -si http://203.0.113.2
    HTTP/1.1 200 OK
    Server: nginx/1.15.1
    Date: Sun, 07 Oct 2018 17:09:11 GMT
    Content-Type: text/html
    Content-Length: 612
    Last-Modified: Tue, 03 Jul 2018 13:27:08 GMT
    Connection: keep-alive
    ETag: "5b3b79ac-264"
    Accept-Ranges: bytes

    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    <style>
        body {
            width: 35em;
            margin: 0 auto;
            font-family: Tahoma, Verdana, Arial, sans-serif;
        }
    </style>
    </head>
    <body>
    <h1>Welcome to nginx!</h1>
    <p>If you see this page, the nginx web server is successfully installed and
    working. Further configuration is required.</p>

    <p>For online documentation and support please refer to
    <a href="http://nginx.org/">nginx.org</a>.<br/>
    Commercial support is available at
    <a href="http://nginx.com/">nginx.com</a>.</p>

    <p><em>Thank you for using nginx.</em></p>
    </body>
    </html>

But if I change the host name to the ip address like this:

Using curl with a host name parameter that targets the proxy like this:

curl -H 'Host: 203.0.113.2' -si http://203.0.113.2

Then the proxy works as it should:

    ole@mki:~/Gogs/.gogs/docker$ curl -H 'Host: 203.0.113.2' -si http://203.0.113.2
    HTTP/1.1 302 Found
    Server: nginx/1.15.1
    Date: Sun, 07 Oct 2018 17:14:46 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 34
    Connection: keep-alive
    Location: /user/login
    Set-Cookie: lang=en-US; Path=/; Max-Age=2147483647
    Set-Cookie: i_like_gogits=845bb09d69587b81; Path=/; HttpOnly
    Set-Cookie: _csrf=neGgBfG4LdOcdrdeA0snHjVGz4s6MTUzODkzMjQ4NjE5MzEzNzI3OQ%3D%3D; Path=/; Expires=Mon, 08 Oct 2018 17:14:46 GMT; HttpOnly
    Set-Cookie: redirect_to=%252F; Path=/

    <a href="/user/login">Found</a>.
Ole
  • 41,793
  • 59
  • 191
  • 359
  • Can you ping to that url without adding `203.0.113.2 git.example.com` to `/etc/hosts`? – dvnguyen Oct 06 '18 at 22:20
  • Yes I can ping `203.0.113.2` directly, and I can also ping`git.example.com`, and both addresses provide an answer. – Ole Oct 06 '18 at 22:29
  • Also if I stop the service neither `git.example.com` or 203.0.113.2` will resolve, so I know that they are the same docker container ... – Ole Oct 06 '18 at 22:30
  • How did you deploy nginx container? And which host bears the additional entry in /etc/hosts? – Light.G Oct 06 '18 at 23:46
  • It's all running on my laptop. `docker-compose up` launches both the reverse proxy and the gogs container that the proxy targets. This is for a local dev setup with Gogs. – Ole Oct 07 '18 at 00:04
  • There is no `203.0.113.2` in your `server_names`. Nor `default_server` is set. How is it responding correctly then? – Alexander Azarov Oct 07 '18 at 06:51
  • Did you look into log files? – which of two configurations respond with `404`? – Alexander Azarov Oct 07 '18 at 06:53
  • @AlexanderAzarov I updated the question and also added `203.0.113.2` to `server_names` but the result is the same. I also set the `default_server`. I'll post the full changed configuration in the answer. – Ole Oct 07 '18 at 11:38
  • I asked how it was responding with that configuration. Instead you are posting the changes and new observations. I think you need to invest **your** time to update your question with detailed information what containers, IP addresses and configurations are involved. Otherwise it's really hard to dig into your two related questions. – Alexander Azarov Oct 07 '18 at 11:51
  • @AlexanderAzarov I think I'm miss understanding your question. I tried to answer it by posting the log entries per the requests I'm making and also filling in the details you requested wit hrespect to `203.0.113.2` being in `server_names` etc. – Ole Oct 07 '18 at 12:08
  • I have gogs running on the IP address `203.0.113.1:3000` and in order to get clean URLs without the port number it has to be proxied and I'm trying to setup Nginx to do that in a second docker container using and the entire configuration is defined by `docker-compose`. Please let me know if I can provide more details. – Ole Oct 07 '18 at 12:24

1 Answers1

4

I am sorry, I failed to realize what's happening on your side because the information is sometimes confusing and sometimes incomplete. But Stackoverflow provides a great explanation on what is considered a good question: How to create a Minimal, Complete, and Verifiable example and so I have just tried to implement a minimal example of a system you are likely going to build.

Below I am providing all the files and will show you a test run as well.

File #1: docker-compose.yml

gogs:
  image: gogs/gogs

web:
  build: .
  ports:
  - 8000:80
  links:
  - gogs

I have outdated Docker at my computer and I do not want to bother with Docker networking, so I have just linked both containers using Docker links. This is the most important part and the link will ensure that (1) our web container depends on gogs; (2) we are able to reference gogs IP from inside web as just gogs. Docker will resolve the name to an IP assigned to the container.

Since I want a minimal example, I've skipped everything else as irrelevant. For example, volume.

File #2: Dockerfile

Newer Compose versions support config options specified right in docker-compose.yml, but I need a custom Dockerfile instead. It's trivial:

FROM nginx:stable-alpine
COPY gogs.conf /etc/nginx/conf.d

File #3: gogs.conf

And finally we need Nginx configuration for proxy:

server {
  listen 80 default_server;

  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

  location / {
    proxy_pass http://gogs:3000;
  }
}

You may notice here we are referring another container simply by name gogs and we need to know what port number it is exposes. We know: 3000.

Running

$ docker-compose build
$ docker-compose up

It's up and running:

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
1f74293df630        g_web               "nginx -g 'daemon off"   2 minutes ago       Up 26 seconds       0.0.0.0:8000->80/tcp   g_web_1
dfa2dbaa6074        gogs/gogs           "/app/gogs/docker/sta"   2 minutes ago       Up 26 seconds       22/tcp, 3000/tcp       g_gogs_1

web container is exposed to the world at port number 8000.

Tests

by IP

Let's request it by IP:

$ curl -si http://192.168.99.100:8000/
HTTP/1.1 302 Found
Server: nginx/1.14.0
Date: Sun, 07 Oct 2018 15:13:55 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 31
Connection: keep-alive
Location: /install
Set-Cookie: lang=en-US; Path=/; Max-Age=2147483647
Set-Cookie: i_like_gogits=50411f542e2ae8f8; Path=/; HttpOnly
Set-Cookie: _csrf=ZJxRPqnqayIbpAYgZ22zrPIOaSo6MTUzODkyNTIzNTQ2NTg5MDE1NA%3D%3D; Path=/; Expires=Mon, 08 Oct 2018 15:13:55 GMT; HttpOnly

<a href="/install">Found</a>.

Corresponding log file:

web_1   | 192.168.99.1 - - [07/Oct/2018:15:14:24 +0000] "GET / HTTP/1.1" 302 31 "-" "curl/7.61.1" "-"
gogs_1  | [Macaron] 2018-10-07 15:14:24: Started GET / for 192.168.99.1
gogs_1  | [Macaron] 2018-10-07 15:14:24: Completed GET / 302 Found in 199.519µs
gogs_1  | 2018/10/07 15:14:24 [TRACE] Session ID: 38d06d393a9e9d21
gogs_1  | 2018/10/07 15:14:24 [TRACE] CSRF Token: Xth986dFWhhj8w8vBdIqRZu4SbI6MTUzODkyNTI2NDYxMDYzNzAyNA==

I can see from the log that (1) both containers work and they were used to process the request; (2) 192.168.99.1 is my host's IP address, which means "gogs" successfully gets a real request IP via X-Forwarded-For.

by domain name

OK, let's request using a domain name:

$ curl -H 'Host: g.example.com' -si http://192.168.99.100:8000/

Trust me, this is just sufficient. Host is an HTTP protocol header to pass domain name. And any browser will do the same under the hood.

and the corresponding log file is --

gogs_1  | [Macaron] 2018-10-07 15:32:49: Started GET / for 192.168.99.1
gogs_1  | [Macaron] 2018-10-07 15:32:49: Completed GET / 302 Found in 618.701µs
gogs_1  | 2018/10/07 15:32:49 [TRACE] Session ID: 81f64d97e9c3dd1e
gogs_1  | 2018/10/07 15:32:49 [TRACE] CSRF Token: X5QyHM4LMIfn8OSJD1gwSSEyXV46MTUzODkyNjM2OTgyODQyMjExMA==
web_1   | 192.168.99.1 - - [07/Oct/2018:15:32:49 +0000] "GET / HTTP/1.1" 302 31 "-" "curl/7.61.1" "-"

No changes, everything works as expected.

Alexander Azarov
  • 12,971
  • 2
  • 50
  • 54
  • Thanks @Alexander - That gave me some new tools to try out - like curl ... I have a similar setup that does work. It was only when I switched to docker-compose that I started getting hickups, so I'm wondering. It obviously has something to do with the host name. If I curl the proxy directly I get the gogs response, but if I curl `git.example.com` I get back an Nginx welcome page response. I'll post the responses in the question. – Ole Oct 07 '18 at 17:08
  • If I use curl like this: `curl -H 'Host: 203.0.113.2' -si http://203.0.113.2` the docker compose setup works, but if I use it like this `curl -H 'Host: git.example.com' -si http://203.0.113.2` then I get the Nginx welcome page ... and I don't get why ... because `git.example.com` is listed as a `server_name` right next to the ip address ... – Ole Oct 07 '18 at 17:18
  • For some reason the host name matters to Nginx when it's trying to figure out whether to proxy the request. If the host name is set to git.example.com the request does not seem to go through, but if it's set to 203.0.113.2 then it goes through. Why does the host name matter? – Ole Oct 07 '18 at 17:23
  • Another observation is that if I curl the gogs host directly like this: `curl -si http://203.0.113.1:3000/` I get the same response as when I curl it like this: `curl -H 'Host: 203.0.113.2' -si http://203.0.113.2` ... so it does seem like Nginx does not perform the proxying when the hostname is present instead of the ip address ... but why? – Ole Oct 07 '18 at 17:34
  • Also described this in an [Nginx Docker issue](https://github.com/nginxinc/docker-nginx/issues/281) – Ole Oct 07 '18 at 17:41