• Home
  • Cloud VPS
    • Hong Kong VPS
    • US VPS
  • Dedicated Servers
    • Hong Kong Servers
    • US Servers
    • Singapore Servers
    • Japan Servers
  • Company
    • Contact Us
    • Blog
logo logo
  • Home
  • Cloud VPS
    • Hong Kong VPS
    • US VPS
  • Dedicated Servers
    • Hong Kong Servers
    • US Servers
    • Singapore Servers
    • Japan Servers
  • Company
    • Contact Us
    • Blog
ENEN
  • 简体简体
  • 繁體繁體
Client Area

How to Host Multiple Websites on One Hong Kong VPS with Nginx (2026)

July 15, 2026

One of the most cost-effective ways to use a Hong Kong VPS is to host multiple websites on a single server using Nginx virtual hosts. Instead of paying for a separate VPS for each domain, a single 4 GB VPS comfortably hosts 5–20 websites — each with its own domain, SSL certificate, PHP version, and database — while sharing the CN2 GIA network connection that gives all of them fast access from mainland China.


Architecture Overview


  Internet (CN2 GIA)
        ↓
  [Nginx on port 80/443]
  Reads: Host header from request
        ↓           ↓           ↓
  [site1.com]  [site2.com]  [site3.com]
  /var/www/1   /var/www/2   /var/www/3
  PHP 8.3-FPM  Node.js 20   Static HTML

Each “server block” in Nginx matches the incoming Host header and routes to the appropriate web root, application backend, or upstream proxy.


Step 1: Install Nginx and Create Directory Structure

apt update && apt install -y nginx certbot python3-certbot-nginx ufw

# Create organised directory structure
mkdir -p /var/www/{site1,site2,site3}
# Each site gets its own logs directory
mkdir -p /var/log/nginx/{site1,site2,site3}

# Create separate system users per site (security isolation)
useradd -r -s /bin/false site1user
useradd -r -s /bin/false site2user
useradd -r -s /bin/false site3user

# Set ownership
chown -R site1user:www-data /var/www/site1
chown -R site2user:www-data /var/www/site2
chown -R site3user:www-data /var/www/site3
chmod -R 750 /var/www/site1 /var/www/site2 /var/www/site3

ufw allow 80/tcp && ufw allow 443/tcp && ufw enable

Step 2: Virtual Host for Static HTML Site

cat > /etc/nginx/sites-available/site1.com << 'EOF'
server {
    listen 80;
    server_name site1.com www.site1.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name site1.com www.site1.com;

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

    root /var/www/site1;
    index index.html;

    access_log /var/log/nginx/site1/access.log;
    error_log  /var/log/nginx/site1/error.log;

    location / {
        try_files $uri $uri/ =404;
    }

    # Cache static assets aggressively
    location ~* \.(css|js|png|jpg|ico|svg|woff2)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}
EOF

ln -s /etc/nginx/sites-available/site1.com /etc/nginx/sites-enabled/
certbot --nginx -d site1.com -d www.site1.com

Step 3: Virtual Host for WordPress / PHP Site

cat > /etc/nginx/sites-available/site2.com << 'EOF'
server {
    listen 80;
    server_name site2.com www.site2.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name site2.com www.site2.com;

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

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

    access_log /var/log/nginx/site2/access.log;
    error_log  /var/log/nginx/site2/error.log;

    # WordPress-specific configuration
    location = /favicon.ico { log_not_found off; access_log off; }
    location = /robots.txt  { log_not_found off; access_log off; }

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

    location ~ \.php$ {
        # Use site-specific PHP-FPM pool (see Step 5)
        fastcgi_pass unix:/run/php/php8.3-fpm-site2.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

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

    location ~ /\. { deny all; }
}
EOF

ln -s /etc/nginx/sites-available/site2.com /etc/nginx/sites-enabled/
certbot --nginx -d site2.com -d www.site2.com

Step 4: Virtual Host for Node.js Application

cat > /etc/nginx/sites-available/site3.com << 'EOF'
upstream site3_node {
    server 127.0.0.1:3001;
    keepalive 32;
}

server {
    listen 80;
    server_name site3.com www.site3.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name site3.com www.site3.com;

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

    access_log /var/log/nginx/site3/access.log;
    error_log  /var/log/nginx/site3/error.log;

    location / {
        proxy_pass http://site3_node;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection '';
        proxy_set_header Host $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_cache_bypass $http_upgrade;
    }
}
EOF

ln -s /etc/nginx/sites-available/site3.com /etc/nginx/sites-enabled/
certbot --nginx -d site3.com -d www.site3.com
nginx -t && systemctl reload nginx

Step 5: Separate PHP-FPM Pools Per Site

Running all PHP sites through a single PHP-FPM pool means one site’s traffic affects all others. Separate pools provide isolation:

<code">cat > /etc/php/8.3/fpm/pool.d/site2.conf << 'EOF'
[site2]
user = site2user
group = www-data
listen = /run/php/php8.3-fpm-site2.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 5
pm.max_requests = 500

; Restrict to site2's directory only
php_admin_value[open_basedir] = /var/www/site2:/tmp
php_admin_value[error_log] = /var/log/nginx/site2/php-error.log
EOF

systemctl restart php8.3-fpm

The open_basedir restriction is the key security feature — PHP running for site2 cannot read files from site1 or site3’s directories, even if a vulnerability in site2’s application attempts to access them.


Step 6: Separate MySQL Databases Per Site

mysql -u root -p << 'SQL'
-- Separate database and user per site
CREATE DATABASE site1_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE site2_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE site3_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

CREATE USER 'site1db'@'localhost' IDENTIFIED BY 'Site1StrongPass!';
CREATE USER 'site2db'@'localhost' IDENTIFIED BY 'Site2StrongPass!';
CREATE USER 'site3db'@'localhost' IDENTIFIED BY 'Site3StrongPass!';

-- Each user can only access their own database
GRANT ALL ON site1_db.* TO 'site1db'@'localhost';
GRANT ALL ON site2_db.* TO 'site2db'@'localhost';
GRANT ALL ON site3_db.* TO 'site3db'@'localhost';
FLUSH PRIVILEGES;
SQL

Step 7: Per-Site Log Rotation

<code">cat > /etc/logrotate.d/nginx-multisites << 'EOF'
/var/log/nginx/site1/*.log
/var/log/nginx/site2/*.log
/var/log/nginx/site3/*.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    sharedscripts
    postrotate
        nginx -s reopen
    endscript
}
EOF

Step 8: Resource Limits Per Site

Prevent a single high-traffic site from consuming all VPS resources:

<code"># Rate limit per site in Nginx (separate zones per site)
# In /etc/nginx/nginx.conf http block:

http {
    limit_req_zone $binary_remote_addr zone=site1_limit:10m rate=20r/s;
    limit_req_zone $binary_remote_addr zone=site2_limit:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=site3_limit:10m rate=50r/s;
}

# In each site's server block, add:
# limit_req zone=site2_limit burst=20 nodelay;
<code"># PHP memory limit per pool
# In each pool's .conf file:
php_admin_value[memory_limit] = 256M
php_admin_value[max_execution_time] = 60

Monitoring Resource Usage Per Site

<code"># Check which sites are consuming the most requests
tail -n 1000 /var/log/nginx/site1/access.log | wc -l
tail -n 1000 /var/log/nginx/site2/access.log | wc -l

# PHP-FPM process count per pool
ps aux | grep php | grep "site2" | wc -l

# Disk usage per site
du -sh /var/www/site1 /var/www/site2 /var/www/site3

# Database size per site
mysql -u root -p -e "SELECT table_schema, ROUND(SUM(data_length + index_length)/1024/1024,2) AS 'MB' FROM information_schema.tables GROUP BY table_schema;"

How Many Sites Can One VPS Handle?

VPS RAMSites (low traffic)Sites (medium traffic)
2 GB3–51–2
4 GB8–123–5
8 GB20–308–12
16 GB50+20–30

“Low traffic” = under 500 daily visitors per site. “Medium traffic” = 500–5,000 daily visitors with database queries on most pages. Sites with Redis object caching scale significantly higher than these estimates.


Conclusion

Nginx virtual hosting on a Hong Kong VPS makes hosting multiple websites economical — one server, one CN2 GIA connection, multiple domains each with full SSL and PHP isolation. The key to doing it safely is separate PHP-FPM pools with open_basedir restrictions and separate MySQL users — preventing cross-site contamination even if one application has a security vulnerability.

Host all your sites: Browse Server.HK Hong Kong VPS plans — a 4 GB plan with NVMe SSD comfortably hosts 8–12 low-to-medium traffic WordPress sites, all with CN2 GIA routing.

Recent Posts

  • Hong Kong VPS vs Cloudflare Workers: Which for Asia-Pacific APIs? (2026)
  • How to Self-Host Gitea on Hong Kong VPS: Private Git Server (2026)
  • WooCommerce for China Market on Hong Kong VPS: Sell Cross-Border in 2026
  • Game Server on Hong Kong VPS: CS2, Valheim, and Minecraft for Asia (2026)
  • Linux Kernel and Sysctl Hardening for Hong Kong VPS Security (2026)

Recent Comments

  1. Hong Kong VPS Uptime and SLA: What 99.9% Uptime Really Means for Your Business (2026) - Server.HK on How to Monitor Your Hong Kong VPS: Uptime, Performance, and Alert Setup Guide (2026)
  2. Best Hong Kong VPS Providers in 2026: Compared by Speed, Routing, and Value - Server.HK on How to Migrate Your Website to a Hong Kong VPS: Zero-Downtime Transfer Guide (2026)
  3. vibramycin injection on How to Choose the Right Hong Kong VPS Plan: A Buyer’s Guide for 2026
  4. allopurinol for gout on CN2 GIA vs BGP vs CN2 GT: What’s the Real Difference for China Connectivity?
  5. antibiotics online purchase on How to Set Up a WordPress Site on a Hong Kong VPS with aaPanel (Step-by-Step 2026)

Knowledge Base

Access detailed guides, tutorials, and resources.

Live Chat

Get instant help 24/7 from our support team.

Send Ticket

Our team typically responds within 10 minutes.

logo
Alipay Cc-paypal Cc-stripe Cc-visa Cc-mastercard Bitcoin
Cloud VPS
  • Hong Kong VPS
  • US VPS
Dedicated Servers
  • Hong Kong Servers
  • US Servers
  • Singapore Servers
  • Japan Servers
More
  • Contact Us
  • Blog
  • Legal
© 2026 Server.HK | Hosting Limited, Hong Kong | Company Registration No. 77008912
Telegram
Telegram @ServerHKBot