Env setup for production and local development

@DMehaffy

Can we run simultaneously two separate instances, one for production, the other for development on separate ports? I would like to have a setup like this:

  • production instance running uninterrupted with pm2
  • development instance running on demand on localhost

Is it possible?

Yes, I see no reason why not?

1 Like

Actually, you could also do:

  • Production instance running uninterrupted with pm2
    and
  • Development instance running uninterrupted with pm2

Here how I would do it let me know if I’m wrong.

  1. Configure NGINX on 2 different subdomains.
  2. Deploy a Strapi project in the folder …/MyProd
  3. Deploy another strapi project in another folder …/MyDev
  4. Build both projects
  5. The configure PM2 to start your project automatically

Then you got both development and production live.
But can you do it with 2 subdomains, pointing to the same source code …/MyProd ?
Maybe this is a nodjs question, Can Node execute 2 different processes pointing to the same code…

This question was in fact answered here:

… because running 2 instances, development and production, is the same as running 2 instances of the same code.

When I tried to configure both subdomain (dev&prod) pointing to the same source code it didn’t work. It was only taking one configuration either prod or Dev and I couldn’t figure out or to make it work. That’s why I was asking the question. Perhaps there is a guide somewhere explaining how to configure this?

You may want to read this post, Using a prefix for strapi routes.

The point is to isolate the routes, administration route vs production route (access for regular users). This can be done by customizing the server.js config file something like this:

// modified server config
module.exports = ({ env }) => ({
  host: env('HOST', '0.0.0.0'),
  port: env.int('PORT', 1337),
  url: "https://prod.domain.com/api", 
  admin: {
    url: "https://dev.domain.com/api", 
    auth: {
      secret: env('ADMIN_JWT_SECRET', 'replaced'),
    },
  },
});

Then you need to start both dev and prod instances with pm2.

1 Like

You shouldn’t set the admin url to the same as the normal url. (this url key either needs to be a full path to the admin or a relative that will be used with the normal url key).

We also don’t currently support binding the admin to the root.

My bad, I didn’t pay atention when I wrote, it should be like this:

// modified server config
module.exports = ({ env }) => ({
  host: env('HOST', '0.0.0.0'),
  port: env.int('PORT', 1337),
  url: "https://prod.domain.com/api", 
  admin: {
    url: "https://dev.domain.com/admin", 
    auth: {
      secret: env('ADMIN_JWT_SECRET', 'replaced'),
    },
  },
});

I was concentrated to use subdomains, the preference of @pm74. My own preference is like this:

// modified server config
module.exports = ({ env }) => ({
  host: env('HOST', '0.0.0.0'),
  port: env.int('PORT', 1337),
  url: "https://domain.com/api", 
  admin: {
    url: "https://domain.com/admin", 
    auth: {
      secret: env('ADMIN_JWT_SECRET', 'replaced'),
    },
  },
});

Generally speaking (given I wrote the proxy documentation: Deployment | Strapi Developer Documentation ) I would suggest to avoid the sub-folder proxying where possible and opt to use subdomains only.

Combining the two can result in a fairly complex proxy structure. Also splitting your Admin vs endpoint urls also could be quite confusing :thinking:

What I usually suggest is define your prod, stag, dev (you don’t usually deploy dev) infra scopes and keep them seperate:

  • Dev => Local based
  • Staging => As close to prod as possible but does not overlap
  • Prod => Least “breaking” as possible, goal is uptime and stability.

As an example on my own hobby project: GitHub - canonn-science/CAPIv2-Strapi: Canonn APIv2

I have 4 environments:

Given my project is not narrowly scoped to only accept requests from my own applications but is ran as a public API (video game: Elite Dangerous). My staging is designed to be used by people who want to test and don’t care about errors, typically external developers. Rate limits are much more lax here and permissions are a bit less restricted.

Subdomains are used to create isolated parts of an application stack, this is done to make it clear they are a separate service. And you should have as little overlap as possible between staging and production to minimize risks of pollution. In my case the user sync between prod and staging is one way. Production users get synced to staging, never in the reverse.

1 Like

Ok, I’m very lost and my configuration is not working at all. Once I put both my dev and prod env to automatically start in PM2, I get no access to create new content even connected with the superuser.
My understanding is that it thinks it is in production mode and that’s why it’s not letting me do it. It will not allow creating anything through Content Builder.

Below my configuration, and I will now try you configuration to see if it works any better.

module.exports = {
       apps: [{
           name: 'strapiProd',
           cwd: '/mnt/data/strapi/Prod',
           script: 'npm',
           args: 'start',
           env: {
             NODE_ENV: 'production',
             DATABASE_HOST: 'localhost', // database endpoint
             DATABASE_PORT: '3306',
             DATABASE_NAME: '', // DB name
             DATABASE_USERNAME: 'strapi', // your username for psql
             DATABASE_PASSWORD: '', // your password for psql
           },
         },{
           name: 'strapiDev',
           cwd: '/mnt/data/strapi/dev',
           script: 'npm',
           args: 'start',
           env: {
             NODE_ENV: 'development',
             DATABASE_HOST: 'localhost', // database endpoint
             DATABASE_PORT: '3306',
             DATABASE_NAME: '', // DB name
             DATABASE_USERNAME: '', // your username for psql
             DATABASE_PASSWORD: '', // your password for psql
           },
         },
       ],
     };

~

This is my upstream conf

/etc/nginx/conf.d/upstream.conf

Strapi server

upstream strapiProd{
server 127.0.0.1:1337;
}
upstream strapiDev{
server 127.0.0.1:1338;
}

You will need to set the permissions in production as well as dev/staging, those are stored in the database and aren’t in source control.

Can you give some examples? Because this sounds like a bug but it depends on what you mean.

First, thank you for the details. Regarding the opt for subdomains, as you said… where possible! From my point of view this opt is not quite an option, mostly the type of the project dictates what is should be!

Yes, not easy task, but again, in my case not splitting is not an option! Imagine an eCommerce site, letting the admin endpoint be publicly accessible would attract a huge volume of spam (scanners, bots, etc.). Moreover, I consider that the access to the Strapi administration panel is poorly protected. This is also the main reason why I split access and restrict ip based in the Nginx configuration, as follows:

// nginx (inside isolated admin location)
location /admin {
    Allow 123.123.123.123;
    Deny All;
    ...
}

I’m logged in with the super user and cannot create content, the server things I’m in Production mode.
If I do yarn develop it works, but I cannot get it to work with my above mentioned configuration.

Which permission are you talking about here?

Ah alright this isn’t RBAC then this is normal Strapi default. We forcefully disable the CTB (Content-Type builder) in Production and Staging. Even in development mode it will only be enabled under a very specific set of circumstances:

  • You must be using the NODE_ENV=development (the default env)
  • You must be using the strapi develop command (or yarn develop / npm run develop)
  • You cannot use a server.js file with the start syntax
  • You cannot use the CTB in any other environment

For reasons why I’ll lead you to this FAQ entry: Troubleshooting | Strapi Developer Documentation

But will post it here also:


Strapi stores model configuration files (what defines the model schema) in files such as api/restaurant/models/restaurant.settings.json. Due to how Node.js works, in order for changes to take effect, that would require Node to restart the server. This could potentially cause downtime of your production service and likewise these changes should be tracked in some kind of source control.

Generally your “flow” of development would follow the following path:

  • Development - Develop your Strapi application locally on your host machine, then push changes into source control
  • Staging - Deploy changes from source control to a “production-like” environment for testing
  • Production - If no other changes are needed, deploy into production
  • Repeat as needed, it is recommended that you properly version and test your application as you go

At this time and in the future there is no plan to allow model creating or updating while in a production environment, and there is currently no plans to move model settings into the database. There is no known nor recommended workarounds for this.

1 Like

When I make changes to server.js I always rebuild the admin panel, by erasing the cache and build folders and by running npm run build -- --clean. See docs…

1 Like

It would yes just as it does on most applications, security through obscurity helps with automated bots that aren’t aware of your work-around but they don’t prevent humans from digging (as someone who does as a hobby to submit CVEs or bug reports to services :wink: )

Do you have some examples?

This is certainly a good policy, I’ll say it’s a tad overkill but is very effective. Honestly you can deploy Strapi without the admin panel entirely and simply serve it say inside of an intranet so long as it can reach the backend API then there is no real risk.

(Sorry to both of you btw, there is kinda 2 convos going on here)

1 Like

Thank you very much.
If I understand correctly I cannot configure strapi to automatically run with PM2 at boot time in development mode?
When I want to use CTB I must start my dev node with strapi develop from the command line?