Deploying Angular SSR and Headless WordPress Admin on the Same Port 80

I’m working on my Angular Universal application using Node.js with server-side rendering on port 80, while my WordPress site operates on port 8080 through Apache. I need to make both applications accessible on port 80. Specifically, I want to:

  • Serve Angular when visiting http://my-ip/
  • Access WordPress admin at http://my-ip/wp-admin or /backend
  • Disable all front-end functionality of WordPress, keeping only the admin interfaces available at /wp-admin and /backend
  • Ensure that Angular’s sitemap and robots.txt are unaffected by WordPress settings

Currently, my WordPress setup serves both the front-end and admin on port 8080, while Angular is on port 80. I attempted to implement a reverse proxy within my Node.js server configuration to redirect requests to /wp-admin and /backend on port 8080, but I’m unsure about how to configure Apache to turn off the WordPress front-end while ensuring everything functions correctly on port 80.

Here’s my Apache configuration for reference:

<VirtualHost *:8080>
    ServerName my-ip
    DocumentRoot /var/www/backend
    <Directory /var/www/backend>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
    <FilesMatch "^.">
        Require all denied
    </FilesMatch>
    ErrorLog ${APACHE_LOG_DIR}/backend_error.log
    CustomLog ${APACHE_LOG_DIR}/backend_access.log combined
</VirtualHost>

And here’s how I’m running my Angular app with a systemd service:

[Unit]
Description=Angular SSR Application
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/var/www/html
ExecStart=/usr/bin/node server/server.mjs
Restart=always
Environment=NODE_ENV=production
Environment=PORT=80

[Install]
WantedBy=multi-user.target

Finally, the WordPress and Angular files are located in the following directories:

  • WordPress files (e.g., wp-admin, wp-content, index.php) are at /var/www/backend
  • Angular files (e.g., server/, browser/, package.json) are at /var/www/html

I have a few questions:

  1. How can I configure Apache to ensure only /wp-admin and /backend are accessible while blocking the WordPress front-end?
  2. Is my current setup for the Node.js reverse proxy the best method to serve both applications on port 80?
  3. How can I make sure that Angular’s SEO directives, like sitemap and robots.txt, work correctly and that WordPress admin URLs do not get indexed by search engines?

System environment details:

  • OS: Ubuntu 22.04
  • Angular: Universal 19 SSR
  • Database: MySQL 8.0

I’ve dealt with this setup recently - nginx as a reverse proxy beats handling everything in Node.js. Put nginx on port 80, then proxy Angular requests to port 3000 and WordPress requests to Apache on 8080.

To disable WordPress frontend, drop this in your wp-config.php:

if (!is_admin() && !in_array($GLOBALS['pagenow'], ['wp-login.php', 'wp-register.php'])) {
    wp_redirect('/'); 
    exit();
}

This bounces any non-admin requests back to Angular. Also add add_action('wp_robots', '__return_empty_string'); so WordPress doesn’t mess with your robots.txt.

The Node.js reverse proxy route works but gets ugly with static assets and file uploads. nginx is cleaner and faster.

Apache’s probably overkill for this. Just throw WordPress in a subdirectory and stick with your node proxy. Make a /wordpress folder, dump the WP files there, then set your reverse proxy to catch /wp-admin and /backend requests and send them to localhost:8080/wordpress/wp-admin. Much cleaner than blocking the WP frontend with redirects - those break all the time when plugins update.

Your Node.js reverse proxy approach works well for this. Since you’re already using that setup, here’s what I’d do based on similar projects I’ve worked on.

For Apache, update your .htaccess in /var/www/backend to block everything except admin paths:

RewriteEngine On
RewriteCond %{REQUEST_URI} !^/wp-admin
RewriteCond %{REQUEST_URI} !^/backend
RewriteCond %{REQUEST_URI} !^/wp-login.php
RewriteRule ^(.*)$ - [R=404,L]

In your Node.js server, handle the proxy headers properly and add a catch-all for WordPress assets that wp-admin needs. Proxy /wp-includes and /wp-content too.

For SEO, add X-Robots-Tag: noindex headers to all proxied WordPress requests in your Node.js middleware. This stops accidental indexing even if search engines hit those paths.

One thing that bit me: WordPress redirects based on its configured site URL, so make sure your WordPress database settings match your intended URLs.