Search code examples
node.jsdockerssldocker-compose

After moving docker-compose.yml file, I get "The server does not support SSL connections"


This is most likely due to my lack of knowledge around Docker, so I probably just need a theoretical answer but I can post some code if needed.

So, I have a containerized project that connects to a managed database on Digital Ocean through a public network connection and SSL is required so I have that configured. When I run it locally with:

docker compose build
docker compose up

everything looks fine and I can see that it connects to the DB. Then I push the new images to docker hub with:

docker compose push

and reference those images in my docker-compose.yml:

image: <myDockerID>/<imagename>

I've checked Docker hub to confirm that the images are being updated when pushing and also deleted them to make sure they were the right images being uploaded.

In my root directory I have the key files:

  • docker-compose.yml
  • Dockerfile
  • ca-certificate.crt
  • .env
  • ..

From what I've read, everything looks good. From my understanding, I should now be able to copy/paste the docker-compose file in any directory on any machine and run docker compose up (this might be where I misunderstand). However, when I try this, I get an SSL error. For example, in a new directory containing only the docker-compose.yml, I would clear out old stuff then run fresh:

docker compose down -v --rmi all --remove-orphans
docker compose up

and it fetches new images and everything looks pretty good except that now I get:

[TypeOrmModule] Unable to connect to the database. Retrying (2)...
worker    | Error: The server does not support SSL connections
worker    |     at Socket.<anonymous> (/usr/src/app/node_modules/pg/lib/connection.js:77:37)
worker    |     at Object.onceWrapper (node:events:628:26)
worker    |     at Socket.emit (node:events:513:28)
worker    |     at addChunk (node:internal/streams/readable:324:12)
worker    |     at readableAddChunk (node:internal/streams/readable:297:9)
worker    |     at Readable.push (node:internal/streams/readable:234:10)
worker    |     at TCP.onStreamRead (node:internal/stream_base_commons:190:23)

So, my question is why doesn't this error present itself in the project directory? Is this error referring to the DB not supporting SSL connection (it does)? Does docker require more than just the docker-compose.yml file to run correctly?

Here is my Dockerfile:

FROM node:18.16.0-alpine

WORKDIR /usr/src/app

COPY package.json ./
COPY yarn.lock ./
RUN yarn --production
COPY . .
RUN yarn build

Here is my docker-compose.yml:

version: "3.8"

networks:
  app-net:
    driver: bridge

volumes:
  server_data: {}
  worker_data: {}
  postgres_data: {}

services:
  ######################################################################################
  server:
    container_name: server
    build:
      context: .
      dockerfile: Dockerfile
    image: <dockhubID>/backend2-server
    ports:
      - 3001:3001
    command: ["yarn", "start:server"]
    volumes:
      - server_data:/usr/src/app
    networks:
      - app-net
    environment:
      DB_HOST: ${DB_HOST}
      DB_PORT: ${DB_PORT}
      DB_NAME: ${DB_NAME}
      DB_USERNAME: ${DB_USERNAME}
      DB_PASSWORD: ${DB_PASSWORD}
      DB_CA_CERT_PATH: ${DB_CA_CERT_PATH}
  worker:
    container_name: worker
    build:
      context: .
      dockerfile: Dockerfile
    image: <dockerhubID>/backend2-worker
    command: ["yarn", "start:worker"]
    volumes:
      - worker_data:/usr/src/app
    expose:
      - 4000
    networks:
      - app-net
    environment:
      DB_HOST: ${DB_HOST}
      DB_PORT: ${DB_PORT}
      DB_NAME: ${DB_NAME}
      DB_USERNAME: ${DB_USERNAME}
      DB_PASSWORD: ${DB_PASSWORD}
      DB_CA_CERT_PATH: ${DB_CA_CERT_PATH}

Any help is greatly appreciated!

I've seen the following questions but wasn't able to answer the questions that pertain to my situation:

UPDATE: After adding the missing environment variable to the docker-compose.yml file, I'm seeing an error that makes me think I didn't set the variable correctly:

node:internal/fs/utils:347
worker  |     throw err;
worker  |     ^
worker  | 
worker  | Error: ENOENT: no such file or directory, open
worker  |     at Object.openSync (node:fs:601:3)
worker  |     at Object.readFileSync (node:fs:469:35)
worker  |     at Object.<anonymous> (/usr/src/app/dist/vendure-config.js:62:30)
worker  |     at Module._compile (node:internal/modules/cjs/loader:1254:14)
worker  |     at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
worker  |     at Module.load (node:internal/modules/cjs/loader:1117:32)
worker  |     at Module._load (node:internal/modules/cjs/loader:958:12)
worker  |     at Module.require (node:internal/modules/cjs/loader:1141:19)
worker  |     at require (node:internal/modules/cjs/helpers:110:18)
worker  |     at Object.<anonymous> (/usr/src/app/dist/index-worker.js:4:26) {
worker  |   errno: -2,
worker  |   syscall: 'open',
worker  |   code: 'ENOENT'
worker  | }

I also see this warning now:

WARN[0000] The "DB_CA_CERT_PATH" variable is not set. Defaulting to a blank string.

The variable is set in .env as: DB_CA_CERT_PATH=/usr/src/app/ca-certificate.crt

Since the Dockerfile's workspace is set to /usr/src/app, I assume the path should be correct. I also assume that .env is copied over when COPY . . is ran, but I could be mistaken. Just to reiterate, I'm focusing on the case where I copy the docker-compose.yml file into an empty directory. Running the container in the original directory still works fine. Thanks again for the help!


Solution

  • I will try to summarize the comments by Alex D. and me:

    • The assumption was that ca-certificate.crt is used for the SSL connection, and that your docker-compose.yml is where you are referencing this certificate and the path in that file might be broken.
    • You stated that you are referencing the certificate file via process.env.DB_CA_CERT_PATH. However, it was unclear how you are setting this variable in the container, since it was not present in the docker-compose.yml or Dockerfile.
    • It turns out the environment variable was not configured at all. You then added a reference to this variable in the docker-compose.yml file, which in turn references a "local" environment variable defined in an .env file, which needs to be present alongside the docker-compose.yml.

    As you pointed out, the way you are currently defining your environment variables in the docker-compose.yml (e.g. DB_CA_CERT_PATH: ${DB_CA_CERT_PATH}), you actually are only passing your "local" environment variables on the host to that file, which are then passed into the docker container. For this reason, you also need the .env file alongside the docker-compose.yml file.

    If you only want to use "a single docker-compose.yml" file without the local .env file, you can just defined the environment variables directly in docker-compose.yml:

    server:
    ...
      environment:
        DB_CA_CERT_PATH=/usr/src/app/ca-certificate.crt
    

    If you wanted to have a self-contained image, you could, again, use a .env file which is copied to the image, or define these environment variables in your Dockerfile with the ENV instruction.