The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →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
Antihost offers managed WordPress hosting with free migration, one-click staging and a 14-day free trial.
The safest pattern for independent WordPress sites on one LEMP VPS is one Unix account, document root, Nginx server block, PHP-FPM pool and local socket, database, and database user per domain. Correct ownership and permissions keep a compromised site from casually reading another site’s files, while separate databases limit credential and data exposure.
This guide shows a repeatable setup for Debian- or Ubuntu-style systems, explains the permission and socket details that are easy to get wrong, and provides verification and recovery checks. The commands are examples; adapt package names and PHP-version paths to your distribution.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Architecture that keeps sites separate
Map every site to its own operating-system and application resources. A request for example.com should never depend on a shared document root, shared PHP worker identity, or shared database password.
| Layer | Per-site resource | Purpose |
|---|---|---|
| Unix identity | site1, site2 (non-login service accounts) |
PHP processes and file operations run with only that site’s permissions. |
| Files | /home/site1/public/, /home/site2/public/ |
Each installation has a separate document-root tree. |
| Nginx | One server {} block per domain |
Routes the hostname to the correct root and PHP socket. |
| PHP-FPM | One named pool and Unix socket per site | Workers use the site’s UID/GID instead of a common PHP user. |
| Database | One database and least-privilege database user per site | A leaked credential grants access only to that site’s tables. |
| Logs and backups | Separate paths and backup sets | Investigate incidents and restore one site without mixing data. |
A practical layout is:
/home/site1/public/
/home/site2/public/
/run/php/site1.sock
/run/php/site2.sock
/etc/php/<version>/fpm/pool.d/site1.conf
/etc/php/<version>/fpm/pool.d/site2.conf
/etc/nginx/sites-available/site1.conf
/etc/nginx/sites-available/site2.conf
The WordPress Nginx handbook documents the per-site root and server-block pattern. PHP’s pool model supports different UIDs, GIDs, sockets and per-pool limits, which is what makes the process boundary useful.
#1 Best Overall
Plan the server before deploying
Confirm DNS and resource headroom
Create an A or AAAA record for every domain and verify that each name resolves to the VPS before troubleshooting Nginx. Leave capacity for the operating system, database server and all PHP pools; eight workers per pool is only an example, not a safe universal value. RAM usage, PHP version, traffic and plugin workload determine the appropriate pool limits.
Choose independent installations deliberately
Use separate WordPress installations when sites belong to different customers, require different plugins or themes, follow different PHP or update schedules, or need stronger filesystem and database boundaries. WordPress Multisite shares core files and central administration; it is useful when one organization wants a network of sites managed together, but it is not a substitute for per-customer isolation.
Install only required services
- Nginx
- A supported PHP version with PHP-FPM and the extensions required by your themes and plugins
- A MySQL-compatible database server
- DNS management and an ACME client supplied by your distribution for HTTPS
- Optional ACL tooling (
setfacl) if you want precise web-server traversal and read permissions
Build each site in a repeatable sequence
-
Point the domain at the VPS
Publish DNS records for
example.comandwww.example.com(and the equivalent names for every additional site). Wait for the records to resolve from outside the server. Do not enable a catch-all virtual host that could send an unknown hostname to the wrong installation. -
Create a non-login Unix account and directory tree
On a Debian- or Ubuntu-style host, create one system account per site:
sudo useradd --system --home /home/site1 --shell /usr/sbin/nologin site1 sudo mkdir -p /home/site1/public /home/site1/logs sudo chown -R site1:site1 /home/site1 sudo chmod 750 /home/site1Repeat with
site2and its home directory. The account should not have an interactive shell or sudo rights. Keep each site’s files outside directories readable by another site account.Nginx, commonly running as
www-data, needs only traversal of the path and read access to static files. If ACLs are available, grant those rights without granting write access:Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.Rank #2
sudo setfacl -m u:www-data:--x /home/site1 sudo setfacl -R -m u:www-data:rX /home/site1/publicAlternatively, use a dedicated group and group-read permissions, but do not put all site accounts in one shared writable group. Avoid
chmod 777. Make only deliberately writable paths, such aswp-content/uploads, writable by the PHP process. -
Install WordPress files with ownership in mind
Obtain the package from WordPress.org, extract it into
/home/site1/public, and set ownership tosite1:site1. Keep normal directories non-writable by unrelated users and restrictwp-config.phpafter configuration:sudo chown -R site1:site1 /home/site1/public sudo find /home/site1/public -type d -exec chmod 750 {} ; sudo find /home/site1/public -type f -exec chmod 640 {} ; sudo chmod 640 /home/site1/public/wp-config.phpWordPress automatic file operations run as the owner of the files. Therefore, your update workflow and ownership must agree: either let the site-owned PHP process perform updates, or run command-line maintenance as
site1. Do not make the entire tree world-writable merely to avoid an update prompt. -
Create a PHP-FPM pool and private socket
Create
/etc/php/<version>/fpm/pool.d/site1.conf:[site1] user = site1 group = site1 listen = /run/php/site1.sock listen.owner = www-data listen.group = www-data listen.mode = 0660 pm = ondemand pm.max_children = 8The pool name, Unix user and group, and socket path must be unique.
listen.mode = 0660lets Nginx connect through the socket’s owner/group without exposing a network listener. PHP documents that an exposed FastCGI endpoint can permit arbitrary code execution; keep FPM on a local Unix socket and never publish it to the Internet.What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.pm.max_children = 8is a starting example from a deployment pattern, not a recommendation for every VPS. Size it after measuring memory per PHP worker and leaving headroom for the database and other pools. Use separate pool settings for slow sites rather than allowing one workload to consume all workers.Duplicate the file for
site2, changing the pool name, UID/GID and socket. Reload PHP-FPM only after checking the configuration with your distribution’s service command. -
Create a database and database user for the site
Log in to the database server as an administrator and create credentials that are never reused by another site:
CREATE DATABASE site1_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'site1_db_user'@'localhost' IDENTIFIED BY 'use-a-long-random-secret'; GRANT ALL PRIVILEGES ON site1_db.* TO 'site1_db_user'@'localhost'; FLUSH PRIVILEGES;Run the equivalent statements for
site2with different names and a different password. Grant privileges on the site’s database only; do not grant global privileges or use one administrator account in multiplewp-config.phpfiles. WordPress hardening guidance recommends separate databases and users when several blogs share a server.Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchSpecial offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy. -
Configure
wp-config.phpCopy the sample configuration, set the database name, user, password and host, and generate unique authentication salts for each installation. A minimal database section looks like:
define( 'DB_NAME', 'site1_db' ); define( 'DB_USER', 'site1_db_user' ); define( 'DB_PASSWORD', 'use-a-long-random-secret' ); define( 'DB_HOST', 'localhost' );Use a distinct table prefix for each installation even though the databases are already separate; it provides an additional safeguard if a backup is accidentally imported into the wrong database. Keep the file readable by the site account and by the PHP process running under that account, but not writable by Nginx.
-
Create one Nginx server block per domain
Save this as
/etc/nginx/sites-available/site1.conf:server { listen 80; server_name example.com www.example.com; root /home/site1/public; index index.php; location / { try_files $uri $uri/ /index.php?$args; } location ~ .php$ { try_files $uri =404; include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/site1.sock; } location ~* /.ht { deny all; } }For the second site, change
server_name,rootandfastcgi_pass. Keep common security rules in reviewed include files where practical, but inspect every copied rule: a typo in a location block can expose a configuration or incorrectly route PHP.Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.Rank #4
Enable each site using your distribution’s sites-enabled convention, test the complete configuration, and reload only after the test succeeds:
sudo nginx -t sudo systemctl reload nginx -
Start or reload PHP-FPM and Nginx
Reload the PHP-FPM service for the installed version, then reload Nginx. Check that each socket exists and has the expected owner, group and mode:
ls -l /run/php/site1.sock /run/php/site2.sock getfacl /home/site1/publicA missing socket usually means the pool failed to parse or the service was not reloaded. A permission-denied error usually means the socket group or directory traversal permissions do not allow Nginx to connect.
-
Complete HTTPS configuration
Use the ACME client supported by your distribution to issue certificates for every hostname, then configure Nginx to redirect HTTP to HTTPS. Test both the certificate and renewal process; an expired certificate can take every site offline even when the individual WordPress installations are healthy. HTTPS protects administrator logins, cookies and visitor traffic and should be treated as an operational requirement.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Clear out junk files and repair common Windows errors3Fix the driver behind crashes, sound loss and screen glitchesSpecial offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy. -
Finish the WordPress installer and verify the site
Open each HTTPS domain and complete the installer with that site’s database credentials. Then test:
/wp-adminlogin and logout- A pretty permalink after saving the intended permalink structure
- An image upload into
wp-content/uploads - A plugin or core update using the planned ownership workflow
- A scheduled task, either through WordPress cron or your chosen system scheduler
- That the site logs contain the request and the other site’s logs do not
From a browser or command-line HTTP client, request both domains and confirm that each returns the correct title, files and cookies. Never infer correct isolation from a successful front page alone.
-
Configure backups, monitoring and incident procedures
Back up each database and document root separately to storage outside the VPS. Retain enough history to recover from delayed discovery of a compromised plugin. Monitor disk space, PHP-FPM pool saturation, Nginx errors, certificate renewal and backup success. Write down how to disable one site, rotate its database credentials, preserve logs and restore it without taking unrelated sites offline.
Permissions that prevent cross-site file reads
Isolation depends on the complete path, not just the final file mode. A site account must not be able to traverse another site’s home directory, and Nginx must receive only the read and traversal rights needed to serve public files. Keep private material such as backups, deployment keys and configuration exports outside every document root.
- Owner: the site’s Unix account.
- Group: a narrowly scoped group, not a group containing every site account.
- Directories: executable for the owner and the explicitly authorized web-server identity; writable only where required.
- Files: readable by the owner and the web-server identity when Nginx must serve them; generally not writable by Nginx.
wp-content/uploads: writable by the site’s PHP process, with execution of uploaded scripts blocked by Nginx rules appropriate to your deployment.wp-config.php: not writable by Nginx and not readable by other site accounts.
Test permissions as the actual identities rather than as root. For example, use sudo -u site1 to verify that site1 can update its own files, and use sudo -u site1 with a read attempt against site2’s document root to confirm it is denied. Root can bypass these checks, so a root test does not prove tenant isolation.
How to diagnose common failures
| Symptom | Likely cause | Checks and correction |
|---|---|---|
| 502 Bad Gateway | Socket missing, wrong path, or Nginx cannot connect | Inspect the PHP-FPM pool log, verify the socket path, and check socket owner/group/mode and directory traversal. |
| 403 Forbidden for static files | Nginx lacks execute permission on a parent directory or read permission on files | Review every directory in /home/site1/public; grant only the required ACL or group-read permission. |
| WordPress asks for FTP credentials during updates | Files are owned by a different identity than the PHP worker | Align ownership with the site1 pool or run the update as the owner; do not use 777 as a workaround. |
| Wrong site appears for a hostname | Duplicate or missing server_name, DNS pointing elsewhere, or an unintended default server |
Run nginx -t, inspect enabled blocks, test the Host header and confirm DNS answers. |
| Database connection error | Wrong credentials, host, database name or grants | Test the site’s account against only its database and compare the values in wp-config.php. |
| One site consumes all CPU or memory | Unbounded or oversized PHP-FPM pools, a plugin loop or traffic spike | Review per-pool worker counts and logs, lower limits carefully, and investigate the offending workload before increasing VPS size. |
| Uploads fail but pages work | wp-content/uploads is not writable by the site account or PHP pool |
Create the directory with site ownership and grant write permission only there. |
Independent installs versus WordPress Multisite
Multisite hosts several sites from one WordPress installation and shares core files and network administration. It can simplify centralized updates and governance when one organization controls every site. The network configuration must be planned at creation time; Nginx generally needs the appropriate network rewrite rules from the beginning.
Choose independent installs when customers must not share an administrative surface, when one site needs a different plugin or theme lifecycle, when PHP versions may diverge, or when a stronger filesystem and database boundary is a requirement. Separate installs cost more to update and monitor, but they make ownership, credentials, backups and incident response explicit.
Understand what this isolation does not protect
Separate accounts and pools reduce the blast radius of ordinary file-permission mistakes and many WordPress-level compromises. They are not a complete security boundary. All sites still share the Linux kernel, the Nginx master process, the database service, the VPS administrator account, hardware and other host resources. A kernel vulnerability, host compromise, malicious administrator or vulnerable shared component can cross those boundaries.
Recommended Free Tools
Treat a vulnerable plugin or theme as a possible host-level incident: preserve logs, disable the affected site or pool, rotate its database and WordPress secrets, inspect neighboring sites, patch the vulnerable component and restore from a known-clean backup. Keep the operating system, PHP, Nginx, database server, WordPress core, themes and plugins current. Review writable directories after every deployment and test full restores rather than assuming that a successful backup job is recoverable.
Per-site maintenance checklist
- Confirm DNS, HTTPS renewal and HTTP-to-HTTPS redirects for every domain.
- Check that each Nginx block still points to the intended root and PHP socket.
- Review PHP-FPM worker usage and error logs per pool.
- Verify that database users have privileges only on their own databases.
- Audit ownership and permissions after updates, migrations and restores.
- Test administrator login, permalinks, uploads and scheduled tasks after PHP or Nginx changes.
- Run an off-site backup restore for at least one site on a schedule, then rotate credentials used by the restored copy.
- Document who can access the VPS and remove unused shells, keys and service accounts.
With this layout, a hostname selects one Nginx root, PHP executes under that site’s Unix identity through a private socket, and database credentials stop at that site’s database. That is the practical foundation for hosting multiple WordPress sites on one LEMP server while keeping failures and compromises from automatically becoming everyone else’s problem.
Quick Recap
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.

