Fix 413 Request Entity Too Large in WordPress on Nginx

by Fahim

You drop your shiny new Envato theme zip into the WordPress admin, hit install, and get hit with a blank page and a raw 413 Request Entity Too Large error. No helpful WordPress warning—just Nginx slamming the door shut.

I ran straight into this last Tuesday setting up an e-commerce template on an Ubuntu 24.04 VPS with Nginx 1.26 and PHP 8.3-FPM. Here’s how to reconfigure Nginx, get PHP-FPM in sync, dodge sneaky disk buffer permission bugs, and install your theme without resorting to bloated plugins.

Linux terminal showing Nginx client_max_body_size configuration to resolve HTTP 413 error
Linux terminal showing Nginx client_max_body_size configuration to resolve HTTP 413 error

Why Envato Themes Trigger HTTP 413 on Default Nginx Stacks

Nginx ships with an out-of-the-box upload limit of exactly 1 megabyte via client_max_body_size. The second an incoming request body blows past 1MB, Nginx drops the connection immediately and serves its own static 413 error page. It won’t even pass the request to PHP.

Almost every multipurpose theme on ThemeForest runs between 20MB and 80MB. And if you grabbed the “All files & documentation” bundle instead of the install-only archive, you’re trying to send 150MB+ of licensing PDFs, Photoshop mockups, and dummy sliders through that tiny 1MB straw.

Drop a 45MB archive onto /wp-admin/theme-install.php, and Nginx catches the file header in its buffer, flags the payload size, and kills the transfer on the spot.

Here’s what that crash looks like inside /var/log/nginx/error.log:

2025/02/11 14:22:04 [error] 4812#4812: *143 client intended to send too large body: 46281720 bytes, client: 198.51.100.42, server: dev.example.com, request: "POST /wp-admin/update.php?action=upload-theme HTTP/2.0", host: "dev.example.com", referrer: "https://dev.example.com/wp-admin/theme-install.php?upload"

That 46,281,720 bytes is roughly 44.1MB. Because Nginx’s default roof was 1MB (1,048,576 bytes), WordPress never had a fighting chance to see the file.

Step 1: Check the Theme Archive Before Touching Server Configs

Before editing system files, double-check that you’re uploading the actual theme zip. ThemeForest gives you two download links: “All files & documentation” and “Installable WordPress file only”.

If you upload the full bundle, you’ll trigger the 413 error first. Then, once you raise the limit, WordPress will complain that style.css is missing because the theme is buried inside subfolders. If you’ve already hit that, check my fix for the missing style.css stylesheet error.

  1. Unpack the main zip on your local machine.
  2. Find the inner zip matching the actual theme name (something like theme-name.zip).
  3. Check its size. If it’s under 30MB, you’re ready to tweak your server configs.

Even stripped down, virtually all modern themes will exceed Nginx’s 1MB ceiling. Let’s fix the server.

Step 2: Update client_max_body_size in Nginx

The directive controlling this cap is client_max_body_size. According to the Nginx core module documentation, setting this to 0 turns off payload limits entirely. Don’t do that—leaving it uncapped exposes your server to basic denial-of-service memory exhaustion attacks.

Give yourself some breathing room with 64M or 128M. Open your site’s Nginx server block:

sudo nano /etc/nginx/sites-available/example.com

You can set client_max_body_size inside the http, server, or location blocks. Putting it inside the server block applies it cleanly to this WordPress site without loosening security on other virtual hosts:

server { listen 443 ssl http2; server_name dev.example.com; root /var/www/example.com/public_html; index index.php index.html; # Allow theme and media uploads up to 64 Megabytes client_max_body_size 64M; location / { try_files $uri $uri/ /index.php?$args; } location ~ .php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php8.3-fpm.sock; }
}

If you run multiple sites and want this applied globally, drop client_max_body_size 64M; right inside the http { ... } block in /etc/nginx/nginx.conf.

Always validate your config before restarting the daemon:

sudo nginx -t

If it returns syntax is ok and test is successful, reload Nginx without dropping existing connections:

sudo systemctl reload nginx

Step 3: Update PHP-FPM Upload Directives

Fixing Nginx clears the 413 roadblock, but if you stop here, your upload will hit PHP’s internal wall next. Instead of a clean install, WordPress will throw “The link you followed has expired” or a generic 500 error.

If you run into that blank or expired session screen right after updating Nginx, see my walkthrough on how to fix the link you followed has expired in WordPress.

PHP relies on two settings in php.ini: upload_max_filesize and post_max_size. The rule of thumb here is straight from the PHP core directives documentation: memory_limit ≥ post_max_size ≥ upload_max_filesize.

Find the php.ini powering your PHP-FPM pool. For PHP 8.3 on Ubuntu or Debian:

sudo nano /etc/php/8.3/fpm/php.ini

Update these values to match what you set in Nginx:

upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 256M
max_execution_time = 300
max_input_time = 300

Bumping max_execution_time to 300 seconds prevents PHP from killing worker threads while unzipping heavy archives and dumping assets onto disk. Save the file and restart PHP-FPM:

sudo systemctl restart php8.3-fpm

Confirm the new values landed by checking the CLI or opening the WordPress admin and heading to Tools → Site Health → Info → Server.

Step 4: Fix Client Body Temp Path Permissions

Here’s a subtle gotcha that bit me hard after raising the limits: Nginx buffers incoming payloads larger than client_body_buffer_size (usually 8k or 16k) out to temporary files in /var/lib/nginx/body. If the Nginx worker process doesn’t have write access to that folder, your upload fails with an HTTP 500 or another 413 error.

This regularly happens after package updates when Nginx workers run under www-data, but the temporary spool directory gets reset to root or nginx ownership.

Inspect your temp directory ownership:

ls -ld /var/lib/nginx/body

If the directory isn’t owned by your Nginx user (usually www-data on Debian/Ubuntu), fix it immediately:

sudo chown -R www-data:www-data /var/lib/nginx/body
sudo chmod 700 /var/lib/nginx/body

Also, if your distro drops temporary files in /tmp, make sure your PHP-FPM systemd service unit doesn’t have PrivateTmp=true enabled if your stack shares temp storage across daemons.

Step 5: Bypass the Browser Using WP-CLI

If you’re on a locked-down staging server or don’t feel like loosening server-wide upload caps for a single theme, skip the browser upload route entirely with WP-CLI.

Because WP-CLI runs locally over the command line via PHP CLI, it bypasses Nginx’s client_max_body_size and PHP-FPM’s upload_max_filesize limits. The WP-CLI theme install command reference covers the full syntax, but here’s the quick path.

Push the zip file directly to your server via SCP or SFTP:

scp ~/Downloads/my-envato-theme.zip user@dev.example.com:/tmp/

SSH into the machine and let WP-CLI handle the extraction and activation:

cd /var/www/example.com/public_html
wp theme install /tmp/my-envato-theme.zip --activate --allow-root

If a previous failed upload left behind an incomplete folder, WP-CLI will throw a collision error. If that happens, check our guide on how to fix the destination folder already exists error to wipe orphaned folders safely before retrying.

Step 6: Verify the Fix with a Fast cURL Command

Don’t wait around for a client call to find out if the upload works. You can test your server’s payload threshold in five seconds using curl right from your terminal.

Create a dummy 30MB payload file locally:

dd if=/dev/zero of=test-upload.bin bs=1M count=30

Post the mock file straight to your WordPress admin upload handler:

curl -I -X POST -F "themezip=@test-upload.bin" https://dev.example.com/wp-admin/theme-install.php?upload

Check the HTTP status in the response headers. If Nginx is still rejecting oversized requests, you’ll see this:

HTTP/2 413 server: nginx
date: Tue, 11 Feb 2025 14:35:10 GMT
content-type: text/html
content-length: 183

If your configuration worked, you’ll see an HTTP 302 redirect (WordPress bouncing unauthenticated requests to wp-login.php) or an HTTP 200. Once you see that, delete the dummy test file:

rm test-upload.bin

Now jump back into your dashboard, go to Appearance → Themes → Add New → Upload Theme, and drop in your theme zip. It’ll install without a hitch.

Frequently Asked Questions

Can I fix this error by editing .htaccess?

No. Nginx completely ignores Apache .htaccess files. Adding directives like php_value upload_max_filesize into .htaccess does nothing on an Nginx stack. Every upload rule must be configured inside your Nginx server blocks and your php.ini file.

Why am I still seeing a 413 error after changing Nginx and PHP?

If your DNS routes through Cloudflare, check their proxy limits. Cloudflare enforces a hard 100MB client request body cap on Free and Pro tiers. If your theme archive includes demo videos or raw PSD assets pushing it past 100MB, Cloudflare will throw its own 413 error page before the file ever hits your origin server. Unzip the package locally and upload only the installable theme archive.

What should I set client_max_body_size to for production?

Somewhere between 32M and 64M is the sweet spot. That’s plenty of overhead for modern themes and full-resolution WooCommerce product imagery, but tight enough to stop bad actors from exhausting server RAM with gigabyte-sized multi-part payloads.

Do I need to restart Nginx, or is a reload enough?

A reload (sudo systemctl reload nginx) is all you need. Reloading swaps in your new configuration and spawns fresh workers without interrupting active client connections. You only need a full restart when upgrading the Nginx binary or rebuilding compiled modules.

Next Steps

Once your theme is installed and active, you’ll probably want to run the demo content importer. Envato themes are notorious for choking on database execution times and memory during demo staging. If the installer stalls halfway through pulling demo XML or JSON media files, follow our guide on how to fix WordPress demo import timeout and memory errors on Envato themes to keep your PHP workers alive.

all_in_one_marketing_tool