0

I have all my services dockerized via docker-compose.yml (irrelevant lines have been omitted):

proxy:
    image: nginx:alpine    
    ports:
      - '80:80'
      - '443:443'    
    networks:
      - myNetwork

app-server:  
    ports:
      - '3000:3000'
    volumes:
      - ./:/app
      - /app/node_modules    
    networks:
      - myNetwork

mongo6:   
    networks:
      - myNetwork
    ports:
      - 27017:27017    

networks:
  myNetwork:
    external: true
    

I'm trying to connect to the mongo instance so the relevant parts of my nginx.conf are:

   upstream docker-mongo {
      server mongo6:27017;
   }


   server {
      listen 443 ssl;
      server_name mongo.mysite.co;
      ...

      location / {
         proxy_pass http://docker-mongo;
      }
   }

I created a new Mongo user mongo-mydb-user for the database "mydb"

Now I can connect to the mongo6 container from the outside world like via Compass using connection string:

mongodb://mongo-mydb-user:pass@mongo.mysite.com:27017/mydb

However, I cannot connect to the mongo6 container from within my code (the "app-server" container) using the same connection string.

I can flip this situation around such that my code CAN connect but then Compass CAN'T. To do that, I can simply use network_mode: host instead of network: myNetwork and then modify the nginx config to proxy_pass mongo requests directly to http://localhost:27017 instead of http://docker-mongo.

Using network_mode: host isn't something I want to do. I have another machine setup exactly the same using a docker network and there is no issue connecting from either compass or app code.

My /etc/host is as follows:

127.0.0.1   localhost
::1     localhost ip6-localhost ip6-loopback
ff02::1     ip6-allnodes
ff02::2     ip6-allrouters

# Auto-generated hostname. Please do not remove this comment.
31.123.45.678 mysite.vps.local mysite

What's wrong with my docker network configuration that I can connect via Compass but not from my app code?

The error is

Failed to connect to mongo MongooseServerSelectionError: Server selection timed out after 30000 ms
server  |     at Connection.openUri (/app/node_modules/mongoose/lib/connection.js:825:32)
server  |     at /app/node_modules/mongoose/lib/index.js:414:10
server  |     at /app/node_modules/mongoose/lib/helpers/promiseOrCallback.js:41:5
server  |     at new Promise (<anonymous>)
server  |     at promiseOrCallback (/app/node_modules/mongoose/lib/helpers/promiseOrCallback.js:40:10)
server  |     at Mongoose._promiseOrCallback (/app/node_modules/mongoose/lib/index.js:1288:10)
server  |     at Mongoose.connect (/app/node_modules/mongoose/lib/index.js:413:20)
server  |     at App.connectToDatabase (/app/dist/app.js:47:41)
server  |     at new App (/app/dist/app.js:117:18)
server  |     at main (/app/dist/server.js:42:21) {
server  |   reason: TopologyDescription {
server  |     type: 'Single',
server  |     servers: Map(1) { 'mongo.cardstop.co:27017' => [ServerDescription] },
server  |     stale: false,
server  |     compatible: true,
server  |     heartbeatFrequencyMS: 10000,
server  |     localThresholdMS: 15,
server  |     setName: null,
server  |     maxElectionId: null,
server  |     maxSetVersion: null,
server  |     commonWireVersion: 0,
server  |     logicalSessionTimeoutMinutes: null
server  |   },
server  |   code: undefined
server  | }
parliament
  • 21,544
  • 38
  • 148
  • 238
  • What do you mean by "cannot connect"? What is the error message? – Wernfried Domscheit Jun 30 '23 at 06:11
  • @WernfriedDomscheit It just times out. Added the error to OP – parliament Jun 30 '23 at 07:09
  • The error message indicates that it is trying to connect to localhost (127.0.0.1) instead of your service. Could you try using `mongo6` as host instead (or the reverse-proxy `proxy`, both should be possible with your setup), such as `mongodb://mongo-mydb-user:pass@mongo6:27017/mydb` in the connection string? – Rob Jun 30 '23 at 08:38
  • @Rob Sorry, I posted the wrong error earlier. I updated it to the correct one, it does not mention "127.0.0.1". However, your idea does solve my issue. Using the docker container name mongo6:27017 works thank you. Feel free to answer with anymore details – parliament Jun 30 '23 at 10:31

1 Answers1

1

Instead of using the host as an "indirect route" to the container, you could utilize the network created by docker-compose (myNetwork) and use the service name (mongo6) to identify your container.

As such, you could try using mongo6 as host name instead (or the reverse-proxy proxy, both should be possible with your setup). For example, in the connection string:

mongodb://mongo-mydb-user:pass@mongo6:27017/mydb 
Rob
  • 491
  • 4
  • 14
  • This does solve my issue but makes me wonder how this is working using the "indirect route" on another VPS instance running the same services. Both on Ubuntu 18.04 but one using "WebAdmin" control panel (working) and the other using "HestiaCP" (not working). I wonder if and what changes these control panels could be making that might be causing this. My /etc/hosts file is the same on both machines. – parliament Jul 01 '23 at 04:48
  • I am not familiar with the mentioned tools, but to address your first question: If you specify a port mapping in `docker-compose.yml` (ports: - 27017:27017), you should be able to connect to your mongo6 container through localhost (127.0.0.1). What exactly are you trying to achieve? Connecting to the container directly via the host port, or via your reverse-proxy? The /etc/hosts file should only be relevant if you are using DNS to identify the target container. – Rob Jul 03 '23 at 06:33
  • I'm trying to connect from container A to container B through the reverse-proxy (running in container C), using the publicly available url of container B. I've ran into the same problem with a Minio instance (file storage server). When uploading a file, my backend app can upload to `http://minio:9001` but then it sets the image's url in the database to `http://minio:9001/buckets/upload.jpg` which breaks when loading in the browser. If I use the public (proxy) url, `https://assets.site.com` to upload, communication between container fails, but the image would load in the browser. – parliament Jul 03 '23 at 09:12
  • shorted nginx config for the above mino server, `server { listen 443 ssl; server_name assets.site.com; location / { proxy_pass http://minio:9001 } }` Why can't containers connect to other containers using their public proxy urls, such as `mongo.site.com` or `assets.site.com`? The communication between containers only works with their internal docker networks like `mongo6:27017` and `minio:9001`. – parliament Jul 03 '23 at 09:18
  • Just to be sure, are you also setting `127.0.0.1` for your DNS entries (mongo.site.com, assets.site.com) in /etc/hosts? I cannot spot anything related to your docker services or these domains in the /etc/hosts file you provided in the original question. – Rob Jul 03 '23 at 10:41
  • My /etc/hosts is still as shown in OP, not much in it. To be clear I'm experiencing a similar problem locally, with any service that I run inside a docker container. My main "application container" can only reach those services using the docker names like `postgres:5432` but not `localhost:5432`.... `redis:6379` but not `localhost:6379`. In all cases, GUI apps like pgAdmin or redisUI, can connect to those same services using the `localhost` variant. Only the app running inside a container can't use `localhost`, must use the other container names. – parliament Jul 03 '23 at 11:05
  • Actually the situation above with localhost is proabably different and expected, given that due to loopback interface, localhost on any container will point to itself, not other containers. But in production I still dont see the issue, assets.site.com should be able to reach a specific container due to the proxy configuration. I don't know why it can't. – parliament Jul 03 '23 at 11:27
  • I agree that the reverse-proxy solution should work in production without messing with /etc/hosts. Assuming that the DNS of these domains points to your server, any requests to port 80/443 to this server should end up at your proxy (through port 80 or 443) and then be forwarded to your database container. If you want to use the ports of your host (through "localhost"), then you may need to [add a host network](https://stackoverflow.com/questions/24319662/from-inside-of-a-docker-container-how-do-i-connect-to-the-localhost-of-the-mach) to your docker-compose / container. Can you try this? – Rob Jul 03 '23 at 15:12
  • I've created a new question with some refined details around this problem. https://stackoverflow.com/q/76606848/1267778 please take a look, thank you. – parliament Jul 03 '23 at 17:04