//Server Security

Headless WordPress: Backend on Managed Host, Next.js Frontend on Vercel

Run WordPress headlessly on an AtoZNode VPS, secure it, expose REST/GraphQL APIs, and connect a Next.js frontend on Vercel or Netlify.

7 min read
Headless WordPress: Backend on Managed Host, Next.js Frontend on Vercel

Running WordPress as a headless CMS lets you keep the familiar WordPress editor while building a modern, fast frontend with frameworks such as Next.js. In this guide we pair a decoupled WordPress backend on an AtoZNode managed VPS or dedicated server with a Next.js site hosted on Vercel or Netlify. The steps cover server preparation, WordPress installation, API exposure, and Next.js configuration.

1. Prepare the Managed Server for WordPress

Even in a managed environment you need to install the web stack that will serve WordPress. The commands differ between Debian/Ubuntu (apt) and AlmaLinux/Rocky/RHEL (dnf). Windows servers are not covered here.

Debian / Ubuntu (apt)

# Update package list
sudo apt update

# Install Nginx, PHP‑FPM 8.2 and required extensions
sudo apt install -y nginx php8.2-fpm php8.2-mysql php8.2-xml php8.2-gd php8.2-curl php8.2-mbstring php8.2-zip

# Enable and start services
sudo systemctl enable --now nginx
sudo systemctl enable --now php8.2-fpm

What each command does:

  • apt update refreshes the local package index.
  • The apt install line pulls Nginx, PHP‑FPM 8.2, and extensions that WordPress needs for database access, XML handling, image processing, HTTP requests, multibyte strings, and ZIP archives.
  • Each systemctl enable --now starts the service immediately and configures it to start on boot.

AlmaLinux / Rocky / RHEL (dnf)

# Enable EPEL for additional packages
sudo dnf install -y epel-release

# Reset any existing PHP module and enable PHP 8.2 stream
sudo dnf module reset php -y
sudo dnf module enable php:8.2 -y

# Install Nginx, PHP‑FPM 8.2 and extensions
sudo dnf install -y nginx php php-fpm php-mysqlnd php-xml php-gd php-curl php-mbstring php-zip

# Enable and start services
sudo systemctl enable --now nginx
sudo systemctl enable --now php-fpm

Explanation:

  • Installing epel-release provides packages that are not in the default repo.
  • The module reset and module enable commands ensure the PHP 8.2 stream is used.
  • PHP‑FPM is the FastCGI Process Manager that Nginx will use to run PHP.
  • Both Nginx and PHP‑FPM are enabled and started.

2. Secure the Server and Configure Nginx

A solid security baseline protects your WordPress API and admin interface.

Firewall Setup (both OS families)

# Debian/Ubuntu – UFW
sudo apt install -y ufw
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

# AlmaLinux/Rocky/RHEL – firewalld
sudo dnf install -y firewalld
sudo systemctl enable --now firewalld
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

Create an Nginx server block that points to the WordPress directory and enables pretty URLs for the REST API.

# Create WordPress directory
sudo mkdir -p /var/www/wordpress
sudo chown -R $USER:$USER /var/www/wordpress

# Sample Nginx config (save as /etc/nginx/sites-available/wordpress.conf)
server {
    listen 80;
    server_name example.com;   # replace with your domain

    root /var/www/wordpress;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    # Pass PHP scripts to PHP‑FPM
    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;   # Debian/Ubuntu
        # fastcgi_pass unix:/run/php-fpm/www.sock;   # AlmaLinux/RHEL
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    # Cache static assets
    location ~* \.(js|css|png|jpg|jpeg|gif|svg|ico)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
}

Enable the site and reload Nginx:

# Debian/Ubuntu
sudo ln -s /etc/nginx/sites-available/wordpress.conf /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

# AlmaLinux/Rocky/RHEL (use /etc/nginx/conf.d)
sudo cp /etc/nginx/sites-available/wordpress.conf /etc/nginx/conf.d/
sudo nginx -t && sudo systemctl reload nginx

3. Install WordPress and Enable Headless Features

Download the latest WordPress package, extract it, and run the installer through the web UI.

# Download and extract
wget https://wordpress.org/latest.tar.gz
tar -xzf latest.tar.gz
mv wordpress/* /var/www/wordpress/
rm -rf wordpress latest.tar.gz

# Set permissions for the web server user
sudo chown -R www-data:www-data /var/www/wordpress
sudo find /var/www/wordpress -type d -exec chmod 755 {} \;
sudo find /var/www/wordpress -type f -exec chmod 644 {} \;

Open http://example.com in a browser and complete the setup wizard (provide database name, user, password). Use a MySQL/MariaDB instance supplied by AtoZNode or a managed database service.

Activate Headless Plugins

  • WPGraphQL – adds a /graphql endpoint for GraphQL queries.
  • WP REST API – available by default at /wp-json/wp/v2.
  • Optionally disable the front‑end theme or install a minimal “blank” theme to reduce unnecessary output.

Install plugins via the admin UI or with WP‑CLI:

# Example with WP‑CLI
wp plugin install wp-graphql --activate
wp plugin install disable-gutenberg --activate   # optional

4. Expose the API Securely

Because the frontend will be served from Vercel or Netlify, the API must be publicly reachable. The admin area should remain protected.

Basic Authentication for /wp-admin

# Debian/Ubuntu – Apache utils for htpasswd
sudo apt install -y apache2-utils
# AlmaLinux/Rocky/RHEL – httpd-tools
sudo dnf install -y httpd-tools

# Create a password file
sudo htpasswd -c /etc/nginx/.htpasswd admin
# (you’ll be prompted for a password)

Add the following snippet inside the server block of your Nginx config, before the location / block:

location /wp-admin {
    auth_basic "Restricted Area";
    auth_basic_user_file /etc/nginx/.htpasswd;
}

Reload Nginx to apply the change.

Enable HTTPS with Let’s Encrypt

# Debian/Ubuntu
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com

# AlmaLinux/Rocky/RHEL
sudo dnf install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com

Certbot updates the Nginx configuration to redirect HTTP to HTTPS and sets up automatic renewal.

5. Build the Next.js Frontend

On your local machine or CI environment create a Next.js project that consumes the WordPress API.

# Create a new Next.js app (Node.js 18+ recommended)
npx create-next-app@latest my-headless-site
cd my-headless-site

# Install GraphQL client if using WPGraphQL
npm install @apollo/client graphql

Fetching Data with GraphQL

Create lib/apollo.js:

import { ApolloClient, InMemoryCache } from '@apollo/client';

const client = new ApolloClient({
  uri: 'https://example.com/graphql',
  cache: new InMemoryCache(),
});

export default client;

In pages/index.js, query posts:

import { gql } from '@apollo/client';
import client from '../lib/apollo';

export async function getStaticProps() {
  const { data } = await client.query({
    query: gql`
      query AllPosts {
        posts(first: 10) {
          nodes {
            title
            slug
            excerpt
          }
        }
      }
    `,
  });

  return {
    props: { posts: data.posts.nodes },
    revalidate: 60, // regenerate at most once per minute
  };
}

export default function Home({ posts }) {
  return (
    <main>
      <h1>Latest Articles</h1>
      <ul>
        {posts.map((post) => (
          <li key={post.slug}>
            <h2>{post.title}</h2>
            <div dangerouslySetInnerHTML={{ __html: post.excerpt }} />
          </li>
        ))}
      </ul>
    </main>
  );
}

If you prefer the REST API, replace the GraphQL client with node-fetch and call https://example.com/wp-json/wp/v2/posts inside getStaticProps.

Deploy to Vercel or Netlify

  • Vercel – Connect the GitHub repository, set the build command to npm run build, and let Vercel detect the Next.js framework automatically.
  • Netlify – Use the “Next.js build plugin” or set the build command to npm run build and publish directory to .next. Netlify also supports ISR via Edge Functions.

Both platforms serve the site over HTTPS. If you externalise the WordPress endpoint, set the environment variable NEXT_PUBLIC_WORDPRESS_URL to https://example.com.

6. Optimize Performance and Maintenance

Cache API Responses

  • Enable a caching plugin such as WP Super Cache or Cache Enabler on WordPress to store REST/GraphQL responses.
  • Set appropriate Cache-Control headers in WordPress (e.g., public, max-age=300) to leverage Vercel/Netlify edge caching.

Schedule Regular Updates

Use AtoZNode’s managed‑server tools or run the following commands to keep the OS and packages up to date.

# Debian/Ubuntu
sudo apt update && sudo apt upgrade -y

# AlmaLinux/Rocky/RHEL
sudo dnf upgrade -y

Consider a cron job or the provider’s automated patching feature to keep PHP, Nginx, and the OS current.

Monitor API Health

Expose a simple health‑check endpoint (e.g., /healthz) that returns 200 OK when the database and PHP are functioning. Configure Vercel or Netlify to ping this endpoint periodically.

Conclusion

Decoupling WordPress from the presentation layer gives you the editorial power of WordPress while delivering a fast, SEO‑friendly frontend built with Next.js. This guide walked you through provisioning a secure WordPress backend on an AtoZNode managed server, exposing the REST/GraphQL API over HTTPS, and deploying a Next.js site on Vercel or Netlify. Keep both layers updated, cache wisely, and monitor health to maintain a smooth experience for your Indian audience.

wordpressheadless cmsnext.jsapinginxubuntualmalinuxvercel

Try it on your own server

Follow along on a Cloud VPS with full root access, or read the step-by-step knowledge base guides.