I am using docker to create the postgresql database.
The installation guide isn’t detailed enough for me unfortunately, maybe because I am new to docker, and I may be missing something.
https://payloadcms.com/docs/production/deployment#docker
This is my docker-compose.yml:
version: '3'
services:
payload:
image: node:18-alpine
ports:
- '3000:3000'
volumes:
- .:/home/node/app
- node_modules:/home/node/app/node_modules
working_dir: /home/node/app/
command: sh -c "yarn install && yarn dev"
depends_on:
- mongo
- postgres
env_file:
- .env
mongo:
image: mongo:latest
ports:
- '27017:27017'
command:
- --storageEngine=wiredTiger
volumes:
- data:/data/db
logging:
driver: none
postgres:
image: postgres:latest
ports:
- '5432:5432'
environment:
POSTGRES_DB: ExperimentOne
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- pgdata:/var/lib/postgresql/data
logging:
driver: none
pgadmin:
image: dpage/pgadmin4
environment:
PGADMIN_DEFAULT_EMAIL: [email protected]
PGADMIN_DEFAULT_PASSWORD: admin
ports:
- "5050:80"
depends_on:
- postgres
volumes:
data:
node_modules:
pgdata:
This is my .env:
DATABASE_URI=postgres://user:[email protected]:5432/experimentOne
PAYLOAD_SECRET=1f9719d86d80cca708048d07
PAYLOAD_PUBLIC_SERVER_URL=http://localhost:3000
NEXT_PUBLIC_SERVER_URL=http://localhost:3000
I am quite certain that the password and username and ip address are correct, because I am using the same information to connect to the db using pgadmin. But the IP address inside docker is not always the same, so the last time I wanted to connect to pgadmin, I had to inspect the IP in docker using docker inspect [container_id].
PAYLOAD_SECRET
is probably wrong, it has been generated during the payload setup, and I do not know what this does, but I would guess this isn’t the problem.
If I try to open:
http://localhost:3000/admin
It is unable to connect:
ns_error_connection_refused
Any ideas?
I have tried to add variables to .env.
I am stuck because the error message isn’t helping.
UPDATE:
More images to help debug.
3
Answers
Change the IP address in your DATABASE_URI to postgres, the name of the service in Docker. Update it to:
This way, Docker handles the IP addresses internally.
If you’re unsure about the PAYLOAD_SECRET, just create a new random string and replace the old one.
Also, run docker-compose logs payload to see if there are any error messages when trying to start the Payload service. When you make the changes you can do:
And lastly make sure nothing else on your machine is using port 3000. If everything is set up correctly, you should be able to access it at http://localhost:3000/admin
A few things:
This is by design. You generally don’t want to use the private IP address that Docker assigns to a container, and instead make use of the hostname that Docker automatically creates for bridge networks.
As @Zerx pointed out, you would then refer to your Postgres URI as
postgres://user:password@postgres:5432/ExperimentOne
. Wherepostgres
is the name of the service as defined in your compose file.You are also missing a network block in your compose file. The network block should look something like this:
Then in your services add a
network
key for each service that you want to join the networkWhen troubleshooting network issues, there are two things to check. First, after your containers are started, inspect them using
docker inspect <container>
, and look at the networking output. Make sure that all of your containers are on the same named network. Containers can belong to multiple networks, but in order for two containers to communicate over a bridge network, they must both be part of it explicitly.Second, install the
nmap
tool inside of yourpayload
service (apk add nmap
), start both the postgres and payload containers, exec into the payload container, then check the results ofnmap postgres -p 5432
. If nmap reports the port as closed or unreachable, then the inter-container network communication is not set up properly.A few other suggestions:
then you can
docker compose exec payload bash
Temporarily remove the
command
section of your service definition. That way when you start the service (after adding the stdin and tty from above) you will just get a running alpine container that you can exec into. That will let you isolate the issue to network communication between that container and the postgres service, vs some other configuration that is causing the error.Don’t try upping everything at once. Start with just one service (payload), then add others one at a time (postgres, mongo, pgadmin).
While debugging, don’t disable the logging drivers. While it sounds like your postgres database is up and running, by suppressing log output you may be hiding errors.
You can use this in combination with a host-based development environment. If you run
then, since the
postgres
service declaresports:
, the database will be reachable from the host aslocalhost
(assuming you’re using Docker Desktop, or plain Docker on native Linux) on port 5432 (the first port number).Then in your host environment, you can run
From here, you’re using a totally normal Node/Yarn development environment, except that the database happens to be running in a container.
This setup doesn’t use the
payload
container, and you can delete it. It’s just attempting a very indirect route to try to run Node in a container but otherwise ignoring Docker’s image ecosystem; you’ll find it easier to directly run Node without Docker in most cases.