✨ Strapi MCP is now Generally Available - let your agents manage your Strapi content ✨

EcosystemBeginner5 min read

"Refused to connect to http://localhost:1337/admin/init" after deploying Strapi

September 9, 2026
"Refused to connect to http://localhost:1337/admin/init" after deploying Strapi

You deploy Strapi to ECS, Render, Railway, a VPS, or a Docker host. https://cms.example.com serves the Strapi welcome page fine. You open https://cms.example.com/admin and get a blank screen with this in the browser console:

Refused to connect to 'http://localhost:1337/admin/init' because it does not
appear in the connect-src directive of the Content Security Policy.

Two things are going on, and only one of them is the actual bug.

What is actually happening

The Strapi admin panel is a static React bundle compiled at build time. When it runs in your browser, it needs to know which URL to send API requests to, and that URL is written into the JavaScript during strapi build. It is not read from the environment at runtime.

If strapi build ran without knowing your public URL, the bundle hardcodes the default http://localhost:1337. Your browser then loads the admin panel from https://cms.example.com and it immediately tries to call http://localhost:1337/admin/init, a machine that, from your browser's point of view, is your own laptop.

The CSP error is the symptom, not the cause. Strapi's security middleware sets a Content-Security-Policy that only permits connections back to itself, so the browser blocks the cross-origin call to localhost and reports it as a CSP violation. Adding localhost:1337 to your CSP would silence the error and change nothing, because the request would still go nowhere.

The fix is to tell Strapi its public URL and rebuild the admin panel.

The fix

1. Set the public URL

In config/server:

export default ({ env }) => ({
  host: env('HOST', '0.0.0.0'),
  port: env.int('PORT', 1337),
  url: env('PUBLIC_URL', 'http://localhost:1337'),
  app: {
    keys: env.array('APP_KEYS'),
  },
});

And in your deployed environment:

PUBLIC_URL=https://cms.example.com

Note host: '0.0.0.0', not localhost. Inside a container, binding to localhost means the process only accepts connections from inside that container, so the health check fails and the proxy gets connection refused. This is a separate, equally common deployment mistake.

2. Rebuild the admin panel with that variable present

This is the step people miss:

NODE_ENV=production PUBLIC_URL=https://cms.example.com npm run build
NODE_ENV=production npm run start

PUBLIC_URL must be set during the build, not only when the server starts. Setting it at runtime alone changes nothing, because the bundle was already compiled with the old value.

In a Dockerfile:

ARG PUBLIC_URL
ENV PUBLIC_URL=${PUBLIC_URL}
ENV NODE_ENV=production

RUN npm run build

CMD ["npm", "run", "start"]

Pass it in at build time:

docker build --build-arg PUBLIC_URL=https://cms.example.com -t my-strapi .

In the original forum thread, the poster's Dockerfile was starting Strapi without ever running npm run build in the image. Adding the build step resolved it, which is exactly this problem: the running container was serving a stale admin bundle built with default values.

3. Check config/admin if the admin lives elsewhere

By default the admin panel is served at /admin on the same host. If you serve it from a different path or a different domain, set it explicitly:

export default ({ env }) => ({
  url: env('ADMIN_URL', '/admin'),
  auth: {
    secret: env('ADMIN_JWT_SECRET'),
  },
});

Changing anything under config/server or config/admin requires a rebuild. The docs are explicit about this: "Changes to the server.js file require rebuilding the admin panel."

The other cause: a port mismatch

The second reply in the original thread hit a different version of the same problem. The PORT environment variable was set to something (8080, or 80), but the admin bundle had been built expecting 1337, so the UI was served on one port while its API calls went to another.

Keep them consistent. If your platform injects a PORT variable, as Heroku, Cloud Run, Render, and Railway all do, read it rather than hardcoding:

port: env.int('PORT', 1337),

And set url to the public URL your users hit, which is usually port 443 with no port in the string, not the internal port the container listens on. Those two values are different things and conflating them is a frequent source of this exact error.

When you genuinely do need to touch CSP

Adding hosts to connect-src is the right move when the admin panel legitimately needs to talk to another origin, most commonly a third-party media provider, where images and videos are served from S3 or Cloudinary rather than from Strapi:

export default [
  'strapi::logger',
  'strapi::errors',
  {
    name: 'strapi::security',
    config: {
      contentSecurityPolicy: {
        useDefaults: true,
        directives: {
          'connect-src': ["'self'", 'https:'],
          'img-src': ["'self'", 'data:', 'blob:', 'market-assets.strapi.io', 'my-bucket.s3.eu-west-1.amazonaws.com'],
          'media-src': ["'self'", 'data:', 'blob:', 'market-assets.strapi.io', 'my-bucket.s3.eu-west-1.amazonaws.com'],
          upgradeInsecureRequests: null,
        },
      },
    },
  },
  'strapi::cors',
  'strapi::poweredBy',
  'strapi::query',
  'strapi::body',
  'strapi::session',
  'strapi::favicon',
  'strapi::public',
];

Keep market-assets.strapi.io, which is a default that the in-app Marketplace needs.

Deployment checklist

  1. host is 0.0.0.0, not localhost.
  2. port reads from env.int('PORT', 1337).
  3. url in config/server is your public HTTPS URL.
  4. That variable is present during strapi build, not just at runtime.
  5. NODE_ENV=production is set for both build and start.
  6. The image or release artifact actually contains a fresh admin build.
  7. If you are behind a reverse proxy, set proxy.koa: true in config/server.
  8. Verify the server is up independently of the admin panel: curl -I https://cms.example.com/_health should return 204.

Further reading

Theodore Kelechukwu OnyejiakuDevRel and Community | Software Developer | Technical Writer

Theodore is a Technical Writer and a full-stack software developer. He loves writing technical articles, building solutions, and sharing his expertise.

"Cannot destructure property 'client' of 'db.config.connection'" in Strapi
EcosystemIntermediate·6 min read

"Cannot destructure property 'client' of 'db.config.connection'" in Strapi

This error means Strapi loaded no database configuration at all. The file is missing from the build, excluded from the container, or never compiled.

·September 9, 2026
"Cannot send secure cookie over unencrypted connection" in Strapi
EcosystemAdvanced·6 min read

"Cannot send secure cookie over unencrypted connection" in Strapi

Your site is on HTTPS but Strapi thinks the request came over HTTP. The fix is one config key, proxy.koa, plus the proxy headers that make it work.

·September 9, 2026
"Strapi is in production mode" when you are running development mode
EcosystemBeginner·5 min read

"Strapi is in production mode" When you are Running Development Mode

The Content-Type Builder is disabled and Strapi claims production, but your terminal says development. The rule Strapi actually applies, and the fix.

·September 9, 2026