Host several WordPress sites on one server, each one isolated

On Nextweb each WordPress site has its own copy, database and user, PHP processes and port. What a second site, a failing site and an undeploy look like.

· Updated · about 7 minutes to read

The free license covers three sites on one machine, so the dry run below fits in it. More sites, or a second machine, is what the Developer license is for: five machines and ten sites, at beta prices, and Enterprise has no site limit (pricing). This is what several WordPress sites look like on Nextweb, with the output of the dry run of 17 October 2026, in which a second site joined the first, a third failed on purpose, and both were removed again. The addresses are the first instance's on a machine; yours may differ.

The first site

Four commands deploy it: deploy, commit, apply and verify. Self-host WordPress on Linux without Docker walks through them with every line of output, from the download to the browser. The first site, company-site, ended up on port 4001 with a database wp_company_site and two PHP processes on 19100.

The second site

At the nextweb prompt
deploy blog to blog.example.com using wordpress
commit "Deploy blog"
apply -y
You should see
Committed: Deploy blog
Configuration validated.
Configuration written.
Applying configuration...

Applying site configuration...
Service mariadb: running (manage with "service mariadb status" / "service mariadb restart")
company-site: unchanged, running

Site: blog (blog.example.com)
  Allocated site listen port 4004 for blog
  Provisioning database for site blog...
  MariaDB running (socket /tmp/nw-maria-f982b35671ab.sock)
  Database wp_blog and user wp_blog ready
  Starting PHP runtime for site...
  php-cgi listening on 19101 (2 processes, opcache off)
blog: WordPress provisioned at /home/you/nextweb-tour/nextweb_server/sites/blog/wordpress
Service blog: registered (manage with "service blog status" / "service blog restart")
Visit: http://127.0.1.10:4004/
Webserver reloaded (site listen ports bound)

Site apply complete.

Configuration changes complete!
Changes 1, Warnings 0, Errors 0

apply touched only what changed: the first site is reported unchanged and left running. The second got the next free port, a database and user of its own, and two PHP processes of its own on the next port. verify blog then asked it for a page:

At the nextweb prompt
verify blog
You should see
Verifying site: blog
wp-config.php present
state.json (domain: blog.example.com, status: applied)
database configuration present in site state
HTTP check passed (200)
Response contains WordPress markers
vhost conf.d: blog.js

Visit: http://127.0.1.10:4004/

All checks passed.

What each site owns, and what they share

Each site has:

  • its own copy of WordPress, in nextweb_server/sites/<site>/wordpress, about 106 MB on this run, which WordPress keeps up to date itself;
  • its own database and its own database user, created by apply;
  • its own two php-cgi processes on a port of their own, so a request stuck on one site is that site's;
  • its own listen port, which the web server routes to by the site's domain;
  • its own log, nextweb_server/logs/<site>.log, read with show log <site>;
  • its own service entry: service blog status, service blog restart.

The sites in one folder share one MariaDB server, the PHP binaries in runtime/, and Nextweb's web server. Nothing at the WordPress level is shared: no table, no plugin folder, no theme.

When one site fails, the others keep running

The dry run makes a third site fail on purpose: it deploys broken, takes away write permission on the site's folder, and applies.

At the nextweb prompt
apply -y
You should see
Applying configuration...

Applying site configuration...
Service mariadb: running (manage with "service mariadb status" / "service mariadb restart")
company-site: unchanged, running
blog: unchanged, running

Site: broken (broken.example.com)
  Allocated site listen port 4005 for broken
  Provisioning database for site broken...
  MariaDB running (socket /tmp/nw-maria-f982b35671ab.sock)
  Database wp_broken and user wp_broken ready
broken: EACCES: permission denied, open '/home/you/nextweb-tour/nextweb_server/sites/broken/wordpress/wp-config.php'

Site apply finished with 1 error(s).

Configuration changes applied with errors.
Changes 0, Warnings 0, Errors 1

The two running sites are named as unchanged and left alone; the failing one is named with its error. verify broken says what is wrong and what to do:

You should see
Verifying site: broken
wp-config.php missing — run apply
state.json (domain: broken.example.com, status: failed)
Last apply failed: EACCES: permission denied, open '/home/you/nextweb-tour/nextweb_server/sites/broken/wordpress/wp-config.php'. Fix it, then: apply (or reload broken)
...
Site verification: FAILED

With the permission restored, the next apply picks the site up where it failed, and it comes up on a port of its own like the others.

Taking a site down

undeploy stops a site and keeps its files and its database, so deploying the same name again picks up where it was:

At the nextweb prompt
undeploy blog -y
You should see
Service blog: stopped and removed
Port 4004 released
blog: removed from the configuration
Webserver reloaded
Kept /home/you/nextweb-tour/nextweb_server/sites/blog and database wp_blog. Remove them with: undeploy blog --purge

Site blog undeployed.
Changes 1, Warnings 0, Errors 0

undeploy <site> --purge drops the database and its user and deletes the folder too. Through all of it, verify company-site kept passing.

This is not Multisite

WordPress's own documentation describes a multisite network as "a collection of sites that all share the same WordPress installation core files", which "can also share plugins and themes" while "they do have separate tables in the database" (developer.wordpress.org, read 17 October 2026). On Nextweb the sites share none of that: each is a separate WordPress with its own files, its own database and user, its own PHP processes and its own port. The cost is disk, one WordPress copy per site; the gain is that a plugin, an update or a fault on one site stays on that site.

Taking them public

Each site is a domain, so each gets its own server block in nginx, pointing at its own port, and its own certificate, and each site's wp-config.php gets its public address in WP_HOME and WP_SITEURL. The steps are the same as for one site, in Self-host WordPress on Linux without Docker.

What this does not do

  • Count sites for you. The license sets the number: one on the free license, ten on Developer, ten for each Team seat, no limit on Enterprise.
  • Separate MariaDB per site. One server holds every site's database, and service mariadb restart restarts it for all of them.
  • Get certificates, run offline, or run anywhere but Linux x64. Nextweb checks its license each time it starts, and HTTPS is yours to add in front.
  • Run a PHP application that is not WordPress. deploy knows WordPress and a Node.js application of your own.

Next step

Download Nextweb and deploy the first site with the first lesson; the second takes the same three commands.

Questions

How many sites can one license run?

The free license covers three sites on one machine. A Developer license covers ten sites across five machines, Team ten sites for each seat, and Enterprise has no site limit. Every tier allows commercial use.

Do the sites share a database?

They share one MariaDB server and nothing inside it. Each site has its own database and its own database user, created by apply.

Is this WordPress Multisite?

No. Multisite is one WordPress installation serving several sites, which share its core files and can share plugins and themes. On Nextweb each site is a separate WordPress with its own files, database, PHP processes and port.

What happens when one site fails to apply?

apply reports the failure, marks that site failed and leaves the others running. verify names what to fix, and the next apply picks the site up where it stopped.

Related: Self-host WordPress on Linux without Docker, How a deploy works, Pricing.