·9 min read·Updated Oct 21, 2026

Hosting Multiple Websites on One No-KYC VPS: Reverse Proxy, TLS and Isolation

How many sites fit on one VPS, how to route them with nginx or Caddy, isolate each site properly — and when separate projects should never share a server.

Yes, one VPS can host many websites — a €9.99/mo box with 2 vCPU and 4 GB RAM comfortably runs five to fifteen small sites, and the real limit is almost never CPU. It's RAM per application process, and whether you've isolated the sites well enough that one compromised WordPress install doesn't take the others with it. There's also a privacy limit most guides skip: sites that share an IP are trivially linkable to each other, which matters if the whole point of your no-KYC VPS was keeping projects separate.

This guide covers the practical side: how many sites each plan size realistically holds, how to route traffic by hostname with nginx or Caddy, how to isolate each site at the filesystem and process level, and when you should pay for a second server instead.

Direct answer: how many sites fit on one VPS

Count memory, not domains. Every site consumes a baseline even when idle:

Component Typical resident memory
nginx (master + 2 workers) 20–40 MB total, shared across all sites
PHP-FPM pool, 3 workers (WordPress) 150–350 MB per site
MariaDB/MySQL (one instance, many DBs) 250–500 MB total
Static site or SPA ~0 MB beyond nginx
Small Node/Python app 60–200 MB each
Docker daemon overhead 50–100 MB

So a realistic mapping against the current plans:

  • Iron 1 (1 vCPU / 1 GB / 15 GB NVMe, €4.99/mo) — several static sites, or one PHP site with a small database, or two or three low-traffic Node apps. Tight but workable if you keep MariaDB tuned down or use SQLite.
  • Iron 2 (2 vCPU / 4 GB / 35 GB NVMe, €9.99/mo) — the sweet spot for multi-site: roughly 4–8 WordPress-class sites plus a shared database server, or a dozen static/landing pages with room for a reverse proxy and monitoring.
  • Iron 3 (4 vCPU / 8 GB / 70 GB NVMe, €19.99/mo) — a dozen-plus PHP sites, or a handful of sites plus containers, Redis, and a staging copy of each.
  • Iron 4 (8 vCPU / 16 GB / 130 GB NVMe, €39.99/mo) — agency-scale or app-heavy setups where each site has its own container stack.

Disk is often the quieter constraint. A WordPress site with a media library grows faster than people expect, and 15 GB on Iron 1 disappears quickly once you add database dumps and local backup copies. Bandwidth is rarely the issue for websites — even 1 TB on Iron 1 is a lot of HTML.

Architecture: one front door, many back ends

The pattern that works, regardless of stack, is a single web server listening on 80/443 that routes by Host header to the right application, with each application running as its own unprivileged user.

Option A: nginx with per-site server blocks

The classic approach. One server block per domain, each with its own root, its own PHP-FPM pool, and its own access log.

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name example.com www.example.com;

    root /srv/sites/example.com/public;
    index index.php index.html;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    access_log /var/log/nginx/example.com.access.log;

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

The critical companion piece is a catch-all default block, so requests to your bare IP or an unknown hostname don't silently serve the first site in alphabetical order:

server {
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;
    server_name _;
    ssl_certificate     /etc/ssl/selfsigned/fullchain.pem;
    ssl_certificate_key /etc/ssl/selfsigned/privkey.pem;
    return 444;
}

return 444 closes the connection without a response. Combined with a plain-HTTP default block doing the same, this stops the easiest form of co-hosting discovery: scanning an IP range and reading whatever site answers by default.

Option B: Caddy with automatic TLS

If you'd rather not manage certbot renewals, Caddy issues and renews certificates itself and keeps the config short:

example.com {
    root * /srv/sites/example.com/public
    encode zstd gzip
    php_fastcgi unix//run/php/example-com.sock
    file_server
    log {
        output file /var/log/caddy/example.com.log
    }
}

blog.example.net {
    reverse_proxy 127.0.0.1:3000
}

:443 {
    abort
}

The trade-off: nginx has more documentation and more fine-grained tuning knobs; Caddy removes an entire class of "my cert expired and the cron job was broken" outages. For a multi-site box you maintain yourself, that reliability is worth a lot. Either way, this is still less overhead than a full hosting panel — if you're weighing that choice, the control panel vs plain nginx comparison covers the RAM and attack-surface costs.

Option C: containers behind a proxy

Each site gets its own container (app + its own database), and the host reverse-proxies to 127.0.0.1:<port>. Cleanest isolation, highest memory overhead — budget 50–100 MB per extra service plus the daemon. One warning: published Docker ports write their own forwarding rules and can bypass your host firewall entirely. Bind containers to 127.0.0.1:3000:3000 rather than 3000:3000, and read up on why Docker punches through nftables and ufw before you expose anything.

Isolation: the part that actually matters

Multi-site hosting fails badly when a single vulnerable plugin gives an attacker read access to every other site's config file — including database credentials and API keys.

Separate users per site. Create site-example as a system user with no shell, own /srv/sites/example.com as that user, and run that site's PHP-FPM pool under it:

[example-com]
user = site-example
group = site-example
listen = /run/php/example-com.sock
listen.owner = www-data
pm = ondemand
pm.max_children = 4
pm.process_idle_timeout = 30s
php_admin_value[open_basedir] = /srv/sites/example.com:/tmp
php_admin_value[disable_functions] = exec,passthru,shell_exec,system,proc_open,popen

pm = ondemand matters on small plans — idle sites release their workers instead of holding RAM all day. open_basedir keeps PHP from reading outside its own tree, which is what stops a compromised site from grepping /srv/sites/*/wp-config.php.

Set directory permissions to 0750 on each site root with the group set to the web server, so one site's user can't traverse into another's.

Separate database users. One MariaDB instance is fine; one database and one DB user per site is mandatory. Grant only on that database, never GRANT ALL ON *.*.

Use systemd sandboxing for app services. For Node, Python, or Go back ends, a unit file with ProtectSystem=strict, PrivateTmp=true, NoNewPrivileges=true, and an explicit ReadWritePaths= list costs nothing and removes most post-exploitation convenience.

Because IronBalkans ships real KVM virtualization with dedicated vCPU, RAM and NVMe rather than a shared container slice, the isolation work you do inside the VM is the actual security boundary for your sites — you're not also fighting noisy neighbours on an oversold node for the CPU time your PHP workers need. Deployment takes under 60 seconds after payment confirms, with no email, name or ID on the account, so spinning up a second box to split workloads is a decision about architecture rather than paperwork.

The privacy cost of co-hosting

This is the part that's specific to running an anonymous or compartmentalised setup, and it's easy to get wrong.

Shared IP links your projects. Reverse-IP lookup services, passive DNS datasets and simple scanning all make it cheap to enumerate every hostname pointing at one address. If two of your sites must never be publicly connected to each other, they cannot share an IP. No amount of nginx configuration fixes that — running two separate VPS is the only real answer, and at €4.99/mo for the smallest plan it's a cheap separation.

Certificates leak hostnames. Every publicly trusted certificate is published to Certificate Transparency logs. Issue a certificate covering a.example.com and b.example.org in one SAN list and you've permanently published the link between them. Issue one certificate per domain, always.

Shared fingerprints. Identical error pages, the same Server header version, the same TLS configuration order, the same favicon, the same analytics instance — any of these can suggest common operation. Separate certificates don't help if every site serves a byte-identical custom 404.

Logs accumulate across all sites. More sites means more IP addresses recorded on one disk. If your threat model includes seizure or compromise of the server, per-site access logs are the largest collection of visitor data you hold. Anonymising nginx logs and setting real retention is worth doing before you have ten sites' worth of history.

Common mistakes

No default server block. The single most common multi-site mistake. Without it, your bare IP serves a real site, which is exactly how people discover that project-a.com and project-b.net live on the same box.

One PHP-FPM pool for everything. Running all sites as www-data under a single pool means one compromise reads every site's secrets, and one runaway site starves all the others of workers.

Forgetting per-site resource limits. One site under a crawler flood can consume every PHP worker. Cap pm.max_children per pool and add a modest limit_req zone in nginx so a single hostname can't monopolise the server.

Backing up the whole box as one blob. Restoring a single broken site from a 60 GB tarball at 3 a.m. is miserable. Back up per site — files and a database dump — so you can restore one without touching the rest.

Letting disk fill. On Iron 1's 15 GB, the combination of media uploads, local database dumps and uncapped logs fills the disk faster than you'd think, and a full disk takes every site offline at once. Monitor free space and ship backups off-box.

Pros and cons of one VPS for many sites

In favour: dramatically lower cost per site — ten sites on a €9.99/mo plan is cents each; one set of updates, one firewall, one TLS story to maintain; shared services like Redis or a database server get used efficiently instead of being duplicated.

Against: a single point of failure for every project at once; one compromised site is a foothold next to all the others unless isolation is genuinely in place; sites are publicly linkable through a shared IP; a traffic spike on one affects all; and maintenance windows are shared whether the other sites need them or not.

FAQ

Do I need a separate IP for each site? No. SNI lets one IPv4 address serve unlimited HTTPS hostnames. Every plan includes one dedicated IPv4 plus a /64 IPv6 block, so if you do want hostnames on distinct addresses, you have effectively unlimited IPv6 to work with — just remember that most visitors will still arrive over the shared IPv4.

Can I add a site later without downtime? Yes. Adding a server block and reloading nginx (nginx -t && systemctl reload nginx) doesn't drop existing connections. Caddy reloads the same way.

Is a wildcard certificate better for multi-site? Only for many subdomains of one domain you already publicly associate. For unrelated domains, separate certificates keep CT logs from tying them together.

What if I outgrow the plan? Scale vertically to the next tier, or split by function — public sites on one server, backups and private services on another. Separation is often the better answer even when raw resources aren't the problem.

Get started

If you're consolidating several small sites, Iron 2 at €9.99/mo is the plan that fits most multi-site setups: 2 vCPU, 4 GB RAM and 35 GB NVMe is enough for a handful of PHP sites plus a reverse proxy, with headroom to add one more without re-architecting. If your projects need to stay unconnected, budget for two small servers instead of one bigger one.

Billing is flat monthly in Monero, Bitcoin or Litecoin, with no email or ID required and deployment in under a minute — pick a plan and deploy when you've decided how you want to split things up.

Written by IronBalkans. Last reviewed Oct 21, 2026.