Config/env/production is not considered when NODE_ENV=production

System Information
  • Strapi Version: 4.10.5
  • Operating System: Some Ubuntu on Digital Ocean App platform, can’t really tell
  • Database: PostgreSQL v15 database cluster
  • Node Version: v17.9.1
  • NPM Version: v8.11.0
  • Yarn Version: -

Hi Strapi Team!

I followed the official docs on deploying Strapi to DigitalOcean, but I’ve run into this problem:

Error: self-signed certificate in certificate chain

I eventually figured out why this was happening after adding some console logs to my config files. It turns out that the production config files are not being read, which produces the above error.

The documentation above tells you to create a file: config/env/production/database.ts I created this file and also added a console log to it console.log('production config file loaded');.

I also added a console log to the main config file, which gets merged with every other environment-specific config file:

console.log('final configuration', connections[client]);
console.log('final configuration', connections[client].connection);

Here you can see what happens when the deployment runs.

Another documentation page states, Everything defined in the production configuration will override the default configuration. but the production config is not being processed at all. NODE_ENV is defined as an App-Level environment variable.

Since this is such a basic functionality, I’m sure I missed something trivial.

I appreciate any input!


These two links should help you:

1 Like

Thanks, @pierreburgy. I could technically remove everything from config/database.js and just put there my production config, but my issue is that the config file config/env/production/database.js is not being processed.

It already has the correct SSL options (suggested in the post you shared) "ssl": { "rejectUnauthorized": false }. Here’s what the file looks like:

But as you can see, I don’t see this console.log in the logs neither this object appears in the final configuration (log my first post)

If you have files in both ‘config’ and ‘config/env/production’, I believe only the former will get processed. I avoided this by moving all my config files into ‘config/env/development’, and then copying the ones that I wanted to be common to production into the ‘config/env/production’ folder - along with those specific to production. It does seem better, even if there’s duplication of files, because you can see the whole config for a given environment in one place. Messier to maintain, though, if there’s more shared than different.

1 Like

Thanks for sharing your workflow!
I just tested this with a simple console log. Both are processed in this order:

  1. config/database
  2. config/env/production/database

so the app platform ends up processing the

ssl: {
  rejectUnauthorized: false,

so I’ve run out of ideas why I’m still getting this error.

Where do you run “console.log(‘final configuration’, connections[client]);”?

I made a video for you: Loom | Free Screen & Video Recording Software | Loom

Thanks for this great video. I wasn’t aware of this register function.

In the meantime, I figured out a couple of things too.

config/database always run before config/env/production/database.

I had the console.log(‘final configuration’, connections[client]); in the config/database file, so that’s the reason why it was always printing the default values.

After realizing this, I put a console log into the config/env/production/database files as well, and that had the correct configuration:

Above I’m logging the entire connection object and inside that connection.ssl to make sure it’s set to { rejectUnauthorized: false }

I also tried:

  • downgrading pg to version 7
  • using ssl: { ca: env('DATABASE_CA') } - with the right certificate set, this was visible in the logs too
  • using ssl: { ca: env('DATABASE_CA'), rejectUnauthorized: false }

But none of these worked. I also tried various combinations of these in the 36 deployments that I did.

If you think logging in the register callback has the potential to show us something we don’t know, I could set up the entire stack again and give it another shot.

What is the output of


if you add these two lines in the register function of the src/index.ts file?

It appears that if you set ‘rejectUnauthorized’ to ‘true’ but don’t provide a valid certificate chain then you get this cryptic error from pg. Have you tried creating a self-signed certificate and providing that as both the ‘server’ and ‘root’. Here’s an example from the pg docs:

Apologies … You’re trying to set rejectUnauthorized to ‘false’, but isn’t that the default if you have no ‘ssl’ key in the config object?

I ended up not going down this route, not only because of the deployment issues but because of the cost of running all this:

  • DigitalOcean App Component (Basic instance with 2GB RAM, Strapi recommended minimum) $20/mo
  • Managed DB - starting at $15/mo
  • Spaces - $5/mo

This is $40/mo.

The cheapest droplet with 2GB / 50GB Disk space (the faster one, Premium Intel) is $14/mo.

After solving some minor hiccups in the docker deployment, I could start Strapi with docker-compose.

1 Like