
First Things First - What Are We Even Talking About?
Virtual hosts are Nginx's way of letting you run multiple websites on the same server. Each website gets its own configuration, its own domain name, and its own little corner of the server. It's like giving each website its own apartment in a building - they share the same foundation but have their own spaces, keys, and rules.
This is super useful when you want to:
- Host multiple client websites on one server
- Run different versions of the same app for testing
- Separate your blog from your main business site
- Basically do anything that requires more than one website
The Setup - Getting Your Server Ready
Before we start creating virtual hosts, let's make sure our house is in order. I'm assuming you've got Nginx installed (if not, I've got another tutorial for that - shameless plug, I know).
First, let's create a sensible directory structure. This is one of those things that seems boring now but you'll thank me later when your server doesn't look like a teenager's bedroom.
# Create our main web directory
sudo mkdir -p /var/www
# Create directories for our example sites
sudo mkdir -p /var/www/myawesomeblog.com
sudo mkdir -p /var/www/mybusinesssite.com
Now let's create some basic index files so we can actually see our websites working:
# Create a simple page for our blog
sudo nano /var/www/myawesomeblog.com/index.html
<!DOCTYPE html>
<html>
<head>
<title>My Awesome Blog</title>
<style>
body { font-family: Arial, sans-serif; text-align: center; margin-top: 50px; }
.container { max-width: 600px; margin: 0 auto; }
h1 { color: #2c3e50; }
</style>
</head>
<body>
<div class="container">
<h1>🎉 Welcome to My Awesome Blog!</h1>
<p>This site is running on Nginx virtual hosts. Pretty cool, right?</p>
</div>
</body>
</html>
And for our business site:
sudo nano /var/www/mybusinesssite.com/index.html
<!DOCTYPE html>
<html>
<head>
<title>My Business Site</title>
<style>
body { font-family: Arial, sans-serif; text-align: center; margin-top: 50px; }
.container { max-width: 600px; margin: 0 auto; }
h1 { color: #27ae60; }
</style>
</head>
<body>
<div class="container">
<h1>🏢 Welcome to My Business Site!</h1>
<p>Professional hosting powered by Nginx virtual hosts.</p>
</div>
</body>
</html>
Setting the Right Permissions
Here's a gotcha that trips up a lot of people - file permissions. Nginx runs as the www-data
user, so it needs permission to read these files:
# Give ownership to www-data
sudo chown -R www-data:www-data /var/www
# Set proper permissions
sudo chmod -R 755 /var/www
Creating Your First Virtual Host
Now for the fun part! Let's create our first virtual host configuration. Nginx has this clever system where configurations live in sites-available
and you enable them by creating symlinks in sites-enabled
. It's like having configuration templates that you can turn on and off without deleting anything.
sudo nano /etc/nginx/sites-available/myawesomeblog.com
Here's what goes in that file:
server {
listen 80;
listen [::]:80; # For IPv6 support
server_name myawesomeblog.com www.myawesomeblog.com;
# Where our website files live
root /var/www/myawesomeblog.com;
index index.html index.php;
# Log files (super useful for debugging)
access_log /var/log/nginx/myawesomeblog.com.access.log;
error_log /var/log/nginx/myawesomeblog.com.error.log;
# Basic configuration
location / {
try_files $uri $uri/ =404;
}
# Security headers (always a good idea)
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
}
Creating the Second Virtual Host
Now let's set up our business site:
sudo nano /etc/nginx/sites-available/mybusinesssite.com
server {
listen 80;
listen [::]:80;
server_name mybusinesssite.com www.mybusinesssite.com;
root /var/www/mybusinesssite.com;
index index.html index.php;
access_log /var/log/nginx/mybusinesssite.com.access.log;
error_log /var/log/nginx/mybusinesssite.com.error.log;
location / {
try_files $uri $uri/ =404;
}
# This one gets some extra love with caching
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
}
Enabling Your Virtual Hosts
Here's where the magic happens. We need to enable these configurations by creating symbolic links:
# Enable our sites
sudo ln -s /etc/nginx/sites-available/myawesomeblog.com /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/mybusinesssite.com /etc/nginx/sites-enabled/
# Remove the default site (optional but recommended)
sudo rm /etc/nginx/sites-enabled/default
Testing and Reloading
Before we restart Nginx and potentially break everything, let's test our configuration:
sudo nginx -t
If you see "syntax is ok" and "test is successful", you're good to go! If not, Nginx will tell you exactly where the problem is.
Now reload Nginx to apply our changes:
sudo systemctl reload nginx
Testing Your Virtual Hosts
Here's the thing - unless you've actually bought these domain names and pointed them to your server, you won't be able to test them properly just by typing the URLs in your browser. But there's a workaround!
Edit your local computer's hosts file (not the server's):
- On Windows:
C:\Windows\System32\driverstc\hosts
- On Mac/Linux:
/etc/hosts
Add these lines:
your_server_ip myawesomeblog.com
your_server_ip mybusinesssite.com
Replace your_server_ip
with your actual server IP address. Now you can visit http://myawesomeblog.com
and http://mybusinesssite.com
in your browser and see your sites!
Some Pro Tips I Learned the Hard Way
1. Always Use Separate Log Files
I made this mistake early on - using the default Nginx log files for all sites. When something went wrong, I had to dig through logs from multiple sites to find the issue. Separate log files are a lifesaver.
2. Set Up Different Error Pages
You can customize 404 pages for each site:
error_page 404 /404.html;
location = /404.html {
root /var/www/myawesomeblog.com;
}
3. Use SSL from the Start
Seriously, don't wait to add SSL. Let's Encrypt makes it free and easy:
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d myawesomeblog.com -d www.myawesomeblog.com
4. Organize Your Configurations
As you add more sites, consider organizing them by creating subdirectories:
mkdir -p /etc/nginx/sites-available/personal
mkdir -p /etc/nginx/sites-available/clients
5. Use Includes for Reusable Configurations
If you have settings you use across multiple sites, put them in a separate file:
sudo nano /etc/nginx/snippets/common-ssl.conf
Then include it in your server blocks:
include snippets/common-ssl.conf;
What If Something Goes Wrong?
Don't panic! Here's my troubleshooting checklist:
- Check Nginx status:
sudo systemctl status nginx
- Look at the logs:
sudo tail -f /var/log/nginx/error.log
- Test configuration:
sudo nginx -t
- Check file permissions:
ls -la /var/www/
- Verify symlinks:
ls -la /etc/nginx/sites-enabled/
The most common issues I see are:
- Typos in configuration files
- Wrong file permissions
- Missing symlinks
- Firewall blocking ports
Going Further
Once you're comfortable with basic virtual hosts, you can explore:
- PHP integration with PHP-FPM
- Database configurations
- Load balancing
- Reverse proxy setups
- SSL termination
- Rate limiting
The beauty of Nginx is that it's incredibly powerful once you understand the basics. Virtual hosts are just the beginning.
Wrapping Up
And there you have it! You've just learned how to host multiple websites on a single Nginx server. Pretty empowering, right?
Remember, virtual hosts are one of those fundamental skills that'll serve you well whether you're running a personal blog, managing client sites, or building the next big thing. Take your time, experiment, and don't be afraid to break things (just make sure you have backups!).
Happy hosting! 🚀
PS: Got questions or ran into issues? Drop them in the comments below - I've probably made the same mistakes you're about to make, and I'm happy to help you avoid them!