Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

Yes. Run both sites on one VPS by using a single public Nginx reverse proxy, separate hostnames, and private application ports. Point example.com to WordPress and news.example.com to Ghost; Nginx owns ports 80 and 443, serves WordPress through PHP-FPM, and proxies Ghost to its local listener at 127.0.0.1:2368. Keep databases, PHP-FPM and Ghost inaccessible from the internet, terminate HTTPS at Nginx, and back up each application independently.

What the shared-VPS architecture looks like

The two applications can share the VPS kernel and Nginx process without sharing their application runtimes, files or databases. WordPress is a PHP application. Ghost is a Node.js application that normally listens only on 127.0.0.1:2368. Nginx examines the hostname in each request and sends it to the correct upstream.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Hostname Application path Public listener Private upstream
example.com WordPress files and PHP-FPM Nginx on 80/443 WordPress document root and PHP-FPM socket
news.example.com Ghost Nginx on 80/443 http://127.0.0.1:2368 (or an internal container address)

Only Nginx should bind host ports 80 and 443. A second web server, a Ghost Docker proxy, or another container attempting to claim those ports causes a bind failure. MySQL or MariaDB, PHP-FPM and Ghost’s port 2368 should bind to localhost or an internal container network rather than a public interface.

Resource and software requirements

Use a supported Linux VPS. Ghost’s documented self-hosting stack is Ubuntu 24, Node.js 22 LTS, MySQL 8.0, Nginx and systemd, with at least 1 GB of memory. WordPress’s current recommended baseline is PHP 8.3 or newer, MariaDB 10.11 or newer or MySQL 8.0 or newer, HTTPS, and Nginx or Apache.

  • Allocate enough disk for both media libraries, databases, logs and backups; 1 GB is Ghost’s stated minimum, not a guarantee that a busy WordPress installation will fit comfortably.
  • Use a current VPS kernel and keep administrative SSH access available while configuring the firewall.
  • Have two DNS names available, or one domain plus a subdomain. Ghost has one canonical domain per installation, so choose its final hostname before enabling redirects and HTTPS.
  • Decide whether you will install directly on the host or run the applications in containers before creating paths, users and backup jobs.

Choose direct installation or Docker

Both approaches work. The critical rule is that the proxy is the only component publishing 80/443.

Decision point Direct services on the VPS Docker services
Port ownership Nginx on the host owns 80/443; Ghost listens locally on 2368. The proxy publishes 80/443; WordPress, Ghost and databases use private networks and internal ports.
Isolation Separate Unix users, directories, processes and database credentials provide isolation. Container boundaries and networks add a layer of isolation, but volumes and host permissions still need management.
Updates and rollback Package, Node.js and application updates are managed on the host. Image tags and compose files make a stack reproducible; persistent volumes must be preserved during rollback.
Backups Back up host directories plus each database. Back up named volumes or bind mounts plus database dumps; do not treat an image as a backup.
Resource overhead Fewer layers and lower overhead. Container runtime and orchestration add some overhead but simplify repeatable deployment.

Choose direct services when you want the simplest path on a single VPS and are comfortable maintaining packages. Choose Docker when you already use compose files, need repeatable environments, or want application networks that make accidental public exposure less likely.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Prepare DNS and the VPS

1. Create the DNS records

Create an address record for each hostname pointing to the VPS address. For example, use example.com for WordPress and news.example.com for Ghost. Wait for the records to resolve before requesting certificates. Keep the Ghost hostname as its canonical URL; additional domains should redirect to it rather than serving a second canonical address.

2. Reserve the public ports

Install or enable one Nginx service and verify that it is the only process listening on 80 and 443. If you use Docker, publish those ports from the proxy container only. Do not publish Ghost’s 2368, database ports, or PHP-FPM sockets to the host internet interface.

3. Apply a minimal firewall

Allow SSH, HTTP and HTTPS, then deny other inbound traffic. A UFW policy commonly permits the SSH service and the HTTP/HTTPS services while leaving MySQL, MariaDB, PHP-FPM and port 2368 unexposed. Confirm that your current SSH connection remains allowed before enabling the firewall.

Install and isolate WordPress

Use a dedicated site directory and database

Place WordPress in its own document root, separate from Ghost’s content directory. Create a dedicated database and database user with only the privileges WordPress needs. Configure PHP-FPM with a site-specific pool or socket where practical, and ensure the Nginx worker can read WordPress files while write permissions are limited to directories that need uploads or updates.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Configure the WordPress URL

Set the WordPress site URL and home URL to the final HTTPS hostname. If you initially install over HTTP, change both values after the certificate is active and replace any hard-coded HTTP references in content. Incorrect URL values can create login redirects, mixed-content warnings or a site that appears under the wrong hostname.

Keep PHP-FPM private

Use a Unix socket or loopback address for PHP-FPM. Nginx should pass only requests for PHP scripts to that upstream; static files should be served directly. Never open the FPM listener in the firewall.

Install and isolate Ghost

Use Ghost’s supported runtime

Ghost’s documented stack uses Node.js 22 LTS, MySQL 8.0, Nginx and systemd on Ubuntu 24. Give Ghost its own application directory, Unix account and database credentials. Its default listener is 127.0.0.1:2368, which is suitable when Nginx runs directly on the host.

Set one canonical URL

Configure Ghost with https://news.example.com (using your actual hostname) as its canonical URL. Ghost’s CLI documentation specifies one canonical domain per installation. If another hostname must remain usable, redirect it to the canonical address at Nginx instead of configuring multiple independent canonicals.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Run Ghost under a service manager

Use systemd, as recommended in Ghost’s stack, so Ghost starts after reboot and can be inspected independently of Nginx. A running Nginx process does not prove that Ghost is healthy; check the Ghost service and its local listener separately.

Build the Nginx virtual hosts

Create two server blocks. The WordPress block points to its document root and PHP-FPM socket. The Ghost block proxies to http://127.0.0.1:2368. The following is a structural example; replace the document root and PHP-FPM socket with the paths used by your installation.

server {
    listen 80;
    server_name example.com;
    root /var/www/wordpress;
    index index.php index.html;

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

    location ~ .php$ {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass unix:/run/php/php-fpm.sock;
    }
}

Use the PHP-FPM socket that exists on your system; the filename varies by package and version. Restrict direct access to sensitive files according to your WordPress hardening policy.

server {
    listen 80;
    server_name news.example.com;

    location / {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://127.0.0.1:2368;
    }
}

Ghost is designed to have a reverse proxy in front of it. Preserve the original host and client information with the proxy headers above. In particular, an incorrect X-Forwarded-Proto value can make Ghost issue an HTTPS redirect loop.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Validate before reloading

  1. Check that each server_name is unique and matches DNS exactly.
  2. Run Nginx’s configuration test command and correct every syntax error before reloading.
  3. Confirm that WordPress’s PHP-FPM socket exists and that Ghost responds locally on port 2368.
  4. Reload Nginx only after the test succeeds.

Enable HTTPS at the edge

Obtain certificates for both hostnames at the Nginx edge and redirect HTTP requests to HTTPS. Ghost recommends SSL in production, and Ghost-CLI can create a Let’s Encrypt certificate and Nginx SSL configuration for a Ghost site. Whichever ACME method you use, certificate validation requires DNS to resolve to this VPS and inbound HTTP or the selected challenge method to reach the proxy.

After TLS is active, make sure the Ghost proxy sends X-Forwarded-Proto https for HTTPS requests. When Nginx terminates TLS, Ghost itself still receives an internal HTTP connection; the forwarded header tells it that the original request was secure. Test the WordPress login, Ghost Admin, canonical redirects and asset URLs from an external browser.

Docker-specific port and network design

Put the proxy, WordPress, Ghost and databases on controlled Docker networks. Publish only the proxy’s host ports 80 and 443. Ghost may listen on its container port internally; do not publish that port directly unless you deliberately use a different, firewalled host port for administration or testing.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Give WordPress and Ghost separate service names and persistent volumes.
  • Use separate database services or at least separate databases and credentials.
  • Make the proxy reach Ghost by its internal service name rather than exposing 2368 publicly.
  • Do not run a second Caddy or Nginx container that also publishes 80/443.
  • Keep compose files, environment files and volume locations in your backup plan, while keeping secrets out of public repositories.

Ghost’s Docker guidance requires MySQL 8, HTTPS and a correctly configured reverse proxy. A container being “up” does not guarantee that its application is reachable; test the proxy-to-container network path and inspect application logs.

Backups and recovery

Back up Ghost

Ghost-CLI’s ghost backup command creates a ZIP archive of Ghost site data. Store that archive outside the VPS as well as locally, and test that it can be read. A site-data archive is not a substitute for a tested database recovery process if your deployment keeps database data separately.

Back up WordPress

Capture the WordPress database and the complete WordPress files, including uploads, configuration and any custom themes or plugins. Keep database and file backups coordinated so a restore represents the same point in time. Store copies away from the VPS and document the credentials and paths needed for restoration.

Perform a restore drill

  1. Provision an isolated test VPS or private test network.
  2. Restore the WordPress database and files, then verify media, permalinks, login and scheduled tasks.
  3. Restore Ghost data and database, start the service, and verify the canonical URL and Admin access.
  4. Recreate Nginx certificates and proxy headers, then test both hostnames through HTTPS.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot the failure that matches the symptom

Ghost redirects forever between HTTP and HTTPS

Check the Ghost Nginx block first. The upstream request may be HTTP, but X-Forwarded-Proto must reflect the original HTTPS request. Verify that the canonical Ghost URL also uses HTTPS and that only one proxy is rewriting the scheme.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Nginx returns 502 Bad Gateway

Confirm that Ghost is running and listening on port 2368 or the configured internal port. From the proxy’s network namespace, test that address. For WordPress, verify the PHP-FPM service and socket path. A stale socket, stopped service or wrong container name produces the same 502 symptom.

A port is already allocated

Find the process or container claiming host port 80 or 443. Stop the extra Ghost Docker proxy, Caddy, Nginx instance or second compose stack, then publish those ports from the shared edge proxy only. Ghost itself does not need to claim either public port.

Large uploads fail

Increase Nginx’s client_max_body_size in the relevant server block when WordPress media or Ghost imports exceed the proxy default. Apply the change to the site that needs it, reload Nginx, and check any application-level upload limit as well.

The wrong site appears

Check DNS resolution, the browser’s requested hostname, Nginx server_name blocks and the Host header reaching the upstream. Then verify each application’s canonical URL. A default Nginx server block or stale DNS record can make a healthy site appear to be misconfigured.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The database is reachable from the internet

Inspect database bind addresses, Docker published ports and firewall rules. Bind MySQL or MariaDB to localhost or an internal network and remove public firewall access. Rotate credentials if a database was exposed.

Operating two sites after launch

  • Patch Ubuntu, Nginx, PHP, Node.js, MySQL or MariaDB and each application on a planned schedule.
  • Before upgrades, take fresh WordPress and Ghost backups and record the current versions.
  • Monitor disk space, memory, certificate expiry, Nginx errors and each application’s service status.
  • Keep logs separated by virtual host so a failing Ghost process is not confused with a WordPress PHP error.
  • Test both domains after every proxy, DNS, certificate or firewall change.
  • Document which service owns each port and where every persistent volume, database and backup is stored.

When a managed Ghost service is a better fit

Self-hosting gives you control over the VPS, networking, versions, filesystem and backup policy, but you also own patching, monitoring, certificates, capacity planning and recovery. Ghost identifies Ghost(Pro) as its official managed PaaS. Compare that option with a VPS on operational responsibility, control, maintenance burden and recurring service cost. WordPress remains on your VPS in either arrangement only if you deliberately keep the two deployments separate.

Final verification checklist

  • DNS: both hostnames resolve to the VPS.
  • Ports: only the shared Nginx proxy publishes 80 and 443.
  • WordPress: PHP 8.3+, MariaDB 10.11+ or MySQL 8.0+, HTTPS and a working PHP-FPM upstream.
  • Ghost: Node.js 22 LTS, MySQL 8.0, systemd, canonical HTTPS URL and a healthy listener on 127.0.0.1:2368 or its private container address.
  • Proxy: correct Host, X-Real-IP, X-Forwarded-For and X-Forwarded-Proto headers.
  • Security: SSH, HTTP and HTTPS allowed; database, PHP-FPM and Ghost ports private.
  • Recovery: separate backups for both sites and a completed restore test.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.