Getting ETIMEDOUT error when calling my rest api

Do you have any idea why calling my api endpoint from axios fails

rontend_1  | Error: connect ETIMEDOUT 188.166.224.149:443
frontend_1  |     at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1142:16) {
frontend_1  |   errno: -110,
frontend_1  |   code: 'ETIMEDOUT',
frontend_1  |   syscall: 'connect',
frontend_1  |   address: '188.166.224.149',
frontend_1  |   port: 443,
frontend_1  |   config: {
frontend_1  |     url: '/gists',
frontend_1  |     method: 'get',
frontend_1  |     headers: {
frontend_1  |       Accept: 'application/json, text/plain, */*',
frontend_1  |       'Content-Type': 'application/json',
frontend_1  |       'User-Agent': 'axios/0.21.1'
frontend_1  |     },
frontend_1  |     baseURL: 'https://api.snippy.blanknodes.com',
frontend_1  |     transformRequest: [ [Function: transformRequest] ],
frontend_1  |     transformResponse: [ [Function: transformResponse] ],
frontend_1  |     timeout: 0,
frontend_1  |     withCredentials: true,
frontend_1  |     adapter: [Function: httpAdapter],
frontend_1  |     xsrfCookieName: 'XSRF-TOKEN',
frontend_1  |     xsrfHeaderName: 'X-XSRF-TOKEN',
frontend_1  |     maxContentLength: -1,
frontend_1  |     maxBodyLength: -1,
frontend_1  |     validateStatus: [Function: validateStatus],
frontend_1  |     data: undefined
frontend_1  |   },
frontend_1  |   request: <ref *1> Writable {
frontend_1  |     _writableState: WritableState {
frontend_1  |       objectMode: false,
frontend_1  |       highWaterMark: 16384,
frontend_1  |       finalCalled: false,
frontend_1  |       needDrain: false,
frontend_1  |       ending: false,
frontend_1  |       ended: false,
frontend_1  |       finished: false,
frontend_1  |       destroyed: false,
frontend_1  |       decodeStrings: true,
frontend_1  |       defaultEncoding: 'utf8',
frontend_1  |       length: 0,
frontend_1  |       writing: false,
frontend_1  |       corked: 0,
frontend_1  |       sync: true,
frontend_1  |       bufferProcessing: false,
frontend_1  |       onwrite: [Function: bound onwrite],
frontend_1  |       writecb: null,
frontend_1  |       writelen: 0,
frontend_1  |       afterWriteTickInfo: null,
frontend_1  |       buffered: [],
frontend_1  |       bufferedIndex: 0,
frontend_1  |       allBuffers: true,
frontend_1  |       allNoop: true,
frontend_1  |       pendingcb: 0,
frontend_1  |       constructed: true,
frontend_1  |       prefinished: false,
frontend_1  |       errorEmitted: false,
frontend_1  |       emitClose: true,
frontend_1  |       autoDestroy: true,
frontend_1  |       errored: null,
frontend_1  |       closed: false,
frontend_1  |       closeEmitted: false,
frontend_1  |       [Symbol(kOnFinished)]: []
frontend_1  |     },
frontend_1  |     _events: [Object: null prototype] {
frontend_1  |       response: [Function: handleResponse],
frontend_1  |       error: [Function: handleRequestError]
frontend_1  |     },
frontend_1  |     _eventsCount: 2,
frontend_1  |     _maxListeners: undefined,
frontend_1  |     _options: {
frontend_1  |       maxRedirects: 21,
frontend_1  |       maxBodyLength: 10485760,
frontend_1  |       protocol: 'https:',
frontend_1  |       path: '/gists',
frontend_1  |       method: 'GET',
frontend_1  |       headers: [Object],
frontend_1  |       agent: undefined,
frontend_1  |       agents: [Object],
frontend_1  |       auth: undefined,
frontend_1  |       hostname: 'api.snippy.blanknodes.com',
frontend_1  |       port: null,
frontend_1  |       nativeProtocols: [Object],
frontend_1  |       pathname: '/gists'
frontend_1  |     },
frontend_1  |     _ended: true,
frontend_1  |     _ending: true,
frontend_1  |     _redirectCount: 0,
frontend_1  |     _redirects: [],
frontend_1  |     _requestBodyLength: 0,
frontend_1  |     _requestBodyBuffers: [],
frontend_1  |     _onNativeResponse: [Function (anonymous)],
frontend_1  |     _currentRequest: ClientRequest {
frontend_1  |       _events: [Object: null prototype],
frontend_1  |       _eventsCount: 7,
frontend_1  |       _maxListeners: undefined,
frontend_1  |       outputData: [],
frontend_1  |       outputSize: 0,
frontend_1  |       writable: true,
frontend_1  |       destroyed: false,
frontend_1  |       _last: true,
frontend_1  |       chunkedEncoding: false,
frontend_1  |       shouldKeepAlive: false,
frontend_1  |       _defaultKeepAlive: true,
frontend_1  |       useChunkedEncodingByDefault: false,
frontend_1  |       sendDate: false,
frontend_1  |       _removedConnection: false,
frontend_1  |       _removedContLen: false,
frontend_1  |       _removedTE: false,
frontend_1  |       _contentLength: 0,
frontend_1  |       _hasBody: true,
frontend_1  |       _trailer: '',
frontend_1  |       finished: true,
frontend_1  |       _headerSent: true,
frontend_1  |       _closed: false,
frontend_1  |       socket: [TLSSocket],
frontend_1  |       _header: 'GET /gists HTTP/1.1\r\n' +
frontend_1  |         'Accept: application/json, text/plain, */*\r\n' +
frontend_1  |         'Content-Type: application/json\r\n' +
frontend_1  |         'User-Agent: axios/0.21.1\r\n' +
frontend_1  |         'Host: api.snippy.blanknodes.com\r\n' +
frontend_1  |         'Connection: close\r\n' +
frontend_1  |         '\r\n',
frontend_1  |       _keepAliveTimeout: 0,
frontend_1  |       _onPendingData: [Function: nop],
frontend_1  |       agent: [Agent],
frontend_1  |       socketPath: undefined,
frontend_1  |       method: 'GET',
frontend_1  |       maxHeaderSize: undefined,
frontend_1  |       insecureHTTPParser: undefined,
frontend_1  |       path: '/gists',
frontend_1  |       _ended: false,
frontend_1  |       res: null,
frontend_1  |       aborted: false,
frontend_1  |       timeoutCb: null,
frontend_1  |       upgradeOrConnect: false,
frontend_1  |       parser: null,
frontend_1  |       maxHeadersCount: null,
frontend_1  |       reusedSocket: false,
frontend_1  |       host: 'api.snippy.blanknodes.com',
frontend_1  |       protocol: 'https:',
frontend_1  |       _redirectable: [Circular *1],
frontend_1  |       [Symbol(kCapture)]: false,
frontend_1  |       [Symbol(kNeedDrain)]: false,
frontend_1  |       [Symbol(corked)]: 0,
frontend_1  |       [Symbol(kOutHeaders)]: [Object: null prototype]
frontend_1  |     },
frontend_1  |     _currentUrl: 'https://api.snippy.blanknodes.com/gists',
frontend_1  |     [Symbol(kCapture)]: false
frontend_1  |   },
frontend_1  |   response: undefined,
frontend_1  |   isAxiosError: true,
frontend_1  |   toJSON: [Function: toJSON]
frontend_1  | }

When I tried using curl it works fine.

snippy (main) curl https://api.snippy.blanknodes.com/gists -v
*   Trying 188.166.224.149:443...
* Connected to api.snippy.blanknodes.com (188.166.224.149) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=api.snippy.blanknodes.com
*  start date: Jul 22 01:09:00 2021 GMT
*  expire date: Oct 20 01:08:58 2021 GMT
*  subjectAltName: host "api.snippy.blanknodes.com" matched cert's "api.snippy.blanknodes.com"
*  issuer: C=US; O=Let's Encrypt; CN=R3
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x5641a162d970)
> GET /gists HTTP/2
> Host: api.snippy.blanknodes.com
> user-agent: curl/7.77.0
> accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
< HTTP/2 200 
< access-control-allow-credentials: true
< content-security-policy: default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests
< content-type: application/json; charset=utf-8
< date: Thu, 22 Jul 2021 03:07:51 GMT
< etag: W/"2-l9Fw4VUO7kr8CvBlt4zaMCqXZ0w"
< expect-ct: max-age=0
< referrer-policy: no-referrer
< server: Caddy
< strict-transport-security: max-age=15552000; includeSubDomains
< vary: Origin
< x-content-type-options: nosniff
< x-dns-prefetch-control: off
< x-download-options: noopen
< x-frame-options: SAMEORIGIN
< x-permitted-cross-domain-policies: none
< x-xss-protection: 0
< content-length: 2
< 
* Connection #0 to host api.snippy.blanknodes.com left intact
[]

This app runs using docker-compose and caddy server.

I use caddy for reverse-proxy and auto https

{
   email [REDACTED]
   acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
}

snippy.blanknodes.com {
  reverse_proxy frontend:3000
}

api.snippy.blanknodes.com {
  reverse_proxy backend:4000
}

and run the app through docker-compose up

version: "3.7"
services:
  database:
    image: postgres:13-alpine
    restart: always
    environment:
      POSTGRES_PASSWORD: postgres
      POSTGRES_USER: postgres
      APP_DB_NAME: snippy_prod
      APP_DB_USER: jeepers3327
    volumes:
      - ./db:/docker-entrypoint-initdb.d/
      - postgres_data:/var/lib/postgresql/data/
    expose: 
      - 5432
    networks: 
      - webserver

  sessions:
    image: redis:6.2-alpine
    volumes:
      - redis_data:/redis/data
    ports:
      - 6379
    networks: 
      - webserver

  backend:
    build: ./backend
    restart: unless-stopped
    env_file: ./backend/.env.production
    depends_on:
      - database
      - sessions
    networks: 
      - webserver

  frontend:
    build: ./frontend
    restart: unless-stopped
    depends_on:
      - backend
    networks: 
      - webserver
      
  proxy:
    image: caddy:2.4.3-alpine
    restart: unless-stopped
    ports:
      - 80:80
      - 443:443
    volumes:
      - $PWD/Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config
    depends_on: 
      - backend
      - frontend
    networks: 
      - webserver

volumes:
  redis_data:
  postgres_data:
  caddy_data:
  caddy_config:

networks: 
  webserver:
    external: true


Read more here: https://stackoverflow.com/questions/68478698/getting-etimedout-error-when-calling-my-rest-api

Content Attribution

This content was originally published by jeepers3327 at Recent Questions - Stack Overflow, and is syndicated here via their RSS feed. You can read the original post over there.

%d bloggers like this: