BLOG POSTS
    MangoHost Blog / How to Set Up Nginx Server Blocks (Virtual Hosts) on Ubuntu 24
How to Set Up Nginx Server Blocks (Virtual Hosts) on Ubuntu 24

How to Set Up Nginx Server Blocks (Virtual Hosts) on Ubuntu 24

Nginx server blocks (also known as virtual hosts in Apache land) are essentially a way to run multiple websites or applications on a single server by telling Nginx which configuration to use based on the incoming domain name or IP address. This is crucial for anyone managing multiple sites or applications on one server – whether you’re hosting client websites, running different environments (staging, production), or just want to organize your services properly. By the end of this guide, you’ll know how to create, configure, and troubleshoot Nginx server blocks on Ubuntu 24, plus some pro tips that’ll save you headaches down the road.

How Nginx Server Blocks Work

Unlike Apache’s virtual hosts that can get pretty resource-heavy, Nginx server blocks are lightweight and efficient. When a request hits your server, Nginx looks at the server_name directive in your server block configurations and matches it against the Host header in the HTTP request. If there’s a match, it uses that server block’s configuration to serve the content.

The magic happens in the /etc/nginx/sites-available/ directory where you store your server block configurations, and /etc/nginx/sites-enabled/ where you symlink the active ones. This separation lets you keep configurations ready but disabled, which is super handy for maintenance or testing.

Here’s what happens under the hood:

  • Client sends HTTP request with Host header (e.g., example.com)
  • Nginx checks enabled server blocks for matching server_name
  • If match found, uses that block’s configuration
  • If no match, falls back to the default server block
  • Serves content from specified document root with applied rules

Prerequisites and Initial Setup

Before diving in, make sure you’ve got Nginx installed on Ubuntu 24. If you’re running this on a VPS or dedicated server, the process is identical.

sudo apt update
sudo apt install nginx

# Start and enable Nginx
sudo systemctl start nginx
sudo systemctl enable nginx

# Check if it's running
sudo systemctl status nginx

You should also verify your firewall allows HTTP and HTTPS traffic:

sudo ufw allow 'Nginx Full'
sudo ufw status

Step-by-Step Server Block Configuration

Let’s create a server block for a site called myapp.local. In production, this would be your actual domain name.

Step 1: Create Directory Structure

# Create web root directory
sudo mkdir -p /var/www/myapp.local/html

# Set ownership to your user (replace 'username' with your actual username)
sudo chown -R $USER:$USER /var/www/myapp.local/html

# Set proper permissions
sudo chmod -R 755 /var/www/myapp.local

Step 2: Create Sample Content

nano /var/www/myapp.local/html/index.html

Add some basic HTML:

<!DOCTYPE html>
<html>
<head>
    <title>Welcome to myapp.local</title>
</head>
<body>
    <h1>Success! myapp.local server block is working!</h1>
    <p>If you can see this page, your Nginx server block is properly configured.</p>
</body>
</html>

Step 3: Create Server Block Configuration

sudo nano /etc/nginx/sites-available/myapp.local

Here’s a solid basic configuration:

server {
    listen 80;
    listen [::]:80;
    
    root /var/www/myapp.local/html;
    index index.html index.htm index.nginx-debian.html;
    
    server_name myapp.local www.myapp.local;
    
    location / {
        try_files $uri $uri/ =404;
    }
    
    # Security headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;
    
    # Disable server tokens for security
    server_tokens off;
    
    # Log files
    access_log /var/log/nginx/myapp.local.access.log;
    error_log /var/log/nginx/myapp.local.error.log;
}

Step 4: Enable the Server Block

# Create symbolic link to enable the site
sudo ln -s /etc/nginx/sites-available/myapp.local /etc/nginx/sites-enabled/

# Test configuration syntax
sudo nginx -t

# If test passes, reload Nginx
sudo systemctl reload nginx

Step 5: Configure DNS/Hosts File

For local testing, add the domain to your hosts file:

sudo nano /etc/hosts

Add this line:

127.0.0.1 myapp.local www.myapp.local

Now you should be able to visit http://myapp.local in your browser and see your page.

Advanced Configuration Examples

PHP Application Server Block

For PHP applications (make sure php-fpm is installed), use this configuration:

server {
    listen 80;
    server_name phpapp.local;
    root /var/www/phpapp.local/html;
    
    index index.php index.html index.htm;
    
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
    
    location ~ /\.ht {
        deny all;
    }
    
    # Cache static files
    location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

Reverse Proxy Server Block

For proxying to Node.js apps or other services:

server {
    listen 80;
    server_name nodeapp.local;
    
    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;
        proxy_cache_bypass $http_upgrade;
    }
}

SSL/HTTPS Configuration

Let’s add SSL support using Let’s Encrypt. First, install Certbot:

sudo apt install certbot python3-certbot-nginx

Obtain and install certificate:

# Replace with your actual domain
sudo certbot --nginx -d myapp.local -d www.myapp.local

Certbot automatically modifies your server block to include SSL configuration. Here’s what a complete HTTPS server block looks like:

server {
    listen 80;
    server_name myapp.local www.myapp.local;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name myapp.local www.myapp.local;
    
    ssl_certificate /etc/letsencrypt/live/myapp.local/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/myapp.local/privkey.pem;
    
    # SSL Security
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    
    root /var/www/myapp.local/html;
    index index.html index.htm;
    
    location / {
        try_files $uri $uri/ =404;
    }
}

Performance Optimization and Best Practices

Here are some performance tweaks that make a real difference:

Enable Gzip Compression

Add this to your server block or main nginx.conf:

gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied expired no-cache no-store private must-revalidate no_last_modified no_etag auth;
gzip_types
    application/atom+xml
    application/javascript
    application/json
    application/ld+json
    application/manifest+json
    application/rss+xml
    application/vnd.geo+json
    application/vnd.ms-fontobject
    application/x-font-ttf
    application/x-web-app-manifest+json
    application/xhtml+xml
    application/xml
    font/opentype
    image/bmp
    image/svg+xml
    image/x-icon
    text/cache-manifest
    text/css
    text/plain
    text/vcard
    text/vnd.rim.location.xloc
    text/vtt
    text/x-component
    text/x-cross-domain-policy;

Rate Limiting

Protect your server from abuse:

# Add to nginx.conf http block
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;

# Add to server block
location /login {
    limit_req zone=login burst=5 nodelay;
    # your location config
}

Common Issues and Troubleshooting

Here’s a troubleshooting checklist for when things go wrong:

Problem Likely Cause Solution
403 Forbidden Permission issues or missing index file Check file permissions (755 for dirs, 644 for files)
502 Bad Gateway Upstream service down (PHP-FPM, Node.js app) Check if backend service is running
Nginx won’t start Configuration syntax error Run sudo nginx -t to check syntax
Wrong site loading Server block priority/default issues Check server_name and default_server directives

Debug Commands That Save Your Sanity

# Check configuration syntax
sudo nginx -t

# Test and show configuration
sudo nginx -T

# Check what sites are enabled
ls -la /etc/nginx/sites-enabled/

# View error logs
sudo tail -f /var/log/nginx/error.log

# Check if nginx is binding to correct ports
sudo netstat -tlnp | grep nginx

# Reload without stopping (graceful reload)
sudo nginx -s reload

Real-World Use Cases and Examples

Multi-Environment Setup

Here’s how to set up staging and production environments:

# Production - myapp.com
server {
    listen 443 ssl http2;
    server_name myapp.com www.myapp.com;
    root /var/www/production/html;
    # SSL and other config
}

# Staging - staging.myapp.com
server {
    listen 443 ssl http2;
    server_name staging.myapp.com;
    root /var/www/staging/html;
    
    # Basic auth for staging
    auth_basic "Staging Environment";
    auth_basic_user_file /etc/nginx/.htpasswd;
    # SSL and other config
}

Load Balancing Multiple App Instances

upstream app_backend {
    server 127.0.0.1:3000;
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;
}

server {
    listen 80;
    server_name myapp.com;
    
    location / {
        proxy_pass http://app_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Security Considerations

Always implement these security measures:

  • Hide Nginx version: server_tokens off;
  • Disable unused HTTP methods
  • Set proper security headers
  • Use strong SSL/TLS configuration
  • Implement rate limiting on sensitive endpoints
  • Regularly update Nginx and SSL certificates
# Block common exploit attempts
location ~ /(\.|wp-admin|wp-includes) {
    deny all;
}

# Only allow specific HTTP methods
if ($request_method !~ ^(GET|HEAD|POST)$ ) {
    return 405;
}

Performance Benchmarks and Monitoring

With proper server block configuration, you can expect significant performance improvements. Here’s what well-configured Nginx can handle:

Configuration Concurrent Connections Requests/Second Memory Usage
Basic Static Files 10,000+ 50,000+ ~10MB
PHP-FPM Proxy 1,000-5,000 1,000-5,000 ~50MB
Node.js Reverse Proxy 5,000-10,000 10,000-20,000 ~30MB

Monitor your server blocks with:

# Enable status page
location /nginx_status {
    stub_status on;
    access_log off;
    allow 127.0.0.1;
    deny all;
}

The beauty of Nginx server blocks is their flexibility and efficiency. Unlike Apache virtual hosts that spawn new processes, Nginx handles everything in a single master process with worker processes, making it incredibly resource-efficient. You can run dozens of sites on a modest server without breaking a sweat.

For more advanced configurations and edge cases, check out the official Nginx documentation. The server names documentation is particularly useful for understanding complex routing scenarios.

Remember: always test your configurations in a staging environment first, keep backups of working configs, and monitor your error logs religiously. Nginx server blocks are powerful, but with great power comes great responsibility to not break production at 3 AM.



This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.

This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.

Leave a reply

Your email address will not be published. Required fields are marked