Back to tutorials
Tutorial

Nginx 413 Request Entity Too Large Fix On VPS

Fix Nginx 413 error on a VPS by raising safe Nginx/PHP upload limits and verifying large uploads without timeouts.

By Anurag Singh
Updated on Nov 02, 2026
Category: Tutorial
Share article
Nginx 413 Request Entity Too Large Fix On VPS

A 413 error means your reverse proxy rejected the upload before your app (WordPress, phpMyAdmin, a custom API) ever saw it. In many cases, the fix Nginx 413 error is one directive.

The catch is that raising only that limit can still fail later. PHP size caps, upstream timeouts, or a full disk can stop the upload midstream.

This guide gives you a production-safe workflow on a VPS.

You’ll raise Nginx’s request-body limit, align PHP-FPM settings, and validate with repeatable tests. You’ll also avoid two common follow-up problems: memory pressure and timeouts that turn into 502/504s.

What 413 means (and how to confirm it’s Nginx)

Nginx returns 413 Request Entity Too Large when the request body exceeds what it allows. The setting that controls this is client_max_body_size.

Before you change configs, confirm the 413 is actually coming from Nginx. It may be coming from a CDN, load balancer, or an app gateway instead.

On your VPS, start here:

sudo nginx -v
sudo systemctl status nginx --no-pager

Reproduce the error once (try the upload again). Then check logs:

# Ubuntu/Debian default paths
sudo tail -n 50 /var/log/nginx/error.log
sudo tail -n 50 /var/log/nginx/access.log

A typical Nginx 413 entry looks like this:

client intended to send too large body: 15728640 bytes, client: 203.0.113.10, server: example.com, request: "POST /wp-admin/async-upload.php HTTP/2.0"

If you see that line, you’ve found the right knob to turn.

If you don’t see it, keep going anyway. After you lift size limits, timeouts often become the next bottleneck.

This is especially common when the failure changes to a 502/504 later.

Fix Nginx 413 error by setting client_max_body_size

You can set client_max_body_size at three levels: http (global), server (per site), or location (per path).

For most VPS setups, per-site (inside the domain’s server {}) is the safest default.

Set a limit you actually need. If you upload 200MB videos, set 256M. If you occasionally import WordPress backups, 128M is usually plenty.

Don’t crank it up “just in case.” Large bodies increase temp-file pressure and widen the blast radius of abusive requests.

Step 1: Find your active site config

On Ubuntu/Debian, you’ll usually have:

ls -la /etc/nginx/sites-available
ls -la /etc/nginx/sites-enabled

Find the server block for your domain (example: /etc/nginx/sites-available/example.com).

On AlmaLinux/Rocky, virtual hosts are often pulled in from includes.

Use this to see what Nginx is actually loading:

sudo nginx -T | sed -n '1,140p'

nginx -T prints the full active config and shows each file included.

Step 2: Add (or raise) client_max_body_size

Edit the site config. Here’s a common example:

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

Add the directive inside the correct server block. Don’t put it above the block or outside braces.

server {
    # ... your existing config

    client_max_body_size 128M;

    # ... the rest
}

This applies whether you’re proxying to PHP-FPM or to an upstream app (Node/Python/etc.).

Step 3: Validate and reload Nginx

sudo nginx -t
sudo systemctl reload nginx

If nginx -t fails, stop there.

Fix the syntax error first, then reload.

Verify: confirm the directive is active

Nginx doesn’t provide a clean “effective settings for this one vhost” view.

Still, you can confirm the loaded config includes your directive:

sudo nginx -T | grep -n "client_max_body_size" -n

Try the upload again.

If the 413 is gone but the upload still fails, you’re likely hitting PHP limits or timeouts. Handle those next.

Align PHP-FPM upload and post limits (WordPress, PHP apps)

If you run PHP (WordPress, Laravel, phpMyAdmin), Nginx accepting the request is only step one.

PHP enforces its own ceilings:

  • upload_max_filesize – max size of a single uploaded file
  • post_max_size – max size of the entire POST body (must be bigger than upload_max_filesize)
  • memory_limit – too low can kill imports/unzips; too high can OOM your VPS
  • max_execution_time / max_input_time – large imports can hit these

Step 1: Identify your PHP version and FPM service

php -v

List PHP-FPM services (common names):

sudo systemctl list-units --type=service | grep -E "php.*fpm"

On Ubuntu/Debian you’ll typically see php8.3-fpm or php8.4-fpm in 2026.

Step 2: Edit the correct php.ini for FPM

Make changes in the FPM ini, not the CLI ini.

  • Ubuntu/Debian example: /etc/php/8.3/fpm/php.ini
  • AlmaLinux/Rocky (Remi packages vary): often /etc/php.ini plus pool overrides

On Ubuntu/Debian, for example:

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

Set values that match your target upload size. Example for 128MB uploads:

upload_max_filesize = 128M
post_max_size = 140M
memory_limit = 256M
max_execution_time = 180
max_input_time = 180

Rule of thumb: keep post_max_size about 10–20% higher than upload_max_filesize.

Also, don’t set memory_limit to gigabytes on a small VPS.

PHP-FPM workers can get OOM-killed and take your site with them.

Step 3: Reload PHP-FPM

sudo systemctl reload php8.3-fpm

If reload fails, restart and check logs:

sudo systemctl restart php8.3-fpm
sudo journalctl -u php8.3-fpm -n 80 --no-pager

Verify: confirm PHP sees the new limits

The clean check is a tiny temporary script that prints the values PHP is using.

Create the file:

sudo mkdir -p /var/www/example.com/public
sudo nano /var/www/example.com/public/php-limits.php

Paste:

<?php
header('Content-Type: text/plain');
foreach (['upload_max_filesize','post_max_size','memory_limit','max_execution_time','max_input_time'] as $k) {
  echo $k.': '.ini_get($k)."\n";
}

Visit https://example.com/php-limits.php and confirm the values match what you set.

Important: remove it right after testing:

sudo rm -f /var/www/example.com/public/php-limits.php

If your error changed from 413 to a gateway issue, use this HostMyCode guide to isolate upstream problems: Nginx 502 Bad Gateway fix on Ubuntu VPS.

Docker/Compose deployments: set the limit in your reverse proxy container

With Docker Compose, you might have two proxies in play.

You can have Nginx on the host and another proxy in a container (Nginx/Caddy/Traefik) at the edge. A 413 can come from either layer.

Quick check: inspect response headers and see who answers the request.

Look for server: nginx, and whether it matches your container build:

curl -I https://example.com/ | sed -n '1,20p'

Nginx container example

If an Nginx container is your edge proxy, add a small config snippet and mount it into the container.

Create a file on the host:

mkdir -p ~/proxy/nginx/conf.d
nano ~/proxy/nginx/conf.d/uploads.conf

Add:

client_max_body_size 128M;

Then mount it in docker-compose.yml for the proxy service:

services:
  nginx:
    image: nginx:1.27
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
    ports:
      - "80:80"
      - "443:443"

Apply changes:

docker compose up -d
docker compose logs --tail=50 nginx

Caddy and Traefik note

Caddy and Traefik don’t use client_max_body_size.

If you front a PHP app with Caddy, PHP limits are still the usual culprit.

If you’re using Caddy for TLS termination on a VPS, see: Set Up Let’s Encrypt With Caddy for a VPS Site.

Stop uploads from stalling: timeouts and buffering that actually matter

Once size limits are high enough, the next failure often looks like a “stuck” upload.

It eventually turns into a 504/499, or a WordPress import that dies mid-run.

Two Nginx settings help most on slow connections and large request bodies:

  • client_body_timeout – how long Nginx waits for the client to send the request body
  • send_timeout – how long Nginx waits while sending a response to the client

On a typical VPS, increase them conservatively in the same server block:

server {
    # uploads
    client_max_body_size 128M;

    # tolerate slower uploads without keeping sockets forever
    client_body_timeout 120s;
    send_timeout 120s;
}

Don’t go extreme (like 30 minutes) unless you’ve measured a real need.

Overlong timeouts make slow-client abuse easier.

Buffering and temp disk space (why /var can suddenly fill up)

Nginx buffers request bodies to disk once they outgrow in-memory buffers.

Large uploads can end up under /var/lib/nginx (the exact path depends on distro/build).

If that disk fills, uploads can fail with “no space left on device”.

Check free space before you test big uploads:

df -h
sudo du -sh /var/lib/nginx 2>/dev/null || true

If space is tight, rotate/clean logs safely (don’t delete active log files) or increase your VPS storage.

WordPress-specific checks (Media Library, plugin uploads, and imports)

WordPress uploads pass through several layers: browser → Nginx → PHP-FPM → WordPress.

After Nginx and PHP accept the size, WordPress can still block certain operations via settings/constants or workflow quirks.

Practical checks:

  • In WordPress admin, open Media → Add New and confirm “Maximum upload file size” matches your PHP limit.
  • Upload a file that’s 10–20% under your cap (for a 128MB limit, try ~100MB). It should complete without drama.
  • Upload a file slightly above the cap (for a 128MB limit, try ~140MB). A predictable failure is healthy—it proves limits are enforced.

If you’re also tuning WordPress performance on a VPS (caching and PHP worker efficiency), you can pair this fix with: Install LiteSpeed Cache for WordPress on a VPS.

Test the fix properly (without guessing)

Browser uploads are convenient, but they’re noisy to debug.

Use a repeatable curl test so you can separate “size limit” from “app problem.”

Create a file with a known size (example: 110MB):

# On Linux/macOS
dd if=/dev/zero of=upload-test-110M.bin bs=1M count=110

Now POST it to an endpoint that accepts uploads.

WordPress uploads require auth and a nonce, so they’re not curl-friendly.

Instead, test against a temporary upload handler, then delete it.

Temporary upload endpoint (remove after test)

Create a minimal PHP upload receiver:

sudo nano /var/www/example.com/public/upload-receiver.php
<?php
header('Content-Type: text/plain');
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
  http_response_code(405);
  echo "POST only\n";
  exit;
}
if (!isset($_FILES['file'])) {
  http_response_code(400);
  echo "missing file field\n";
  exit;
}
$dst = __DIR__ . '/_upload_test_' . basename($_FILES['file']['name']);
if (!move_uploaded_file($_FILES['file']['tmp_name'], $dst)) {
  http_response_code(500);
  echo "move failed\n";
  exit;
}
echo "ok: " . filesize($dst) . " bytes\n";

Run the curl upload:

curl -sS -F "file=@upload-test-110M.bin" https://example.com/upload-receiver.php

You want an ok: response.

If you still get 413, Nginx is blocking somewhere.

If you get 500, check PHP logs, permissions, and available disk.

Clean up immediately after:

sudo rm -f /var/www/example.com/public/upload-receiver.php
sudo rm -f /var/www/example.com/public/_upload_test_*
rm -f upload-test-110M.bin

Common mistakes that keep 413 coming back

  • You edited the wrong config file. Use nginx -T to confirm which files are loaded.
  • You put the directive in the wrong context. client_max_body_size must live inside http, server, or location.
  • You reloaded the wrong service. OpenResty, containerized Nginx, or panel-managed Nginx can change service names and reload behavior.
  • You only adjusted Nginx. PHP can still reject uploads via upload_max_filesize/post_max_size.
  • You raised limits and ran out of disk. Upload buffering can fill /var. Check df -h before and after testing.

Control panels (Plesk/cPanel/DirectAdmin): where the limit is set

On a panel-managed VPS, Nginx configs are often generated from templates.

Direct edits may disappear after updates or a “reconfigure” run.

  • Plesk: add per-domain Nginx directives in the domain’s Apache & Nginx settings, and align PHP settings per domain.
  • cPanel (with Nginx or as a proxy): upload limits may live in includes/templates; PHP limits are typically set via MultiPHP INI Editor.
  • DirectAdmin: changes may need to be made in templates or per-domain settings so they survive template rebuilds.

If you can’t tell whether your stack is panel-managed or hand-managed, a managed VPS hosting plan can save you from chasing config changes that keep getting overwritten.

Monitoring after the change (catch the next bottleneck)

After uploads succeed, watch what tends to break next.

Common issues include PHP-FPM worker saturation, rising 499s (client closed request), and slow disk creep from temp files and logs.

These quick checks cover the basics:

# Nginx error spikes
sudo grep -R "too large body" -n /var/log/nginx/error.log | tail

# PHP-FPM status and errors
sudo journalctl -u php8.3-fpm -n 100 --no-pager

# Disk trends
df -h

If you want a lightweight live dashboard for a VPS, HostMyCode has a practical walkthrough for Netdata: Run Netdata on a VPS for live server monitoring.

Summary: a safe upload fix that doesn’t create new outages

To stop 413s for good, raise the limit where the request is rejected (client_max_body_size).

Then match PHP-FPM’s POST/upload settings so the app can actually handle the file.

After that, test with a known-size upload and watch disk usage and timeouts.

If you’re doing this on production infrastructure and want predictable behavior under load, run on a VPS sized for your traffic and PHP workload.

A HostMyCode VPS gives you full control over Nginx/PHP settings and consistent resources, which makes upload limits far easier to manage.

If uploads are failing because your site has outgrown shared hosting limits, move to a VPS you control. Start with a HostMyCode VPS, or pick managed VPS hosting if you want help keeping Nginx/PHP and security settings clean as you scale.

FAQ

Should I set client_max_body_size globally in nginx.conf?

Only if every site on the server needs the same limit. On a multi-site VPS, set it per domain in the site’s server {} block.

I increased client_max_body_size but uploads still fail. What next?

Check PHP-FPM: upload_max_filesize and post_max_size must be high enough. Then review logs for timeouts (504) or upstream errors (502).

Why does WordPress show a lower “Maximum upload file size” than Nginx?

WordPress displays the PHP limit, not the Nginx limit. If PHP is set to 64M, WordPress will show 64MB even if Nginx allows 128M.

Can raising upload limits create security risk?

Yes. Higher limits increase exposure to large request-body abuse and disk pressure. Keep the cap close to what you need, use reasonable timeouts, and add rate-limiting/WAF controls if the site is public and targeted.

Do I need to restart Nginx after changing the config?

A reload is usually enough: sudo systemctl reload nginx. Run sudo nginx -t first so you don’t load a broken config.

Nginx 413 Request Entity Too Large Fix On VPS | HostMyCode