Magento 2 Blank Page on Frontend & Admin: The Complete Fix Guide
After installing Magento 2 on Ubuntu with Apache, hitting the frontend or admin URL shows a blank page — no theme, no error, nothing. This guide walks through the 14 root causes that actually trigger it and the exact recovery recipe for each, with the canonical hosts-file edit (Linux + Windows) and a Magento-ready Apache virtual host you can copy verbatim.
You installed Magento 2 on Ubuntu, restarted Apache, opened the storefront URL in Chrome — and got a blank white page. No theme, no error, no HTML, no 500. The admin URL does the same thing. Tabs flip back and forth between This site can’t be reached, 403 Forbidden, and an empty white rectangle that looks like Magento started rendering and stopped.
This is one of the most frequent “day 1” problems in Magento 2 and the cause is rarely what the symptom suggests. A blank page looks like a Magento bug; the actual root cause is almost always one of 14 well-defined things — an unresolved hostname, a misconfigured Apache vhost, a permissions mismatch, production mode without static content, or PHP errors that have been silenced. This guide walks through every one of them in order, with the exact recovery recipe.
What “blank page” actually means in Magento 2
Browsers display a blank page for three completely different reasons, and the fix is different for each. Before you change anything, decide which kind you have:
- The browser never reached your server. Chrome / Firefox shows This site can’t be reached,
ERR_NAME_NOT_RESOLVED, or a long load with no response. The browser cannot resolve the hostname (jjsmykker.dk,magento2.local, etc.) to an IP. Fix: the hosts file. - The server responded with empty HTML. Chrome shows a white page; View Source shows nothing or a tiny amount of HTML; the URL bar shows your hostname loaded cleanly. Apache did serve a response, it was just empty. Fix: PHP error or Magento mode issue.
- The server returned a 403/404/500 dressed as a blank. The browser may show 403 Forbidden, 404 Not Found, or render Apache’s default placeholder. Fix: Apache virtual host or
.htaccess.
Open Chrome DevTools → Network, reload the page, click the top request and check the Status column. That single number tells you which of the three categories you are in, and therefore which section of this guide to jump to.
Step 1 · Edit the hosts file (Linux & macOS)
If your install is on Ubuntu and you are pointing a fake domain like jjsmykker.dk or magento2.local at 127.0.0.1, the operating system needs a hosts-file entry to resolve the name. Without it, Chrome tries to look it up over real DNS, fails, and shows This site can’t be reached.
On Linux and macOS the file lives at /etc/hosts:
sudo nano /etc/hosts
Add one line per hostname that should resolve to your local machine. Use the exact hostname you put in ServerName/ServerAlias inside the Apache vhost — if they don’t match, Apache will not route the request to the right vhost block.
127.0.0.1 magento2
127.0.0.1 magento2.local
127.0.0.1 jjsmykker.dk
127.0.0.1 admin.magento2.local
Save (Ctrl+O in nano), exit (Ctrl+X), then test resolution without going through the browser at all:
ping -c 2 magento2.local
getent hosts magento2.local
curl -I http://magento2.local/
If ping answers from 127.0.0.1 and curl returns any HTTP status code (even 403 or 500), your hostname now resolves. If curl still hangs, you have a firewall or Apache listen-address problem, not a Magento problem.
/etc/hosts, restart Chrome completely or visit chrome://net-internals/#dns and click “Clear host cache.” Otherwise Chrome keeps using its cached “this hostname doesn’t exist” result for several minutes.Step 2 · Edit the Windows hosts file
If your Magento install is running inside WSL, a VM, or Docker on a Windows 10/11 host, and you are browsing it from Chrome on Windows, you must edit both the Ubuntu /etc/hosts file and the Windows hosts file. Chrome on Windows uses the Windows hosts file for resolution — not the WSL one.
The Windows hosts file lives at:
C:\Windows\System32\drivers\etc\hosts
It has no file extension. To edit it you need an editor running as Administrator — Notepad will silently fail to save otherwise.
- Press Start, type
notepad, right-click Notepad, choose Run as administrator. - In Notepad, File → Open, paste the path above into the filename box, change the file-type filter to All Files (*.*) so the extensionless
hostsfile shows up, and open it. - Add the same lines you added to
/etc/hostson Ubuntu, one per hostname:127.0.0.1 magento2 127.0.0.1 magento2.local 127.0.0.1 jjsmykker.dk - Save the file. Notepad may ask “keep file extension” — say yes; the file should stay called
hostswith no extension. - Flush Windows’ DNS cache so Chrome stops using the cached “not found” result:
ipconfig /flushdns - Close all Chrome windows (check the system tray) and reopen Chrome. Visit
chrome://net-internals/#dns→ Clear host cache, then visitchrome://net-internals/#sockets→ Flush socket pools.
Verify from a Windows command prompt:
ping magento2.local
You should see replies from 127.0.0.1. If you see could not find host, the file did not save — check the path again and confirm the file is exactly hosts with no .txt extension.
C:\Windows\System32\drivers\etc\hosts for “hosts hijack protection” — you need to whitelist it in the antivirus or disable that protection temporarily. (2) Some VPN clients install their own DNS resolver that ignores the hosts file entirely — disconnect the VPN and retry. (3) Chrome’s Secure DNS / DNS-over-HTTPS bypasses the hosts file: chrome://settings/security → turn off “Use secure DNS.”Step 3 · Create the Apache virtual host (Magento-ready)
This is where the most common mistake hides. The example vhost in the original Stack Exchange answer correctly serves a static index.html at /var/www/magento2/index.html — but Magento 2 is not served from the project root. Magento ships an index.php inside the pub/ sub-directory, and that is what Apache must serve. Pointing DocumentRoot at the project root exposes app/, vendor/, and .env to the public web and breaks all the rewrites in pub/.htaccess.
The correct Magento-ready vhost looks like this. Save it as /etc/apache2/sites-available/magento2.conf:
<VirtualHost *:80>
ServerName magento2.local
ServerAlias jjsmykker.dk www.jjsmykker.dk
ServerAdmin webmaster@localhost
# Magento 2 is served from the pub/ sub-directory, NEVER the project root.
DocumentRoot /var/www/magento2/pub
<Directory /var/www/magento2/pub>
Options Indexes FollowSymLinks MultiViews
# AllowOverride MUST be All so Magento's bundled .htaccess can rewrite URLs.
# If you set this to None, every page becomes a blank or a 404.
AllowOverride All
Require all granted
</Directory>
# Block direct access to project files outside pub/.
<Directory /var/www/magento2/app> Require all denied </Directory>
<Directory /var/www/magento2/vendor> Require all denied </Directory>
<Directory /var/www/magento2/var> Require all denied </Directory>
<Directory /var/www/magento2/generated> Require all denied </Directory>
ErrorLog ${APACHE_LOG_DIR}/magento2-error.log
CustomLog ${APACHE_LOG_DIR}/magento2-access.log combined
</VirtualHost>
Enable the site, disable the default vhost so it does not race for the same :80, enable mod_rewrite (required for Magento’s URL rewrites), and reload:
sudo a2ensite magento2.conf
sudo a2dissite 000-default.conf
sudo a2enmod rewrite headers expires deflate
sudo apache2ctl configtest # syntax check before you reload
sudo systemctl reload apache2
Verify Apache is now routing your hostname to this vhost:
curl -I http://magento2.local/
# Look for: HTTP/1.1 200 OK or 302 Found (Magento redirect). Both are fine.
# If you get 403 here, jump to Step 9 (.htaccess + AllowOverride).
DocumentRoot /var/www/magento2 (the project root) instead of DocumentRoot /var/www/magento2/pub. The project root has no index.php — Apache will either render a directory listing, return 403, or serve a blank page. Always point at pub/.Step 4 · Set Magento mode + run the right deploy commands
Magento has three modes — default, developer, and production — and the symptoms of getting them wrong are nearly identical to the blank-page problem. In production mode, Magento serves nothing unless setup:di:compile and setup:static-content:deploy have already run; if you forgot either, the storefront renders blank or unstyled and the admin sometimes returns a literal empty body.
For a local install where you are still debugging, switch to developer mode — it builds generated code on demand and surfaces every PHP error:
cd /var/www/magento2
sudo -u www-data bin/magento deploy:mode:show
sudo -u www-data bin/magento deploy:mode:set developer
sudo -u www-data bin/magento setup:upgrade
sudo -u www-data bin/magento cache:flush
Run the CLI as the web user (www-data on Ubuntu / Debian). Running it as root creates files Apache can’t read — the next request then 500s or returns blank, and the symptom looks exactly like a configuration problem.
If you want to stay in production mode, you must explicitly run the static deploy too:
sudo -u www-data bin/magento setup:upgrade
sudo -u www-data bin/magento setup:di:compile
sudo -u www-data bin/magento setup:static-content:deploy -f en_US
sudo -u www-data bin/magento cache:flush
For a deeper dive into what each of these commands actually does — phases, tables they write to, and the production-safe run order — see my breakdown of setup:upgrade, setup:di:compile, and setup:static-content:deploy.
Step 5 · Fix file and folder permissions
Magento needs to write to var/, generated/, pub/static/, pub/media/, and app/etc/. If any of these is owned by the wrong user or read-only, Magento either errors out (filling var/log/exception.log) or returns an empty body when error display is off.
cd /var/www/magento2
sudo find . -type d -exec chmod 755 {} +
sudo find . -type f -exec chmod 644 {} +
sudo chmod -R g+w var generated pub/static pub/media app/etc
sudo chmod u+x bin/magento
sudo chown -R www-data:www-data .
If you SSH in as your own user but Apache runs as www-data, add yourself to that group so you can edit files without breaking ownership:
sudo usermod -a -G www-data $USER
newgrp www-data # apply group membership in current shell
After fixing permissions, wipe the cache and generated trees so the next request rebuilds them under the correct owner:
sudo -u www-data rm -rf var/cache/* var/page_cache/* generated/code/* generated/metadata/*
sudo -u www-data bin/magento cache:flush
Step 6 · Reveal hidden PHP errors
If the browser is showing blank but Apache returned 200, Magento started rendering and then died inside PHP — with error output suppressed. To see what actually failed, enable developer mode (Step 4) and explicitly turn on error display:
# pub/errors/local.xml — copy from the example shipped with Magento
cp pub/errors/local.xml.sample pub/errors/local.xml
# Magento 2.4: surface PHP errors
sudo -u www-data bin/magento deploy:mode:set developer
sudo -u www-data bin/magento config:set dev/debug/debug_logging 1
Then tail the three log files in three terminals and reload the blank page in Chrome:
# Terminal 1 — Magento application errors
tail -f var/log/exception.log var/log/system.log
# Terminal 2 — PHP fatal errors (Apache + PHP-FPM)
tail -f /var/log/apache2/magento2-error.log
# Terminal 3 — PHP error log (if php.ini points to a separate file)
tail -f /var/log/php_errors.log 2>/dev/null
The first real error tells you which root cause you have. Common ones to expect: Class “Magento\X\Y\Z” does not exist (composer install missed something), Allowed memory size exhausted (PHP memory_limit too low), Permission denied on var/cache (Step 5), SQLSTATE[HY000] [2002] (MySQL host unreachable from PHP).
Step 7 · Re-run setup:upgrade, indexers, and flush every cache layer
If you installed Magento via Composer but skipped setup:upgrade, the database is empty — the storefront tries to render against missing tables and returns blank. Run the full setup sequence in order, as the web user:
cd /var/www/magento2
sudo -u www-data bin/magento setup:upgrade
sudo -u www-data bin/magento setup:di:compile # production mode only
sudo -u www-data bin/magento setup:static-content:deploy -f en_US # production only
sudo -u www-data bin/magento indexer:reindex
sudo -u www-data bin/magento cache:flush
sudo systemctl restart php8.3-fpm # if using PHP-FPM
sudo systemctl reload apache2
If you use Varnish or Redis page cache, restart them too — a stale cached response from a failed earlier request will keep serving blank long after you fixed the underlying issue.
Step 8 · Confirm vendor/ is fully installed
If composer install was interrupted (network drop, disk full, wrong PHP version), the vendor/ directory is half-populated. Magento autoloads classes lazily, so the install looks fine until the first request reaches a missing class. That request returns blank.
cd /var/www/magento2
ls vendor/magento/framework 2>/dev/null && echo "vendor present" || echo "vendor MISSING"
# Re-install if anything looks short
sudo -u www-data composer install --no-dev --optimize-autoloader
sudo -u www-data composer dump-autoload
If you also see the dreaded Proxy.php: No such file or directory error during setup:di:compile, the generated/ tree is out of sync with the optimized autoloader. Recover with a two-pass autoload: composer dump-autoload (non-optimized) → bin/magento setup:di:compile → composer dump-autoload --optimize.
Step 9 · Check .htaccess and AllowOverride
Magento ships an .htaccess file inside pub/ that handles URL rewrites — the rules that turn pretty URLs like /customer/account/login into index.php?.... If Apache is told to ignore .htaccess (the default in many Ubuntu setups), every Magento URL except the front page returns blank or 404.
Check the vhost has AllowOverride All on the pub/ directory (see Step 3). Then confirm mod_rewrite is loaded:
sudo a2enmod rewrite
sudo apache2ctl -M | grep rewrite # rewrite_module must appear
sudo systemctl reload apache2
Verify .htaccess is actually present (a fresh composer create-project sometimes skips it on case-insensitive filesystems):
ls -la /var/www/magento2/pub/.htaccess
# If missing: download it from the Magento mainline tag matching your version
# and re-place it inside pub/ before reloading Apache.
Step 10 · PHP memory_limit + max_execution_time
Magento’s install path needs at least 2G of PHP memory; the storefront usually runs in 756M–1G. If you are below that, PHP silently crashes mid-render and Apache sends an empty body. The browser shows blank with status 200 in DevTools — the most misleading variant of this bug.
php -i | grep memory_limit
# Expect: memory_limit => 2G => 2G
sudo nano /etc/php/8.3/apache2/php.ini
# memory_limit = 2G
# max_execution_time = 1800
# max_input_time = 1800
# zlib.output_compression = Off
# realpath_cache_size = 10M
# realpath_cache_ttl = 7200
sudo systemctl restart apache2
If you use PHP-FPM, edit /etc/php/8.3/fpm/php.ini instead and restart php8.3-fpm. The Apache one is only consulted in mod_php setups.
Step 11 · Base URL mismatch in core_config_data
If you imported a database from another environment, the stored base URL still points at the old hostname. Magento happily issues a 302 redirect to the old URL and your browser ends up at http://staging.example.com/ instead of http://magento2.local/ — which silently fails to resolve and shows blank.
mysql -u magento -p magento_db -e "
SELECT path, value FROM core_config_data
WHERE path IN ('web/unsecure/base_url','web/secure/base_url',
'web/unsecure/base_link_url','web/secure/base_link_url');"
mysql -u magento -p magento_db -e "
UPDATE core_config_data
SET value = 'http://magento2.local/'
WHERE path IN ('web/unsecure/base_url','web/secure/base_url',
'web/unsecure/base_link_url','web/secure/base_link_url');"
bin/magento cache:flush
Step 12 · Admin-only blank page (2FA, Adobe IMS, custom login)
If only the admin is blank and the storefront works, the cause is almost always one of:
- Two-Factor Auth misconfiguration. Magento 2.4 enables Google/Authy 2FA by default. If the admin email was never delivered or the QR was never scanned, the admin login page can render blank after the first POST. Disable 2FA from the CLI to recover:
bin/magento module:disable Magento_TwoFactorAuth Magento_AdminAdobeImsTwoFactorAuth && bin/magento setup:upgrade && bin/magento cache:flush— re-enable and reconfigure once you can log in. - Adobe IMS module enabled by mistake. Magento 2.4.6+ ships the Adobe IMS admin login modules. On Open Source they redirect to an unreachable Adobe URL and the post-redirect lands blank. Disable with
bin/magento module:disable Magento_AdminAdobeIms Magento_AdminAdobeImsTwoFactorAuth. - Custom admin URL not propagated. If
app/etc/env.phphas abackend.frontNamedifferent from what you are typing in the browser, the URL falls through to the storefront router and 404s blank.
Step 13 · SELinux or AppArmor blocking Apache
On RHEL/CentOS/Alma/Rocky, SELinux can prevent Apache from reading /var/www/magento2/pub or writing to var/. The Apache error log will be silent (SELinux blocks happen before mod_php sees the request) and the browser gets a blank or 403. Check and adjust:
sudo sestatus # enforcing? then check audit log
sudo ausearch -m avc -ts recent | grep magento
sudo chcon -R -t httpd_sys_content_t /var/www/magento2
sudo chcon -R -t httpd_sys_rw_content_t /var/www/magento2/var \
/var/www/magento2/pub/static \
/var/www/magento2/pub/media \
/var/www/magento2/generated
On Ubuntu the equivalent is AppArmor — check /var/log/audit/audit.log or journalctl -k | grep apparmor for blocks against the Apache profile.
Step 14 · OPcache + opcache.validate_timestamps trap
If you redeployed Magento and the blank page started after a deploy, OPcache may still be serving the old compiled bytecode of files that no longer exist. The runtime tries to include a class file OPcache cached, fails, and dies silently.
php -r "opcache_reset();" # one-shot reset via CLI
sudo systemctl restart php8.3-fpm # or restart Apache for mod_php
If you rely on file-based deploys (rsync / git pull) on a production box, set opcache.validate_timestamps = 1 with a short revalidate_freq, or wrap every deploy in opcache_reset(). Atomic symlink deploys avoid this entirely — OPcache keys are inode-based, so swapping the symlink misses the cache on purpose.
The diagnosis matrix — pick the right step from one symptom
| Symptom in the browser | Most likely cause | Jump to |
|---|---|---|
This site can’t be reached / ERR_NAME_NOT_RESOLVED | Hosts file not updated (Linux and Windows if applicable) | Steps 1 & 2 |
| 403 Forbidden / Apache default page | Wrong DocumentRoot or vhost not enabled | Step 3 |
| Empty white page, status 200 | PHP error suppressed — enable developer mode & tail logs | Steps 4, 6 |
| Empty page, status 500 in DevTools | Permissions on var/ / generated/ or missing vendor/ | Steps 5, 8 |
| Front page loads, every other URL 404 / blank | .htaccess ignored — AllowOverride All + mod_rewrite | Step 9 |
| Storefront blank, admin works | Production mode without static-content:deploy | Steps 4, 7 |
| Admin blank, storefront works | 2FA / Adobe IMS / wrong backend.frontName | Step 12 |
| Blank after rsync deploy, was working before | OPcache holding stale bytecode | Step 14 |
| Browser redirects to a different domain then blanks | Stale base URL in core_config_data | Step 11 |
| Blank only on heavy pages (catalog, checkout) | PHP memory_limit or max_execution_time | Step 10 |
The 5-minute version — if you only have time for one pass
If you need to unblock fast and read the rest later, run these in order. They cover roughly 80% of real cases:
# 1. Hostname resolves
echo "127.0.0.1 magento2.local" | sudo tee -a /etc/hosts
ping -c 2 magento2.local
# 2. Apache vhost points at pub/ and AllowOverride All (see Step 3)
sudo a2enmod rewrite
sudo apache2ctl configtest && sudo systemctl reload apache2
# 3. Magento in developer mode with errors visible
cd /var/www/magento2
sudo -u www-data bin/magento deploy:mode:set developer
sudo -u www-data bin/magento setup:upgrade
sudo -u www-data bin/magento indexer:reindex
sudo -u www-data bin/magento cache:flush
# 4. Permissions
sudo chown -R www-data:www-data .
sudo chmod -R g+w var generated pub/static pub/media app/etc
# 5. Tail every relevant log and reload the page
tail -f var/log/exception.log var/log/system.log \
/var/log/apache2/magento2-error.log
If the page is still blank after this, the next request will have printed the real error into one of those three log files — that line tells you which of Steps 8–14 above to jump to.
A Magento 2 blank page is almost never a Magento bug. It is one of 14 well-defined infrastructure or config mistakes — an unresolved hostname, the wrong DocumentRoot, a stale OPcache, a missing index, suppressed PHP errors, or production mode without static content. Fix the hosts file, point the Apache vhost at pub/ with AllowOverride All, switch Magento to developer mode, and tail the three logs. The first real error you see is the one to fix.
Stuck on a Magento 2 install that won’t load? I debug Magento 2 & Adobe Commerce environments end to end — Apache, Nginx, PHP-FPM, Varnish, Hyvä — from fixed-fee $499 audit · $2,499 sprint · ~Nh @ $25/hr. See Magento developer services or remote Magento install.
Get unblocked todayFrequently asked questions
Why does Magento 2 show a blank page on the frontend after install?
Most often because Apache is serving the project root instead of the pub/ sub-directory, the hosts file does not resolve the hostname, PHP errors have been suppressed, or production mode was set without running setup:static-content:deploy. Switch Magento to developer mode and tail var/log/exception.log — the first real error tells you which one.
Where is the hosts file on Linux, macOS, and Windows?
Linux and macOS: /etc/hosts, edit with sudo nano /etc/hosts. Windows: C:\Windows\System32\drivers\etc\hosts — open Notepad as Administrator, set the file filter to All Files, and edit the file with no extension. After editing, run ipconfig /flushdns on Windows or restart Chrome and clear chrome://net-internals/#dns.
If I run Magento in WSL on Windows, which hosts file do I edit?
Both. Chrome on Windows uses the Windows hosts file for resolution, not the WSL one. Add the same 127.0.0.1 magento2.local line to C:\Windows\System32\drivers\etc\hosts and to /etc/hosts inside Ubuntu. Then ipconfig /flushdns on Windows.
Should the Apache DocumentRoot point at the Magento project root or at pub/?
Always at pub/. Magento 2 is designed to serve its index.php from inside pub/, with the rest of the codebase outside the document root. Pointing Apache at the project root exposes app/, vendor/, and app/etc/env.php publicly and breaks the bundled .htaccess rewrites — producing exactly the blank-page symptom this guide is about.
What is AllowOverride All and why does it matter?
Apache only honours .htaccess files when the surrounding <Directory> block has AllowOverride All. Magento’s URL rewrites live in pub/.htaccess; if Apache ignores them, every Magento URL except the front page returns 404 or renders blank. AllowOverride None is the silent killer.
How do I see the real PHP error behind a blank Magento page?
Switch to developer mode (bin/magento deploy:mode:set developer), copy pub/errors/local.xml.sample to pub/errors/local.xml, then tail three log files in parallel: var/log/exception.log, var/log/system.log, and /var/log/apache2/magento2-error.log. Reload the page once and the first error printed in any of those three files is the root cause.
Do I need to run setup:upgrade and indexer after installing Magento 2?
Yes. composer create-project only places code on disk; the database, indexes, and generated DI must still be built. Run setup:upgrade, then in production mode setup:di:compile and setup:static-content:deploy -f en_US, then indexer:reindex and cache:flush. Skipping any of these on production mode produces a blank or unstyled page.
Why does the storefront load but the admin shows a blank page?
Almost always one of three things: Magento 2.4’s 2FA module is enabled but never configured (the post-login page blanks); the Adobe IMS admin modules are enabled on Open Source and redirect to an unreachable Adobe URL; or backend.frontName in app/etc/env.php does not match the URL you typed. Disabling Magento_TwoFactorAuth and Magento_AdminAdobeIms from the CLI usually unblocks login so you can fix the underlying setting.
Could file permissions cause a blank Magento page?
Yes. If Apache (running as www-data) cannot read vendor/ or write to var/cache, generated/, or pub/static, Magento either fills the exception log and dies silently or returns an empty body. Run the Magento commands with sudo -u www-data bin/magento ... so files are created under the right owner from the start.
Does Magento 2 work with Nginx instead of Apache?
Yes — Magento ships an Nginx config sample at nginx.conf.sample in the project root. The blank-page debugging steps are identical: hostname must resolve, root must point at <magento>/pub, the bundled rewrite rules must be included, and Magento must be in developer mode while you investigate. Most production Magento installs in 2026 run on Nginx + PHP-FPM rather than Apache + mod_php.
I see a blank only on heavy pages like the cart or checkout. Why?
That pattern is PHP memory_limit or max_execution_time. The lightweight pages render fine; the heavy ones (cart, catalog with many filters, admin order grid) exceed the limit, PHP aborts, and Apache returns an empty body. Raise memory_limit to at least 2G and max_execution_time to 1800 in the PHP .ini Apache or PHP-FPM uses, then restart the service.
Page was working, blank after a deploy. What changed?
Almost always OPcache holding the bytecode of files that no longer exist after the deploy. Reset it with php -r "opcache_reset();" or restart PHP-FPM / Apache. Atomic symlink deploys avoid this entirely — OPcache keys are inode-based and the symlink swap invalidates the cache on purpose.