Skip to content

Default WordPress Vhost Template Breaks Media Uploads on Subfolder/Subdirectory Staging Sites #64

Description

@alaasalama

Issue Description:

The default WordPress Vhost template includes Nginx rewrite rules intended to support WordPress Multisite subdirectories. However, because these rules are applied globally inside the static files location block, they inadvertently intercept, rewrite, and break static assets (like newly uploaded images) on standard single-site instances that utilize a subfolder/subdirectory staging setup (e.g., domain.com/staging/).

Steps to Reproduce:

  1. Spin up a standard single-site WordPress instance on CloudPanel.
  2. Create a staging clone or a subfolder subdirectory named /staging/ within the root directory (/home/user/htdocs/domain.com/staging/).
  3. Log into the staging site's WordPress dashboard and upload a new image via the Media Library or Block Editor.
  4. The newly uploaded asset fails to render in the admin panel/editor and triggers a 404 Not Found error.

Root Cause Analysis:

The issue lies directly inside the static files location ~* regex block:

location ~* ^.+\.(css|js|jpg|jpeg|gif|png|ico|gz|svg|svgz|ttf|otf|woff|woff2|eot|mp4|ogg|ogv|webm|webp|zip|swf|map)$ {
  # WordPress Multisite Subdirectory
  rewrite ^/[_0-9a-zA-Z-]+(/wp-.*) $1 break;
  rewrite ^/[_0-9a-zA-Z-]+(/.*\.php)$ $1 break;
  ...
}

When an asset is requested from the staging subfolder (e.g., /staging/wp-content/uploads/image.webp), Nginx matches the extension, catches the /[_0-9a-zA-Z-]+ pattern (matching /staging), strips the prefix, and internally rewrites the request path to /wp-content/uploads/image.webp.

This forces Nginx to look for the asset in the live production site's directory structure instead of the staging subfolder. Since it is a newly uploaded image on staging, it does not exist on production, resulting in a 404.

Right now, I had to exclude the staging site's folder as a workaround:

  # WordPress Multisite Subdirectory (with staging/dev exclusions)
  rewrite ^/(?!staging|dev)[_0-9a-zA-Z-]+(/wp-.*) $1 break;
  rewrite ^/(?!staging|dev)[_0-9a-zA-Z-]+(/.*\.php)$ $1 break;

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions