0

Problem

I have three Docker containers: a backend, a frontend and an nginx container that handle requests. When I run it on my computer (windows laptop with docker engine), everything works perfectly. I can see the call are made in the logs of the containers:

reverse_proxy_1  | 172.19.0.1 - - [10/Oct/2021:21:15:00 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36"
reverse_proxy_1  | 172.19.0.1 - - [10/Oct/2021:21:15:00 +0000] "GET /static/js/bundle.js HTTP/1.1" 304 0 "http://localhost/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36"
reverse_proxy_1  | 172.19.0.1 - - [10/Oct/2021:21:15:00 +0000] "GET /static/js/vendors~main.chunk.js HTTP/1.1" 304 0 "http://localhost/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36"
reverse_proxy_1  | 172.19.0.1 - - [10/Oct/2021:21:15:00 +0000] "GET /static/js/main.chunk.js HTTP/1.1" 304 0 "http://localhost/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36"
reverse_proxy_1  | 172.19.0.1 - - [10/Oct/2021:21:15:01 +0000] "GET /favicon.ico HTTP/1.1" 304 0 "http://localhost/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36"
reverse_proxy_1  | 172.19.0.1 - - [10/Oct/2021:21:15:01 +0000] "GET /manifest.json HTTP/1.1" 304 0 "http://localhost/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36"
reverse_proxy_1  | 172.19.0.1 - - [10/Oct/2021:21:15:01 +0000] "GET /logo192.png HTTP/1.1" 304 0 "http://localhost/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36"
reverse_proxy_1  | 172.19.0.1 - - [10/Oct/2021:21:15:02 +0000] "GET /api/versions/ HTTP/1.1" 200 55 "http://localhost/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36"
backend_1        | Sending versions

When I deploy this either on a dedicated ubuntu server (192.168.31.103) on a network or a VM in VirtualBox on my computer, it seems the frontend and backend don't communicate anymore. I can see the front end, but if I do the same operation as before, the backend is not queried:

192.168.31.101 - - [10/Oct/2021:21:29:39 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36"
192.168.31.101 - - [10/Oct/2021:21:29:39 +0000] "GET /sockjs-node HTTP/1.1" 101 2801 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36"
192.168.31.101 - - [10/Oct/2021:21:29:39 +0000] "GET /static/js/bundle.js HTTP/1.1" 304 0 "http://192.168.31.103/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36"
192.168.31.101 - - [10/Oct/2021:21:29:39 +0000] "GET /static/js/vendors~main.chunk.js HTTP/1.1" 304 0 "http://192.168.31.103/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36"
192.168.31.101 - - [10/Oct/2021:21:29:39 +0000] "GET /static/js/main.chunk.js HTTP/1.1" 304 0 "http://192.168.31.103/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36"
192.168.31.101 - - [10/Oct/2021:21:29:41 +0000] "GET /favicon.ico HTTP/1.1" 200 2114 "http://192.168.31.103/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36"

I can go directly to the backend in my browser: http://192.168.31.103/api/versions/ and this works fine, return the json object and nginx displays the corresponding log.

192.168.31.101 - - [10/Oct/2021:21:39:25 +0000] "GET /api/versions/ HTTP/1.1" 200 55 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36"
192.168.31.101 - - [10/Oct/2021:21:39:25 +0000] "GET /favicon.ico HTTP/1.1" 200 2114 "http://192.168.31.103/api/versions/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36"

(note that 192.168.31.101 is the IP of my laptop on the network).

Can you spot the mistake?

Configuration

I have a Django-REST backend, that serve some views, everything behind the /api/ prefix, for examples: http:localhost/api/version. I removed all CSRF protection for now.

settings.py

ALLOWED_HOSTS = [
  localhost,
  127.0.0.1,
  192.168.31.103,
]

I have a React frontend that will fetch this backend:

App.js

[...]
const backendURL = 'http://localhost';

const getBackendVersion = () => {
    setFetchingVersions(true);
    fetch(`${backendURL}/api/versions/`)
      .then( response => response.json())
      .then( d => {
        setAppVersions({
          'frontend': frontendVersion,
          'backend': d['versions']['maapi'],
        })
      })
      .catch( () => setFetchingVersions(false));
  };
[...]

I deploy this using Docker.

docker-compose.yml

version: '3.8'

services:
  backend:
    build: ./ma-backend
    command: gunicorn config.wsgi:application --bind 0.0.0.0:8000
    expose:
      - 8000
    env_file:
      - ./.env.prod

  frontend:
    build: ./ma-frontend
    command: npm start
    expose:
      - 3000
    depends_on:
      - backend
    env_file:
      - ./.env.prod

  reverse_proxy:
    build: ./nginx
    ports:
      - 80:80
    depends_on:
      - backend
      - frontend

nginx.conf:

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
  worker_connections 1024;
}

http {
  upstream backend {
    server backend:8000;
  }

  upstream frontend {
    server frontend:3000;
  }

  server {
    listen 80;

    server_name localhost 127.0.0.1;

    location /api {
      proxy_pass              http://backend;
      proxy_http_version  1.1;
      proxy_redirect      default;
      proxy_set_header    Upgrade $http_upgrade;
      proxy_set_header    Connection "upgrade";
      proxy_set_header    Host $host;
      proxy_set_header    X-Real-IP $remote_addr;
      proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header    X-Forwarded-Host $server_name;
    }

    location /admin {
      proxy_pass              http://backend;
      proxy_http_version  1.1;
      proxy_redirect      default;
      proxy_set_header    Upgrade $http_upgrade;
      proxy_set_header    Connection "upgrade";
      proxy_set_header    Host $host;
      proxy_set_header    X-Real-IP $remote_addr;
      proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header    X-Forwarded-Host $server_name;
    }

    location / {
      proxy_pass              http://frontend;
      proxy_http_version  1.1;
      proxy_redirect      default;
      proxy_set_header    Upgrade $http_upgrade;
      proxy_set_header    Connection "upgrade";
      proxy_set_header    Host $host;
      proxy_set_header    X-Real-IP $remote_addr;
      proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header    X-Forwarded-Host $server_name;
    }
  }
}
Romn
  • 174
  • 2
  • 14

1 Answers1

1

Looks like backendURL = 'http://localhost'; may be the culprit here? E.g your front-end is configured to query your backend at http://localhost eventhough it is deployed on a different IP/server.

Is it possible for you to use a environment variable or something like that during the React build process to provide the actual URL of your backend?

Agate
  • 3,152
  • 1
  • 19
  • 30
  • I define `REACT_APP_BACKEND_URL=192.168.31.103` in *.env.prod*, then: `const backendURL = process.env.REACT_APP_BACKEND_URL || 'http://localhost';` in *App.js*. And I have an error displaying in frontend logs: `Proxy error: Could not proxy request /192.168.31.103/api/versions/ from 192.168.31.103 to http://localhost:5000/*. See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (ECONNREFUSED).` I am not sure where this `http://localhost:5000/` come from, it is not defined anywhere in the files. – Romn Oct 10 '21 at 22:03
  • This looks similar to https://stackoverflow.com/a/50207462/2844093, you may have some kind of proxy configuration in your node development environment. – Agate Oct 10 '21 at 22:06
  • 1
    Can you set the backend URL to an empty string? Then your code would try to `GET /api/versions`; the browser would interpret the path-only URL as on the same server as the page; and the request would go to the reverse proxy server. – David Maze Oct 10 '21 at 22:09
  • Thanks both of you. I removed the proxy line from `package.json`, that was not enough, the frontend wat getting 404 errors when querying the backend. I replaced `backendURL` by an empty string and now it works. I pointing the proxy line in `package.json` to the backend should work too as it is [defining a fall back when the address is not resolved](https://create-react-app.dev/docs/proxying-api-requests-in-development/). – Romn Oct 10 '21 at 22:29