Docker install/setup - Invalid database host error

Hello,
I’m running into a situation that I’m not quite understanding. I have attempted to deploy Ghost on a test machine successfully and a live production machine unsuccessfully, both with very similar Docker compose files. The error I am getting on the live production server is this:

[2023-05-15 09:05:22] ERROR Invalid database host.
ghost-ghost-1 |
ghost-ghost-1 | Invalid database host.
ghost-ghost-1 |
ghost-ghost-1 | “Please double check your database config.”
ghost-ghost-1 |
ghost-ghost-1 | Error ID:
ghost-ghost-1 | 500
ghost-ghost-1 |
ghost-ghost-1 | Error Code:
ghost-ghost-1 | ENOTFOUND
ghost-ghost-1 |
ghost-ghost-1 | ----------------------------------------
ghost-ghost-1 |
ghost-ghost-1 | Error: getaddrinfo ENOTFOUND db

Both servers are self-hosted.
Here is the Docker compose file of my working test machine that I used from Ghost’s web site:

version: '3.1'

services:

  ghost:
    image: ghost:latest
    restart: always
    ports:
      - 8080:2368
    environment:
      # see https://ghost.org/docs/config/#configuration-options
      database__client: mysql
      database__connection__host: db
      database__connection__user: root
      database__connection__password: example
      database__connection__database: ghost
      # this url value is just an example, and is likely wrong for your environment!
      url: http://<myserveripaddress>:8080
      # contrary to the default mentioned in the linked documentation, this image defaults to NODE_ENV=production (so development mode needs to be explicitly specified if desired)
      #NODE_ENV: development

  db:
    image: mysql:8.0
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: example

Here is the Docker compose file from my live production server that is giving me the error:

version: '3.1'

services:

  ghost:
    image: ghost:latest
    restart: always
    ports:
      - 8080:2368
    volumes:
      - /path/to/docker/ghost/content:/var/lib/ghost/content
    environment:
      # see https://ghost.org/docs/config/#configuration-options
      database__client: mysql
      database__connection__host: db
      database__connection__user: root
      database__connection__password: mypassword
      database__connection__database: ghost
      # this url value is just an example, and is likely wrong for your environment!
      url: https://www.mydomain.info
      # contrary to the default mentioned in the linked documentation, this image defaults to NODE_ENV=production (so development mode needs to be explicitly specified if desired)
      #NODE_ENV: development

  db:
    image: mysql:8.0
    restart: always
    volumes:
      - /path/to/docker/ghost/mysql:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: mypassword

The only things I changed in the production compose file was adding the volumes and changing the URL to point to my public domain.
What am I doing wrong? It has to be the volumes, right? Perhaps permissions issue since it seems it is having difficulty finding or connecting to the database? Ports need to be defined?
Thanks in advance for any assistance. This issue, for some reason, is knocking me for a loop. I have found similar threads on the same error but none using Docker or Docker compose file.

Update: I’ve tried a number of combinations - removing the volumes, adding MySQL ports, etc. - and nothing has changed. I’m still unable to deploy the latest Ghost with the latest MySQL.
Here is my latest compose file attempt:

version: '3.1'

services:

  ghost:
    image: ghost:latest
    restart: always
    ports:
      - 8080:2368
    volumes:
      - /path/to/docker/ghost/content:/var/lib/ghost/content
    environment:
      # see https://ghost.org/docs/config/#configuration-options
      database__client: mysql
      database__connection__host: db
      database__connection__user: root
      database__connection__password: mystrongpassword
      database__connection__database: ghost
      # this url value is just an example, and is likely wrong for your environment!
      url: https://www.mydomain.info
      # contrary to the default mentioned in the linked documentation, this image defaults to NODE_ENV=production (so development mode needs to be explicitly specified if desired)
      #NODE_ENV: development

  db:
    image: mysql:latest
    restart: always
    volumes:
      - /path/to/docker/ghost/mysql:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: mystongpassword
      MYSQL_DATABASE: ghost
      MYSQL_USER: ghostuser
      MYSQL_PASSWORD: mystongpassword

Here is a portion of the log that is repeating I am now seeing with this latest attempt (some sensitive data edited):

ghost-db-1 | 2023-05-16 10:09:03+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.33-1.el8 started.
ghost-db-1 | 2023-05-16 10:09:03+00:00 [Note] [Entrypoint]: Switching to dedicated user ‘mysql’
ghost-db-1 | 2023-05-16 10:09:03+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.33-1.el8 started.
ghost-db-1 | 2023-05-16 10:09:04+00:00 [ERROR] [Entrypoint]: Database is uninitialized and password option is not specified
ghost-db-1 | You need to specify one of the following as an environment variable:
ghost-db-1 | - MYSQL_ROOT_PASSWORD
ghost-db-1 | - MYSQL_ALLOW_EMPTY_PASSWORD
ghost-db-1 | - MYSQL_RANDOM_ROOT_PASSWORD
ghost-db-1 exited with code 1
ghost-ghost-1 | [2023-05-16 10:09:04] INFO Ghost is running in production…
ghost-ghost-1 | [2023-05-16 10:09:04] INFO Your site is now available on https://www.mypublicdomain.info/
ghost-ghost-1 | [2023-05-16 10:09:04] INFO Ctrl+C to shut down
ghost-ghost-1 | [2023-05-16 10:09:04] INFO Ghost server started in 1.162s
ghost-db-1 | 2023-05-16 10:09:04+00:00 [Note] [Entrypoint]: Switching to dedicated user ‘mysql’
ghost-db-1 | 2023-05-16 10:09:04+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.33-1.el8 started.
ghost-ghost-1 | [2023-05-16 10:09:05] ERROR connect ECONNREFUSED 172.18.0.3:3306
ghost-ghost-1 |
ghost-ghost-1 | connect ECONNREFUSED 172.18.0.3:3306
ghost-ghost-1 |
ghost-ghost-1 | “Unknown database error”
ghost-ghost-1 |
ghost-ghost-1 | Error ID:
ghost-ghost-1 | 500
ghost-ghost-1 |
ghost-ghost-1 | Error Code:
ghost-ghost-1 | ECONNREFUSED
ghost-ghost-1 |
ghost-ghost-1 | ----------------------------------------
ghost-ghost-1 |
ghost-ghost-1 | Error: connect ECONNREFUSED 172.18.0.3:3306
ghost-ghost-1 | at /var/lib/ghost/versions/5.47.2/node_modules/knex-migrator/lib/database.js:57:19
ghost-ghost-1 | at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1278:16)
ghost-ghost-1 |
ghost-ghost-1 | [2023-05-16 10:09:05] WARN Ghost is shutting down
ghost-ghost-1 | [2023-05-16 10:09:05] WARN Ghost has shut down
ghost-ghost-1 | [2023-05-16 10:09:05] WARN Your site is now offline
ghost-ghost-1 | [2023-05-16 10:09:05] WARN Ghost was running for a few seconds

You used the mysql:latest image in production but mysql:8 in testing. Make it exactly the same in production (mysql:8) to eliminate that difference as a source of possible errors.

Well, I tried it both ways and actually found that the image is the exact same. Both times still the same error.

Docker has benefits, but is definitely more complicated to host and introduces a new layer where new an additional category of bugs and misconfigurations can be introduced.

While I support containers professionally at work, I have no regrets about using the officially supported non-containerized install method for my personal Ghost blogs.

I’ll take that into consideration, for sure. And, it actually had crossed my mind.
Thanks.

I’ve made some progress and now have a MySQL container up and running without fault. However, now it seems the Ghost container is having issues connecting to the database with the designated user. Here is my updated Docker compose file:

version: '3.8'

services:

  ghost:
    image: ghost:latest
    restart: always
    ports:
      - 8080:2368
    depends_on:
      - db
    volumes:
      - /path/to/docker/ghost/content:/var/lib/ghost/content
    environment:
      database__client: mysql
      database__connection__host: db
      database__connection__user: ghostuser
      database__connection__password: mystrongpassword
      database__connection__database: ghostdb
      # this url value is just an example, and is likely wrong for your environment!
      url: https://www.mypublicdomain.info

  db:
    image: mysql:latest
    restart: always
    ports:
      - 3306:3306
    volumes:
      - /path/to/docker/ghost/mysql:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=mystrongpassword
      - MYSQL_DATABASE=ghostdb
      - MYSQL_USER=ghostuser
      - MYSQL_PASSWORD=mystrongpassword

Here is the error I am not getting from Ghost in the Docker compose logs:

ghost-ghost-1 | [2023-05-17 09:19:15] ERROR Access denied for user ‘ghostuser’@‘172.18.0.3’ (using password: NO)
ghost-ghost-1 |
ghost-ghost-1 | Access denied for user ‘ghostuser’@‘172.18.0.3’ (using password: NO)
ghost-ghost-1 |
ghost-ghost-1 | “Unknown database error”
ghost-ghost-1 |
ghost-ghost-1 | Error ID:
ghost-ghost-1 | 500
ghost-ghost-1 |
ghost-ghost-1 | Error Code:
ghost-ghost-1 | ER_ACCESS_DENIED_ERROR
ghost-ghost-1 |
ghost-ghost-1 | ----------------------------------------
ghost-ghost-1 |
ghost-ghost-1 | Error: Access denied for user ‘ghostuser’@‘172.18.0.3’ (using password: NO)

Anyone have any idea why Ghost is now complaining about the user?

Nothing in your MySQL configuration grants access to ghostuser@172.18.0.3.

So this section of Ghost

database__connection__user: ghostuser
database__connection__password: mystrongpassword

And this section of MySQL


- MYSQL_USER=ghostuser
- MYSQL_PASSWORD=mystrongpassword

Not grant the access?

The variables in the Ghost container just tell it where to find the database. Setting variables in Ghost can’t force MySQL to give it access.

As for the environment variables you set in the mysql:8 container, you’ll have to read the documentation or the source code of the container to see how it works, but my expectation is that the container may grant access to those users from localhost, but it would be bad security to grant wide open access from any host by default.

Just a hunch here: when I first setup my Docker environment with Ghost, I ran into a similar issue.

My problem was that I used a password for the MySQL user that container lots of special characters. These led to the password string not being interpreted correctly.

I ended up wrapping all environment variables in my docker-compose.yml in “quotes”, which solved the issue:

      database__client: mysql
      database__connection__host: ${url}-mysql
      database__connection__user: "mysql-user"
      database__connection__password: "strongpassword"
      database__connection__database: "db"
      database__connection__port: "3306"

Additionally, as you can see, I am explicitly setting the port to 3306, but I just tried and it also works without. So, my best guess is that there could be a special character in your password that is breaking.

@jannis You nailed it. That was the issue. I was able to get it working with this:

version: '3.8'

services:

  ghost:
    image: ghost:latest
    restart: always
    ports:
      - 8080:2368
    depends_on:
      - db
    volumes:
      - /path/to/docker/ghost/content:/var/lib/ghost/content
    environment:
      database__client: mysql
      database__connection__host: db
      database__connection__user: "ghostuser"
      database__connection__password: "mystrongpassword"
      database__connection__database: "ghostdb"
      # this url value is just an example, and is likely wrong for your environment!
      url: https://www.mypublicdomain.info

  db:
    image: mysql:latest
    restart: always
    ports:
      - 3306:3306
    volumes:
      - /path/to/docker/ghost/mysql:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=mystrongpassword
      - MYSQL_DATABASE=ghostdb
      - MYSQL_USER=ghostuser
      - MYSQL_PASSWORD=mystrongpassword

Thanks so much for your assistance, @jannis

1 Like

In my case it is not enough storage on the filesystem. I have 20GB but I think there is some limit in ghost regarding percentage of space left.

I had this issue once before, unfortunately with so many other services I had to re-learn it all again. Would be nice to see this requirement in the documentation and/or if error reporting were more accurate as it kept giving me a db authentication error making me investigate entirely different set of components.