Search code examples
node.jsdockerexpressapi-gatewaykong

Kong 502 Bad Gateway: "An invalid response was received from the upstream server"


TL;DR

I can't send HTTP request to local docker container (accessible via 127.0.0.1:4002) through Kong gateway.

Kong Gateway components:

  • Service test_service: url=http://127.0.0.1:4002;
  • Route test_route: paths[]=/test, name=test_route;

Request to Kong proxy:

$ curl -X GET http://localhost:8000/test
{
  "message":"An invalid response was received from the upstream server",
  "request_id":"9aba1e35ea54222d9fd27c4e2eeea850"
}

Long Version

I created a simple Express app that responds to HTTP requests with "Foo" and "Bar", and dockerized it.

Application

index.js:

const express = require('express');

const app = express();
var port = 4002;

app.use("/foo", (req, res) => {
    res.send("Foo");
});

app.use("/bar", (req, res) => {
  res.send("Bar");
});

app.use((req, res) => {
  res.send("Test unknown path");
});

app.listen(port, () => {
  console.log(`Foo-bar listening on port ${port}`)
})

Dockerfile:

FROM node:lts-alpine
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 4002
CMD ["node", "index.js"]

After building and running it, I can send HTTP requests to "localhost:4002" and correctly get the responses.

Example:

$ docker ps
CONTAINER ID   IMAGE                        COMMAND                  CREATED              STATUS                 PORTS                                             NAMES
fce1cc4e7b24   mikyll/test-service:latest   "docker-entrypoint.s…"   About a minute ago   Up About a minute      0.0.0.0:4002->4002/tcp                            nice_blackwell

$ curl -X GET http://localhost:4002
Test unknown path

$ curl -X GET http://localhost:4002/foo
Foo

$ curl -X GET http://localhost:4002/bar
Bar

Kong Setup

I followed the instructions to setup Kong Gateway on Docker and manage services and routes:

  1. I run Kong Gateway container:
curl -Ls https://get.konghq.com/quickstart | bash
  1. Tested the connection:
$ curl --head localhost:8001
HTTP/1.1 200 OK
[...]
  1. Created a service:
$ curl -i -s -X POST http://localhost:8001/services --data name=test_service --data url='http://127.0.0.1:4002'
HTTP/1.1 201 Created
[...]

Service JSON:

{
  "data":[
    {
      "retries":5,
      "tls_verify":null,
      "protocol":"http",
      "port":4002,
      "updated_at":1700054325,
      "created_at":1700054325,
      "connect_timeout":60000,
      "read_timeout":60000,
      "client_certificate":null,
      "host":"127.0.0.1",
      "path":null,
      "name":"test_service",
      "enabled":true,
      "tags":null,
      "write_timeout":60000,
      "ca_certificates":null,
      "id":"e79539ca-603b-4237-8abd-6ff07bd73160",
      "tls_verify_depth":null
    }
  ],
  "next":null
}
  1. Created a route:
$ curl -i -X POST http://localhost:8001/services/test_service/routes --data 'paths[]=/test' --data name=test_route

Route JSON:

{
  "data":[
    {
      "https_redirect_status_code":426,
      "service":{
        "id":"e79539ca-603b-4237-8abd-6ff07bd73160"
      },
      "id":"4b04a262-6229-4361-9b2c-88f00b0fe6c2",
      "hosts":null,
      "path_handling":"v0",
      "updated_at":1700054404,
      "created_at":1700054404,
      "preserve_host":false,
      "headers":null,
      "methods":null,
      "sources":null,
      "destinations":null,
      "paths":[
        "/test"
      ],
      "snis":null,
      "name":"test_route",
      "tags":null,
      "request_buffering":true,
      "response_buffering":true,
      "protocols":[
        "http",
        "https"
      ],
      "regex_priority":0,
      "strip_path":true
    }
  ],
  "next":null
}

Problem

When I try to send an HTTP request, I get the error "An invalid response was received from the upstream server.":

$ curl -X GET http://localhost:8000/test
{
  "message":"An invalid response was received from the upstream server",
  "request_id":"9aba1e35ea54222d9fd27c4e2eeea850"
}

Question

Is my configuration (service/route) wrong? Am I missing some setup step?


Solution

  • The problem is mainly how you connect Kong with your service on Docker.
    The service http://127.0.0.1:4002 means that Kong will call 127.0.0.1 (localhost) with port 4002, basically calling the Kong container itself, not you Expressjs app.

    To fix the issue, run both your ExpressJS app and Kong on the same user-defined network and call the app with Docker's service name (nice_blackwell, in this instance).
    Maybe create a compose file just for easier management.