Nginx Server Blocks and Virtual Hosts Hosting Multiple Apps on One Server
Learn how to use Nginx server blocks (virtual hosts) to host multiple Node.js applications on a single EC2 instance with different domains or subdomains.
Nginx Server Blocks and Virtual Hosts
Server blocks (also called virtual hosts) allow you to host multiple websites or applications on a single Nginx instance. Each server block handles requests for a specific domain or subdomain.
Why Use Server Blocks?
If you have:
api.yourdomain.comBackend API (Node.js on port 3000)yourdomain.comFrontend (React static files)admin.yourdomain.comAdmin panel (Node.js on port 3001)
You can host all three on one EC2 instance using server blocks.
Server Block 1: API (api.yourdomain.com)
sudo nano /etc/nginx/sites-available/devtinder-api
server { listen 80; server_name api.yourdomain.com; location / { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; 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; } }
Server Block 2: Frontend (yourdomain.com)
sudo nano /etc/nginx/sites-available/devtinder-frontend
server { listen 80; server_name yourdomain.com; root /home/ubuntu/devtinder-frontend/dist; location / { try_files $uri $uri/ /index.html; } # Cache static assets location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ { expires 1y; add_header Cache-Control "public, immutable"; } }
Server Block 3: Admin Panel (admin.yourdomain.com)
sudo nano /etc/nginx/sites-available/devtinder-admin
server { listen 80; server_name admin.yourdomain.com; location / { proxy_pass http://localhost:3001; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
Enable All Server Blocks
sudo ln -s /etc/nginx/sites-available/devtinder-api /etc/nginx/sites-enabled/ sudo ln -s /etc/nginx/sites-available/devtinder-frontend /etc/nginx/sites-enabled/ sudo ln -s /etc/nginx/sites-available/devtinder-admin /etc/nginx/sites-enabled/ sudo rm /etc/nginx/sites-enabled/default sudo nginx -t sudo systemctl restart nginx
Default Server Block
If no server block matches the request's Host header, Nginx uses the first server block. To specify a default:
server { listen 80 default_server; server_name _; return 444; # Connection closed }
This blocks requests with unknown Host headers.
SSL for Multiple Domains
Get SSL certificates for all domains:
sudo certbot --nginx -d yourdomain.com -d api.yourdomain.com -d admin.yourdomain.com
Or individually:
sudo certbot --nginx -d yourdomain.com sudo certbot --nginx -d api.yourdomain.com sudo certbot --nginx -d admin.yourdomain.com
Load Balancing with Upstream
If you have multiple Node.js instances:
upstream devtinder_backend { server 127.0.0.1:3000; server 127.0.0.1:3001; server 127.0.0.1:3002; } server { listen 80; server_name api.yourdomain.com; location / { proxy_pass http://devtinder_backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; # ... other headers ... } }
Nginx distributes requests across the three instances using round-robin by default.
The Takeaway
Nginx server blocks let you host multiple apps on one EC2 instance by routing based on the domain name. Create a server block for each domain (api, frontend, admin), enable them with symlinks, and use certbot to get SSL for all domains. For multiple Node.js instances, use the upstream directive for load balancing.
Create a server block for each domain or subdomain. Each server block has a different server_name and proxy_pass or root. Enable all with symlinks to sites-enabled, test with nginx -t, and restart. Use certbot to get SSL for all domains.
A server block (also called virtual host) is a configuration section that defines how Nginx handles requests for a specific domain. It includes listen port, server_name, and location blocks for routing. Multiple server blocks allow hosting multiple sites on one server.
Use the upstream directive to define a pool of backend servers (e.g., upstream mybackend { server 127.0.0.1:3000; server 127.0.0.1:3001; }). Then use proxy_pass http://mybackend in the location block. Nginx distributes requests using round-robin by default.
Nginx uses the first server block as the default. You can explicitly set a default with listen 80 default_server and return 444 to close connections with unknown Host headers, preventing access via IP address directly.
Run sudo certbot --nginx -d yourdomain.com -d api.yourdomain.com -d admin.yourdomain.com to get one certificate for all domains (SAN certificate). Or run certbot separately for each domain to get individual certificates.
Ready to master Node.js completely?
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.
Master Node.js
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course.

