How to Configure Virtual Hosts in Nginx on Ubuntu
Configuring virtual hosts in Nginx is one of the most powerful techniques for hosting multiple websites on a single server, each with its own domain name, root directory, and independent configuration. Nginx handles this through server blocks — flexible, lightweight configuration units that define how the web server responds to requests for each domain.
Whether you're managing a personal portfolio, running client websites, or scaling a multi-tenant application, this guide provides a complete, production-ready walkthrough for setting up Nginx virtual hosts on Ubuntu. We'll cover directory structure, server block configuration, enabling sites, SSL/HTTPS setup, and troubleshooting — everything you need to go from zero to a fully functional multi-site Nginx server.
> Looking for a reliable Ubuntu server to follow along? AlexHost's VPS Hosting plans give you full root access, SSD storage, and instant deployment — perfect for this exact use case.
Table of Contents
- Prerequisites
- Set Up Directories for Each Website
- Create Sample HTML Content
- Create Virtual Host Configuration Files
- Enable the Virtual Hosts
- Test the Nginx Configuration
- Restart Nginx to Apply Changes
- Access Your Websites
- Enable HTTPS with Let's Encrypt (Recommended)
- Troubleshooting Common Issues
- Conclusion
Prerequisites
Before you begin, make sure the following conditions are met:
Nginx Installed on Your Server
If Nginx is not yet installed, run the following commands on your Ubuntu server:
sudo apt update
sudo apt install nginxVerify the installation and check that the service is running:
sudo systemctl status nginxYou should see active (running) in the output. If not, start it manually:
sudo systemctl start nginx
sudo systemctl enable nginxDomain Names Pointed to Your Server
Each virtual host requires a domain name that resolves to your server's public IP address. You'll need to create A records in your DNS settings pointing to the server's IP.
> Need a domain? Register yours through AlexHost Domain Registration and manage DNS records directly from your control panel.
For local testing purposes, you can bypass DNS entirely by editing your /etc/hosts file (covered in Step 7).
Required Permissions
You'll need sudo privileges on your Ubuntu server to create directories, edit configuration files, and manage the Nginx service.
Step 1: Set Up Directories for Each Website
Each website hosted on your server should have its own isolated directory to store web files. This separation keeps your projects organized and prevents configuration conflicts.
In this guide, we'll configure two example domains: example1.com and example2.com. Replace these with your actual domain names throughout.
Create the Web Root Directories
sudo mkdir -p /var/www/example1.com/html
sudo mkdir -p /var/www/example2.com/htmlThe -p flag creates all intermediate directories as needed.
Assign Correct Ownership
Grant ownership of these directories to www-data, the system user that Nginx runs as:
sudo chown -R www-data:www-data /var/www/example1.com/html
sudo chown -R www-data:www-data /var/www/example2.com/htmlThis ensures Nginx has the necessary read permissions to serve files from these directories.
Set Directory Permissions
sudo chmod -R 755 /var/wwwThe 755 permission means the owner has full read/write/execute access, while groups and other users have read and execute access — appropriate for publicly served web content.
Step 2: Create Sample HTML Content
To verify that each virtual host is working correctly, create a simple index.html file for each site.
For example1.com
echo "<h1>Welcome to Example1.com!</h1>" | sudo tee /var/www/example1.com/html/index.htmlFor example2.com
echo "<h1>Welcome to Example2.com!</h1>" | sudo tee /var/www/example2.com/html/index.htmlThese placeholder pages will confirm that Nginx is routing requests to the correct document root for each domain.
Step 3: Create Virtual Host Configuration Files
Nginx stores site configuration files in /etc/nginx/sites-available/. Each file defines a server block — the Nginx equivalent of an Apache virtual host. Enabled sites are then symlinked into /etc/nginx/sites-enabled/.
Configuration for example1.com
Create a new configuration file:
sudo nano /etc/nginx/sites-available/example1.comAdd the following server block:
server {
listen 80;
listen [::]:80;
server_name example1.com www.example1.com;
root /var/www/example1.com/html;
index index.html index.htm;
access_log /var/log/nginx/example1.com.access.log;
error_log /var/log/nginx/example1.com.error.log;
location / {
try_files $uri $uri/ =404;
}
}Save and close the file (Ctrl+X, then Y, then Enter).
Configuration for example2.com
Create a second configuration file:
sudo nano /etc/nginx/sites-available/example2.comAdd the following server block:
server {
listen 80;
listen [::]:80;
server_name example2.com www.example2.com;
root /var/www/example2.com/html;
index index.html index.htm;
access_log /var/log/nginx/example2.com.access.log;
error_log /var/log/nginx/example2.com.error.log;
location / {
try_files $uri $uri/ =404;
}
}Key Directives Explained
| Directive | Purpose |
|---|---|
listen 80 | Listens for incoming HTTP connections on port 80 |
listen [::]:80 | Enables IPv6 support on port 80 |
server_name | Defines which domain names this block handles |
root | Sets the document root — where website files are stored |
index | Specifies the default file to serve when a directory is requested |
try_files | Attempts to serve the requested file; returns 404 if not found |
access_log / error_log | Separate log files per site for easier debugging |
Step 4: Enable the Virtual Hosts
Nginx activates sites by creating symbolic links from sites-available to sites-enabled. This design allows you to prepare configurations without immediately activating them.
sudo ln -s /etc/nginx/sites-available/example1.com /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/example2.com /etc/nginx/sites-enabled/Remove the Default Site (Optional but Recommended)
If you want to prevent Nginx's default placeholder page from interfering, disable it:
sudo rm /etc/nginx/sites-enabled/defaultYou can always re-enable it later by recreating the symlink.
Step 5: Test the Nginx Configuration
Before restarting Nginx, always validate your configuration files for syntax errors. A misconfigured file can bring down all sites on the server.
sudo nginx -tA successful test returns:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successfulIf you see errors, Nginx will indicate the file and line number where the problem occurred. Review the relevant configuration file and correct any typos or missing semicolons before proceeding.
Step 6: Restart Nginx to Apply Changes
Once the configuration test passes, reload or restart Nginx to apply your changes:
sudo systemctl restart nginxAlternatively, use reload for a graceful restart that doesn't interrupt active connections:
sudo systemctl reload nginxStep 7: Access Your Websites
If DNS Is Already Configured
If your domain names are already pointing to your server's IP address via DNS A records, simply open a browser and navigate to:
http://example1.comhttp://example2.com
You should see the respective "Welcome" messages you created in Step 2.
For Local Testing (Without DNS)
If you're testing locally or DNS hasn't propagated yet, you can simulate domain resolution by editing your local machine's /etc/hosts file (on Linux/macOS) or C:WindowsSystem32driversetchosts (on Windows).
Open the file with elevated privileges:
sudo nano /etc/hostsAdd the following lines, replacing YOUR_SERVER_IP with your actual server IP:
YOUR_SERVER_IP example1.com www.example1.com
YOUR_SERVER_IP example2.com www.example2.comSave the file and test in your browser. Remember to remove these entries once your real DNS records are live.
Step 8: Enable HTTPS with Let's Encrypt (Recommended)
Running websites over plain HTTP is no longer acceptable for production environments. HTTPS encrypts traffic between your server and visitors, improves SEO rankings, and is required for modern browser features. Let's Encrypt provides free, automatically renewable SSL/TLS certificates.
> Prefer a premium SSL solution? AlexHost offers trusted SSL Certificates for businesses that need extended validation or wildcard coverage.
Install Certbot
sudo apt install certbot python3-certbot-nginxObtain and Install SSL Certificates
Run Certbot for each domain. The --nginx plugin automatically modifies your Nginx configuration to enable HTTPS:
sudo certbot --nginx -d example1.com -d www.example1.comsudo certbot --nginx -d example2.com -d www.example2.comFollow the interactive prompts. Certbot will:
- Verify domain ownership via HTTP challenge
- Obtain a signed certificate from Let's Encrypt
- Automatically update your Nginx server block to listen on port 443
- Configure HTTP-to-HTTPS redirection
Verify Auto-Renewal
Let's Encrypt certificates expire every 90 days. Certbot installs a systemd timer to handle renewals automatically. Test it with:
sudo certbot renew --dry-runIf the dry run completes without errors, your certificates will renew automatically without any manual intervention.
What Your Updated Server Block Will Look Like
After Certbot runs, your configuration will be automatically updated to something like this:
server {
listen 443 ssl;
server_name example1.com www.example1.com;
root /var/www/example1.com/html;
index index.html;
ssl_certificate /etc/letsencrypt/live/example1.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example1.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
try_files $uri $uri/ =404;
}
}
server {
listen 80;
server_name example1.com www.example1.com;
return 301 https://$host$request_uri;
}Troubleshooting Common Issues
Even with careful configuration, issues can arise. Here are the most common problems and how to resolve them:
502 Bad Gateway
This typically means Nginx cannot communicate with a backend service (e.g., PHP-FPM or a Node.js app). Verify the upstream service is running and that the socket/port in your configuration is correct.
403 Forbidden
Usually a permissions issue. Check that www-data owns the web root and that file permissions are set correctly:
sudo chown -R www-data:www-data /var/www/example1.com
sudo chmod -R 755 /var/www/example1.com404 Not Found
Verify that the root directive in your server block points to the correct directory and that index.html exists at that path.
Wrong Site Loading
If visiting example1.com loads example2.com's content, check that:
- Each
server_namedirective is unique and correct - Symlinks in
sites-enabledare valid:ls -la /etc/nginx/sites-enabled/ - The default site is disabled if it conflicts
Nginx Fails to Start After Config Change
Always run sudo nginx -t before restarting. Review the error output carefully — it will point to the exact file and line causing the issue.
Checking Logs
Per-site logs (configured in Step 3) are your best debugging resource:
sudo tail -f /var/log/nginx/example1.com.error.log
sudo tail -f /var/log/nginx/example1.com.access.logAdvanced Considerations
Hosting PHP Applications
If your sites run PHP (e.g., WordPress, Laravel), you'll need to install PHP-FPM and add a fastcgi_pass directive to your server block:
location ~ .php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
}Using a Control Panel
Managing Nginx virtual hosts manually via the command line is powerful but time-consuming at scale. If you prefer a graphical interface, consider AlexHost's VPS with cPanel or explore the full range of VPS Control Panels to find the right fit for your workflow.
Scaling Beyond a Single VPS
As your traffic grows, a single VPS may not be sufficient. For high-traffic, resource-intensive workloads, consider upgrading to Dedicated Servers for guaranteed resources, full hardware isolation, and maximum performance.
Conclusion
You've now successfully configured Nginx virtual hosts on Ubuntu, enabling your server to host multiple independent websites simultaneously. Here's a summary of what was accomplished:
- Created isolated web root directories for each domain with correct ownership and permissions
- Wrote clean, production-ready server block configurations with separate access and error logs
- Enabled virtual hosts using Nginx's symlink-based
sites-available/sites-enabledpattern - Validated and reloaded the Nginx configuration safely
- Secured each site with HTTPS using free Let's Encrypt certificates via Certbot
This setup is efficient, scalable, and follows Nginx best practices. Whether you're hosting two sites or twenty, the same pattern applies — simply repeat the process for each additional domain.
For the best results, pair this configuration with a fast, reliable hosting environment. AlexHost's VPS Hosting plans are optimized for Linux workloads, come with full root access, and are backed by 24/7 technical support — giving you the ideal foundation for running Nginx in production.
