Docs/WordPress Security

WordPress Security

Secure your WordPress site by taking it offline while using it as a headless CMS for PhantomStudio.

WordPress Security

When using WordPress as a headless CMS for PhantomStudio, you have the option to completely block public access to your WordPress installation. This protects against:

  • Bots and scrapers accessing your content
  • Vulnerabilities in WordPress plugins or themes
  • Direct access to potentially malicious PHP files
  • Brute force attacks on wp-login.php
💡

This is completely optional. PhantomStudio works fine with a public WordPress site. Only set this up if you want maximum security.

How It Works

Your project sends a secret header (X-PhantomWP-Secret) with every request to your WordPress REST API: from the editor, from builds and from server-rendered pages. By configuring your server to block requests without this header, you effectively take your WordPress site offline while still letting your site read its content.

Request Flow

Request SourceHas Secret Header?Result
PhantomStudio and your siteYesAllowed
You (with browser extension)YesAllowed
Bots, scrapers, publicNoBlocked (403)

Setup Steps

Step 1: Get Your Secret Key

  1. Open your project in the editor
  2. Open Site ▾ › WordPress and connect your site (see Connecting WordPress)
  3. Open the Security tab
  4. Expand Access Secret
  5. Copy the secret (it starts with pwp_)

The project keeps the secret in .env as WP_ACCESS_SECRET; only server code reads it.

Step 2: Configure Your Browser (For Admin Access)

To access your WordPress admin panel (/wp-admin) after blocking public access, you need to add the secret header to your browser.

Install a header-editing extension:

We recommend Header Editor; it's free, open-source (auditable on GitHub), ad-free, and doesn't collect any data.

⚠️

Avoid ModHeader, which was previously recommended here. It was pulled from the Chrome Web Store and Edge Add-ons in July 2026 after researchers found hidden browsing-history collection code. If you still have it installed, remove it.

Configure Header Editor:

  1. Open the extension and add a new rule (type: Modify request header)
  2. Set the header:
    • Name: X-PhantomWP-Secret
    • Value: Your secret key (e.g., pwp_a1b2c3d4...)
  3. (Optional) Set the rule's match pattern to only apply to your WordPress domain

Now you can browse your WordPress site normally, including wp-admin, and the header will be automatically added.

Step 3: Block Requests Without the Header

Choose one of the following options based on your hosting setup:

If your site uses Cloudflare, this is the most secure option. Requests are blocked at the edge before they ever reach your server.

Create a new Worker:

  1. Go to your Cloudflare dashboard
  2. Navigate to Workers & Pages > Create Worker
  3. Paste this code:
export default {
  async fetch(request, env, ctx) {
    const secret = request.headers.get('X-PhantomWP-Secret');
    const expectedSecret = 'YOUR_SECRET_KEY'; // Replace with your key
    
    if (secret !== expectedSecret) {
      return new Response('Forbidden', { 
        status: 403,
        headers: { 'Content-Type': 'text/plain' }
      });
    }
    
    // Forward the request to your origin
    return fetch(request);
  }
}
  1. Deploy the Worker
  2. Go to your domain settings and add a Route that maps your WordPress domain to this Worker

Option B: nginx Configuration

Add this to your nginx server block:

# Block requests without the secret header
set $block_request 1;

# Allow requests with valid secret
if ($http_x_phantomwp_secret = "YOUR_SECRET_KEY") {
    set $block_request 0;
}

# Return 403 for blocked requests
if ($block_request) {
    return 403;
}

Full example with WordPress:

server {
    listen 80;
    server_name your-wordpress-site.com;
    root /var/www/wordpress;
    
    # Security: Block requests without secret header
    set $block_request 1;
    if ($http_x_phantomwp_secret = "YOUR_SECRET_KEY") {
        set $block_request 0;
    }
    if ($block_request) {
        return 403;
    }
    
    # Standard WordPress configuration
    location / {
        try_files $uri $uri/ /index.php?$args;
    }
    
    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

After editing, reload nginx:

sudo nginx -t && sudo systemctl reload nginx

Option C: Apache .htaccess

Add this to your WordPress .htaccess file (at the beginning, before the WordPress rules):

# PhantomStudio security - Block requests without secret header
RewriteEngine On
RewriteCond %{HTTP:X-PhantomWP-Secret} !^YOUR_SECRET_KEY$
RewriteRule ^ - [F]

Full .htaccess example:

# PhantomStudio security
RewriteEngine On
RewriteCond %{HTTP:X-PhantomWP-Secret} !^YOUR_SECRET_KEY$
RewriteRule ^ - [F]

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

Verifying Your Setup

After configuring your server, test that blocking is working:

Without header (should be blocked):

curl -I https://your-wordpress-site.com
# Expected: HTTP 403 Forbidden

With header (should work):

curl -I -H "X-PhantomWP-Secret: YOUR_SECRET_KEY" https://your-wordpress-site.com
# Expected: HTTP 200 OK

Troubleshooting

I'm locked out of wp-admin

  1. Make sure Header Editor (or your header-editing extension) is installed and enabled
  2. Verify the header name is exactly X-PhantomWP-Secret (case-sensitive)
  3. Check that your secret key matches exactly (no extra spaces)
  4. Try disabling other browser extensions that might interfere

PhantomStudio can't connect to WordPress

  1. Verify your WordPress URL in Site ▾ › WordPress › Connection
  2. Make sure you saved the settings, so .env has the current WP_ACCESS_SECRET
  3. Check that the secret in your server config matches the one on the Security tab
  4. Check your server logs for any errors

I want to allow some paths without the header

Modify your server config to exclude certain paths. For example, in nginx:

# Allow health checks without secret
location /health {
    return 200 'OK';
}

# Block everything else without secret
location / {
    set $block_request 1;
    if ($http_x_phantomwp_secret = "YOUR_SECRET_KEY") {
        set $block_request 0;
    }
    if ($block_request) {
        return 403;
    }
    # ... rest of config
}

Rotating Your Secret Key

If you need to change your secret key:

  1. Open Site ▾ › WordPress › Security, expand Access Secret and click Rotate
  2. Click Save Settings so .env and your deployment's environment variables get the new secret
  3. Reinstall or re-pair PhantomWP Connect so the plugin stores the new secret (download a fresh zip from the Connection tab)
  4. Update your server configuration with the new key
  5. Update the header value in your browser extension with the new key
  6. Deploy again, then test that everything works before removing the old key
⚠️

Always test the new key before removing the old one from your server config. You can temporarily allow both keys during migration.

Security Best Practices

  1. Use HTTPS - Always use HTTPS for your WordPress site to prevent header interception
  2. Keep WordPress updated - Even with this protection, keep WordPress and plugins updated
  3. Use strong passwords - Your WordPress admin password should still be strong
  4. Regular backups - Maintain regular backups of your WordPress database and files
  5. Monitor access logs - Periodically check your server logs for suspicious activity