A Virtual Private Server (VPS) is your personal canvas on the internet. While basic setup is straightforward, unlocking its true potential requires mastering the web server. This guide dives deep into using Nginx to host multiple projects, manage subdomains, and route traffic to different services, transforming your single server into a multi-functional powerhouse.
1. Initial Server Setup
After acquiring a VPS, you’ll get an IP address and root access. Your first steps are to secure the server and create a non-root user for daily operations.
Connect to your server via SSH:
ssh root@YOUR_SERVER_IP
Create a Sudo User
Operating as root
is risky. Create a new user and grant administrative privileges.
# Create the new user (replace 'devuser' with your username)
adduser devuser
# Add the user to the 'sudo' group
usermod -aG sudo devuser
Now, set up SSH key authentication for your new user for enhanced security and convenience, then log in as that user.
2. Essential Security and Updates
A public server is a constant target. Secure it immediately.
Configure the Firewall
ufw
(Uncomplicated Firewall) makes this easy. We’ll allow SSH, HTTP, and HTTPS traffic.
# Allow OpenSSH (so you don't lock yourself out)
sudo ufw allow OpenSSH
# Allow Nginx to handle web traffic on ports 80 and 443
sudo ufw allow 'Nginx Full'
# Enable the firewall
sudo ufw enable
After enabling, check its status to ensure it’s active and your rules are loaded.
sudo ufw status
Update Your Server
Keep your system’s packages current to patch security vulnerabilities.
sudo apt update && sudo apt upgrade -y
3. Installing and Understanding Nginx
Nginx is the heart of our setup. It’s a high-performance web server that can also act as a reverse proxy, load balancer, and more.
# Install Nginx
sudo apt install nginx -y
While the package should start and enable Nginx automatically, it’s good practice to run the commands explicitly to be sure.
# Start the Nginx service
sudo systemctl start nginx
# Enable Nginx to start automatically on boot
sudo systemctl enable nginx
# Now, check that it's running and enabled
sudo systemctl status nginx
You should see active (running)
in the output. Visiting your server’s IP in a browser should also show the Nginx welcome page.
Nginx Configuration Structure
Nginx’s configuration lives in /etc/nginx
. The -p
flag in the commands below ensures that the command does nothing if the directories already exist.
sudo mkdir -p /etc/nginx/sites-available
sudo mkdir -p /etc/nginx/sites-enabled
The key directories are:
/etc/nginx/nginx.conf
: The main configuration file. You rarely edit this./etc/nginx/sites-available/
: Where you store the configuration files for each of your sites (called “server blocks”)./etc/nginx/sites-enabled/
: Where you create symbolic links to the configurations insites-available
that you want to be active.
This structure lets you easily enable or disable sites without deleting their configuration files.
4. Advanced Hosting: Subdomains and Reverse Proxies
This is where the magic happens. A single server can host a blog, a portfolio website, a web app, and several APIs, all neatly organized using subdomains.
The core concept is the Reverse Proxy. Your Nginx server listens on the standard web ports (80 for HTTP, 443 for HTTPS) and intelligently forwards incoming requests to the correct internal service based on the requested domain or subdomain.
Scenario:
Let’s say we want to set up the following on our server:
eknath.dev
: A static HTML/CSS website.blog.eknath.dev
: A separate project, maybe a Hugo or Jekyll site.api.eknath.dev
: A Node.js application running on port3000
.
Step 1: Create Project Directories
Organize your projects in the /var/www
directory.
# Create directories for the main site and blog
sudo mkdir -p /var/www/eknath.dev/html
sudo mkdir -p /var/www/blog.eknath.dev/html
# Set correct permissions
sudo chown -R $USER:$USER /var/www/eknath.dev
sudo chown -R $USER:$USER /var/www/blog.eknath.dev
Verify that the directories were created with the correct ownership.
ls -ld /var/www/eknath.dev/
ls -ld /var/www/blog.eknath.dev/
Now, place some placeholder files.
echo "<h1>Welcome to Eknath's Site</h1>" | sudo tee /var/www/eknath.dev/html/index.html
echo "<h1>Welcome to Eknath's Blog</h1>" | sudo tee /var/www/blog.eknath.dev/html/index.html
Step 2: Create Nginx Server Blocks
Now, we create a configuration file for each site in sites-available
.
For the main domain (eknath.dev
):
sudo nano /etc/nginx/sites-available/eknath.dev
Add the following server block:
server {
listen 80;
listen [::]:80;
server_name eknath.dev www.eknath.dev;
root /var/www/eknath.dev/html;
index index.html index.php;
location / {
try_files $uri $uri/ =404;
}
}
For the blog subdomain (blog.eknath.dev
):
sudo nano /etc/nginx/sites-available/blog.eknath.dev
Add this configuration:
server {
listen 80;
listen [::]:80;
server_name blog.eknath.dev;
root /var/www/blog.eknath.dev/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
Step 3: Configure the Reverse Proxy for the API
For api.eknath.dev
, we’ll proxy requests to our Node.js app, which we assume is running on http://127.0.0.1:3000
.
Create the configuration file:
sudo nano /etc/nginx/sites-available/api.eknath.dev
Add the reverse proxy configuration:
server {
listen 80;
listen [::]:80;
server_name api.eknath.dev;
location / {
proxy_pass http://127.0.0.1:3000;
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;
}
}
Step 4: Enable the Sites and Test
Now, link these configurations into sites-enabled
to activate them.
sudo ln -s /etc/nginx/sites-available/eknath.dev /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/blog.eknath.dev /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/api.eknath.dev /etc/nginx/sites-enabled/
Test the Nginx configuration for syntax errors:
sudo nginx -t
If it’s successful, restart Nginx to apply the changes:
sudo systemctl restart nginx
Check the status to ensure it restarted correctly.
sudo systemctl status nginx
After setting up your DNS records, you’ll be able to access each service through its unique subdomain.
5. Securing Your Sites with SSL (HTTPS)
We’ll use Let’s Encrypt, a free and automated Certificate Authority, and Certbot, a tool that makes managing SSL/TLS certificates effortless.
Step 1: Install Certbot
Certbot has a dedicated Nginx plugin that automates the process.
# Install Certbot and its Nginx plugin
sudo apt install certbot python3-certbot-nginx -y
Step 2: Obtain and Install the SSL Certificates
With your server blocks already configured, running Certbot is incredibly simple.
# Run Certbot to get certificates for all configured domains
sudo certbot --nginx
Certbot will guide you through a few simple steps:
- Enter your email address.
- Agree to the Terms of Service.
- Choose domains from the list Certbot finds.
- Choose to redirect HTTP to HTTPS. This is highly recommended.
Step 3: Verify the New Configuration
Certbot automatically modifies your Nginx files to enable HTTPS. You can check the new configuration by running sudo nginx -t
and then reloading Nginx with sudo systemctl reload nginx
.
Step 4: Understanding Automatic Renewal
Let’s Encrypt certificates are valid for 90 days. The Certbot package automatically sets up a task to renew them. You can test the renewal process with a dry run:
sudo certbot renew --dry-run
If this command runs without errors, your auto-renewal is set up correctly.
Conclusion
You have now transformed a basic VPS into a sophisticated, multi-tenant hosting platform. By leveraging Nginx’s server blocks and reverse proxy capabilities, you can host and manage numerous projects, each on its own subdomain, from a single server. Happy hosting!