Nginx proxy configuration for Strapi admin panel fails to serve assets at /cms/admin

System Information
  • Strapi Version: 5.1.0
  • Operating System: ubuntu
  • Database: postgres

Hi,

I’m trying to set up a Strapi backend alongside a React frontend using Nginx as a reverse proxy. The frontend is accessible at https://pel.example.org, and I want the Strapi admin panel to be accessible at https://pel.example.org/cms/admin. Everything seemed to be moving right until this point. The admin panel fails to load static assets, showing errors like (below) and also a blank white page.

https://pel.example.org/admin/strapi-DBHkT-2C.js net::ERR_ABORTED 404 (Not Found)

The assets seem to be requested at /admin/... instead of /cms/admin/....

My Setup

  • Frontend: React app running in a Docker container (frontend), accessible at https://pel.example.org.
  • Backend: Strapi app running in a Docker container (backend), intended to be accessible at https://pel.example.org/cms. The docker logs show that strapi starts successfully.
  • Nginx: Acts as the reverse proxy for both services.

Here’s my Nginx configuration and config/server.js file:

server {
    listen 80;
    listen [::]:80;

    server_name pel.example.org www.pel.example.org;
    server_tokens off;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://pel.example.org$request_uri;
    }
}

# HTTPS server
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;

    server_name pel.example.org;

    ssl_certificate /etc/nginx/ssl/live/pel.example.org/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/live/pel.example.org/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;

    # Frontend location
    location / {
        proxy_pass http://frontend:80;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /cms/admin {
        rewrite ^/cms/admin/(.*)$ /admin/$1 break;
        proxy_pass http://backend:1337/admin/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
    
    location /cms/ {
        rewrite ^/cms/?(.*)$ /$1 break;
        proxy_pass http://backend:1337/;
        proxy_http_version 1.1;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $http_host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_pass_request_headers on;
        
        client_max_body_size 100M;
        proxy_read_timeout 300;
        proxy_connect_timeout 300;
        proxy_send_timeout 300;
    }
}

Strapi server.js Configuration

module.exports = ({ env }) => ({
  host: env("HOST", "0.0.0.0"),
  port: env.int("PORT", 1337),
  url: 'https://pel.example.org/cms',
  app: {
    keys: env.array("APP_KEYS"),
  },
  webhooks: {
    populateRelations: env.bool("WEBHOOKS_POPULATE_RELATIONS", false),
  },
  transfer: {
    remote: {
      enabled: true,
    },
  },
});

What I’ve Tried

  1. I’ve ensured the admin panel is built by running npm run build inside the container.
  2. The frontend successfully accesses the backend’s assets at /cms.
  3. Checked for similar topics in the forums but none has helped.

Despite this, requests to https://pel.example.org/cms/admin fail due to missing static assets.

Questions

  1. How can I correctly configure Nginx to serve the Strapi admin panel at /cms/admin?
  2. Is there any additional configuration needed in Strapi’s server.js or elsewhere to handle /cms as a prefix?
  3. What could cause the assets to request paths like /admin/... instead of /cms/admin/...?

@DMehaffy @tgalle Any guidance would be appreciated. Thank you! :blush:

I was experiencing a similar issue with my deployment to Digital Ocean App Platform (which uses Nginx) and found I had set ‘Preserve Path Prefix’ to true. Disabling this feature restored expected functionality. Here’s a screenshot of the setting in DO:

Hopefully this will help point you in the right direction.