TROUBLESHOOTING
July 27, 2026

How to Fix "500 Internal Server Error" on a VPS

6 min read
Author
CloudStick Team
WordPress Engineer
Share this article
How to Fix "500 Internal Server Error" on a VPS
CloudStick
500 Server Error

Why 500 Is Vague By Design

A 500 Internal Server Error means the web server hit a problem it could not describe with a more specific code. It is the HTTP equivalent of a shrug — the request reached the server, something inside broke, and there was no better bucket to file it under than "server error, unspecified." Unlike a 404 (page not found) or a 403 (permission denied), a 500 tells you nothing about the actual cause.

That vagueness is deliberate on the web server's part: Nginx and Apache return 500 whenever the upstream application — PHP-FPM, in most WordPress and PHP stacks — crashes, times out, or returns a malformed response. The web server does not parse PHP; it just relays whatever comes back from the PHP process, or returns 500 if nothing comes back at all. Every real fix starts from the same place: stop guessing at the browser screen and go find the actual error, one layer down.

Stop Guessing — Read The Log First

The first real troubleshooting step for any 500 error is always the same: open the error log and read the actual message. Disabling plugins at random, reinstalling WordPress core, or re-uploading the theme before you have looked at a log is wasted motion — you are treating symptoms of an error you have not diagnosed yet.

On a self-managed VPS this means SSHing in and tailing the right log file live while you reload the broken page:

# Nginx error log for the site
tail -f /var/log/nginx/error.log
# PHP-FPM error log
tail -f /var/log/php8.3-fpm.log
# WordPress debug log, if WP_DEBUG_LOG is enabled
tail -f /var/www/html/wp-content/debug.log

"PHP Fatal error: Uncaught Error: Call to undefined function" and "Allowed memory size exhausted" are two of the most common single lines that will end your entire debugging session in under thirty seconds — if you actually look for them instead of clicking through the dashboard hoping the error fixes itself.

On a CloudStick-managed server you can skip the SSH session entirely. Open the site in the CloudStick dashboard and go to its Web Application Logs section — it shows the live Nginx/Apache access and error log alongside the PHP error output for that specific site, so the exact fatal error line is usually visible within a few seconds of reloading the broken page.

Where PHP Errors Actually Get Logged

PHP fatal errors are logged in one of three places, and knowing which one matters for your setup saves a lot of time hunting through the wrong file. First, the PHP-FPM pool's own error log — configured per pool, this is where uncaught fatal errors and warnings land regardless of whether the application logs anything itself. Second, the web server's error log (Nginx or Apache) — this catches upstream connection failures, like PHP-FPM timing out or the socket not responding at all, which show up as 502/504 rather than a PHP-level message. Third, WordPress's own debug.log inside wp-content/, but only if WP_DEBUG and WP_DEBUG_LOG are both set to true in wp-config.php.

On CloudStick-provisioned servers, PHP-FPM runs as its own namespaced pool per site (for example php83cs-fpm) rather than sharing a system-wide pool, so per-site logs stay isolated — one noisy site cannot flood another site's log with unrelated errors, which matters a lot when you are debugging under time pressure.

The Four Most Common Real Culprits

Four causes account for the overwhelming majority of 500 errors on WordPress and general PHP sites. First, a plugin or theme PHP fatal error — most often after a partial update where one file downloaded a new version and a dependent file did not, leaving a call to a function or class that no longer exists. Second, a corrupted .htaccess file with a broken RewriteRule or a directive the server module does not recognize. Third, the PHP process exceeding its memory_limit, which shows up in the log as "Allowed memory size of N bytes exhausted." Fourth, a script that depends on a PHP extension that is not installed or was disabled — GD, imagick, and mysqli are the usual suspects after a PHP version change.

The log line tells you which of the four you are dealing with almost every time. "Call to undefined function" or "Class not found" means a code-level mismatch, usually a plugin or theme. "Premature end of script headers" in the Apache/Nginx log with nothing useful in the PHP log often points to .htaccess. "Allowed memory size exhausted" is self-explanatory. And "Call to undefined function imagecreatefromjpeg()" or similar is a missing extension.

Isolating A Plugin Or Theme Fatal Error

When the log points to a specific plugin or theme file, the fastest isolation trick is renaming the plugins folder over SFTP so WordPress cannot load any of them, then confirming the site comes back. If it does, rename the folder back and move plugins out one at a time (or in halves, to binary-search a large list) until the 500 reappears.

# From an SFTP session or SSH shell, in wp-content/
mv plugins plugins-disabled
# reload the site — if it loads, one plugin is the cause
mv plugins-disabled plugins
# then move suspect plugin folders out one at a time
mv plugins/broken-plugin-name /tmp/broken-plugin-name

If the error trace names an undefined function that used to exist in a plugin file, it almost always means an auto-update replaced part of the plugin but not all of it — check the plugin's changelog for the version installed versus the latest, and reinstall it fresh from the WordPress repository or the vendor rather than trying to patch individual files.

Fixing A Broken .htaccess And Memory Limits

For a corrupted .htaccess, rename the existing file and let WordPress regenerate a clean default from Settings → Permalinks, then re-add any custom rules one block at a time. For memory exhaustion, raise the limit in the site's own PHP configuration rather than editing the shared system php.ini, since a shared edit affects every site on the box:

# rename the broken file, WordPress will regenerate one
mv .htaccess .htaccess.bak
# raise memory_limit in wp-config.php as a quick check
define('WP_MEMORY_LIMIT', '256M');
# or set it in the site's own php.ini override
memory_limit = 256M
TIP

Raising memory_limit treats the symptom, not the cause. If the same script keeps hitting the ceiling after a bump, something is looping or loading far more data than it should — check the exact line in the stack trace before assuming more RAM is the permanent fix.

Practical Next Steps

The fastest path out of a 500 error is always: read the log, identify which of the four common causes it points to, then apply the narrow fix for that cause instead of a broad one. Do not reinstall WordPress core to fix a memory limit, and do not raise memory_limit to fix a missing PHP extension — matching the fix to the actual log line is what separates a five-minute recovery from an hour of guessing.

Going forward, keep WP_DEBUG_LOG enabled on staging environments so fatal errors are captured before they ever reach production, and check the site's error log immediately after any plugin, theme, or PHP version update — most 500 errors trace back to something that changed in the last few minutes, not a mystery that has been lurking for weeks.

Leave a comment
Full Name
Email Address
Message
Contents