Back to notes
#nginx#webserver#linux#devops#tutorial#cheatsheet#security

The Complete Nginx Web Server Guide: Setup, Configuration & Commands Cheatsheet

A comprehensive guide covering Nginx installation, configuration, security best practices, and essential commands for Linux/Unix systems. Perfect for beginners and as a quick reference for deploying web servers.

30 min read5,824 words

Whether you're deploying your first website or need a quick reference for Nginx commands and configurations, this guide has you covered. We'll walk through complete Nginx setup on Debian/Ubuntu systems, security hardening, and provide a comprehensive command cheatsheet.

Table of Contents

Prerequisites

Before starting, ensure you have:

  • Domain name configured
  • Server/VPS (e.g., Vultr, DigitalOcean, AWS EC2)
  • DNS records pointing domain to server IP address
  • Debian-based Linux system (Ubuntu, Debian)
  • Root or sudo access to the server

Initial Server Access

SSH Login

Connect to your server using SSH from your terminal:

Bash
1# Using domain name 2ssh root@example.org 3 4# Or using IP address directly 5ssh root@192.168.1.1

Note: If login fails, verify that your DNS settings are configured correctly. You can always use the IP address as a fallback.

Alternative Access Methods

For different operating systems:

  • Windows: Use PuTTY or Windows Subsystem for Linux (WSL)
  • Mac/Linux: Built-in terminal with SSH support

Finding Your Server Password

  1. Log into your VPS provider's control panel (Vultr, DigitalOcean, etc.)
  2. Navigate to your server instance
  3. Locate the root password in the server details section
  4. Copy the password for SSH authentication

System Update & Nginx Installation

Update Your System

Always start by updating your package lists and upgrading existing packages:

Bash
1apt update # Refresh package database 2apt upgrade # Install available updates

What these commands do:

  • CODE
    apt update
    - Checks repositories for package updates
  • CODE
    apt upgrade
    - Installs the latest versions of installed packages

Install Nginx

Install the Nginx web server package:

Bash
apt install nginx

What is Nginx?

  • Pronounced "Engine-X"
  • High-performance web server and reverse proxy
  • Known for low memory usage and high concurrency
  • Powers millions of websites worldwide
  • Can also function as a load balancer and HTTP cache

Nginx Configuration Structure

Understanding Nginx Directories

Nginx uses a well-organized directory structure for managing configurations:

CODE
1/etc/nginx/ # Main nginx directory 2├── sites-available/ # All site configurations (inactive) 3├── sites-enabled/ # Active configurations (symlinks) 4├── nginx.conf # Main nginx configuration file 5├── conf.d/ # Additional configuration files 6└── snippets/ # Reusable configuration snippets

How Configuration Works

sites-available:

  • Store all website configurations (both active and inactive)
  • Think of this as your "configuration library"
  • Files here don't affect the running server

sites-enabled:

  • Contains symbolic links to active configurations from sites-available
  • Only configurations linked here are loaded by Nginx
  • Enables easy activation/deactivation of sites

Workflow:

  1. Create configuration file in
    CODE
    sites-available
  2. Test the configuration
  3. Create symlink in
    CODE
    sites-enabled
    to activate
  4. Reload Nginx to apply changes

Creating Your First Website

Step 1: Create Configuration File

Use a text editor to create a new site configuration:

Bash
nano /etc/nginx/sites-available/mywebsite

Note: Replace

CODE
mywebsite
with a descriptive name for your site (e.g.,
CODE
blog
,
CODE
portfolio
,
CODE
example.org
)

Step 2: Basic Nginx Configuration

Add this configuration template to your file:

NGINX
1server { 2 listen 80 ; 3 listen [::]:80 ; 4 server_name example.org ; 5 root /var/www/mysite ; 6 index index.html index.htm index.nginx-debian.html ; 7 location / { 8 try_files $uri $uri/ =404 ; 9 } 10}

Remember to customize:

  • CODE
    server_name example.org
    - Change to your actual domain
  • CODE
    root /var/www/mysite
    - Change to your preferred directory name

Configuration Directives Explained

DirectivePurposeExample Value
CODE
listen 80
Listen for IPv4 HTTP connectionsPort 80 (standard HTTP)
CODE
listen [::]:80
Listen for IPv6 HTTP connectionsPort 80 with IPv6 support
CODE
server_name
Domain name(s) for this site
CODE
example.org www.example.org
CODE
root
Directory containing website files
CODE
/var/www/mysite
CODE
index
Default files to serve
CODE
index.html index.htm
CODE
location /
URL routing configurationRoot location block
CODE
try_files
File lookup orderTry file, directory, then 404

Detailed Breakdown

listen directives:

  • Port 80 is the standard HTTP port (unencrypted traffic)
  • The
    CODE
    [::]:80
    enables IPv6 support
  • Both are necessary for full internet accessibility

server_name:

  • Specifies which domain names this configuration handles
  • When someone visits
    CODE
    example.org
    , Nginx uses this config
  • Can include multiple domains:
    CODE
    server_name example.org www.example.org;

root:

  • The filesystem path where your website files are stored
  • Convention is to use
    CODE
    /var/www/
    as the base directory
  • Full path example:
    CODE
    /var/www/mysite/index.html

index:

  • Default files Nginx looks for when accessing a directory
  • When visiting
    CODE
    example.org/
    , it serves
    CODE
    example.org/index.html
  • Tries files in order from left to right

location block:

  • Defines how Nginx handles different URL paths
  • The
    CODE
    /
    location matches all requests
  • CODE
    try_files $uri $uri/ =404
    means:
    1. Try to serve the exact file requested (
      CODE
      $uri
      )
    2. Try to serve it as a directory (
      CODE
      $uri/
      )
    3. Return 404 error if neither exists

Step 3: Create Website Directory

Create the directory to hold your website files:

Bash
mkdir -p /var/www/mysite

The

CODE
-p
flag creates parent directories if they don't exist.

Step 4: Create Your First Web Page

Create an HTML file that will be your website's homepage:

Bash
nano /var/www/mysite/index.html

Add this basic HTML content:

HTML
1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <title>My Website</title> 7</head> 8<body> 9 <h1>Welcome to My Website!</h1> 10 <p>This is my website. Thanks for stopping by!</p> 11 <p>My website is now live on the internet!</p> 12</body> 13</html>

Tips:

  • You can customize this HTML as much as you want
  • Add CSS styling, images, and more pages
  • This is just the starting point for your website

Enabling the Website

Activate your website configuration by creating a symbolic link:

Bash
ln -s /etc/nginx/sites-available/mywebsite /etc/nginx/sites-enabled/

What this command does:

  • CODE
    ln -s
    creates a symbolic link (like a shortcut)
  • Links from
    CODE
    sites-enabled
    to your configuration in
    CODE
    sites-available
  • This tells Nginx to load and use this configuration
  • You can disable a site by removing the link without deleting the config

Test Configuration Syntax

Before reloading Nginx, always test your configuration for errors:

Bash
nginx -t

Expected output if successful:

CODE
1nginx: the configuration file /etc/nginx/nginx.conf syntax is ok 2nginx: configuration file /etc/nginx/nginx.conf test is successful

Reload Nginx

Apply your configuration changes by reloading Nginx:

Bash
systemctl reload nginx

Service Management Commands

Bash
1systemctl start nginx # Start Nginx service 2systemctl stop nginx # Stop Nginx service 3systemctl restart nginx # Full restart (brief downtime) 4systemctl reload nginx # Reload config (no downtime) 5systemctl status nginx # Check service status 6systemctl enable nginx # Start Nginx on system boot 7systemctl disable nginx # Don't start on boot

reload vs restart:

  • CODE
    reload
    - Applies configuration changes without dropping connections
  • CODE
    restart
    - Completely stops and starts the service (may drop active connections)

Firewall Configuration (UFW)

Check UFW Status

First, verify if UFW (Uncomplicated Firewall) is installed and check its status:

Bash
ufw status

Install UFW (If Not Installed)

If UFW isn't installed on your system:

Bash
apt install ufw

Initial UFW Setup and Configuration

⚠️ CRITICAL WARNING: Always allow SSH before enabling UFW to prevent being locked out of your server!

Bash
1# Step 1: Allow SSH first (CRITICAL - prevents lockout!) 2ufw allow 22/tcp 3# Or if using a custom SSH port: 4# ufw allow <your-custom-port>/tcp 5 6# Step 2: Allow HTTP traffic 7ufw allow 80/tcp 8 9# Step 3: Allow HTTPS traffic (encrypted) 10ufw allow 443/tcp 11 12# Step 4: Enable the firewall 13ufw enable 14 15# Step 5: Verify the configuration 16ufw status verbose

Understanding the Status Output

After running

CODE
ufw status verbose
, you should see something like:

CODE
1Status: active 2Logging: on (low) 3Default: deny (incoming), allow (outgoing), disabled (routed) 4New profiles: skip 5 6To Action From 7-- ------ ---- 822/tcp ALLOW IN Anywhere 980/tcp ALLOW IN Anywhere 10443/tcp ALLOW IN Anywhere 1122/tcp (v6) ALLOW IN Anywhere (v6) 1280/tcp (v6) ALLOW IN Anywhere (v6) 13443/tcp (v6) ALLOW IN Anywhere (v6)

Essential UFW Commands

Basic Operations

Bash
1# Enable firewall (blocks everything except allowed rules) 2ufw enable 3 4# Disable firewall (allows all traffic) 5ufw disable 6 7# Check current status 8ufw status 9ufw status verbose # Detailed status 10ufw status numbered # Show rule numbers (useful for deletion) 11 12# Reload firewall rules 13ufw reload 14 15# Reset firewall (delete all rules) 16ufw reset

Allowing Traffic

Bash
1# Allow specific port 2ufw allow 80 3ufw allow 80/tcp # TCP protocol only 4ufw allow 80/udp # UDP protocol only 5 6# Allow port range 7ufw allow 6000:6007/tcp 8 9# Allow from specific IP address 10ufw allow from 192.168.1.100 11 12# Allow from specific IP to specific port 13ufw allow from 192.168.1.100 to any port 22 14 15# Allow from subnet 16ufw allow from 192.168.1.0/24 17 18# Allow application profile (if available) 19ufw allow 'Nginx Full' 20ufw allow 'Nginx HTTP' 21ufw allow 'Nginx HTTPS'

Denying Traffic

Bash
1# Deny specific port 2ufw deny 23 3 4# Deny from specific IP 5ufw deny from 192.168.1.100 6 7# Deny to specific port 8ufw deny to any port 3306

Deleting Rules

Bash
1# Show numbered rules 2ufw status numbered 3 4# Delete rule by number 5ufw delete 3 6 7# Delete rule by specification 8ufw delete allow 80/tcp 9ufw delete allow from 192.168.1.100

Common Port Reference

PortProtocolServiceWhen to Open
22TCPSSHAlways (CRITICAL for remote access)
80TCPHTTPWeb server (unencrypted)
443TCPHTTPSWeb server (encrypted/SSL)
21TCPFTPFile transfer (avoid, use SFTP instead)
22TCPSFTPSecure file transfer (uses SSH)
25TCPSMTPEmail sending
587TCPSMTPEmail submission (TLS)
993TCPIMAPSEmail retrieval (secure)
3306TCPMySQLDatabase (usually keep internal only)
5432TCPPostgreSQLDatabase (usually keep internal only)
6379TCPRedisCache (usually keep internal only)
27017TCPMongoDBDatabase (usually keep internal only)

Advanced UFW Configuration

Rate Limiting (Prevent Brute Force)

Bash
1# Limit SSH connections (max 6 attempts per 30 seconds) 2ufw limit 22/tcp 3ufw limit ssh 4 5# This helps prevent brute force attacks

Default Policies

Bash
1# Set default policies 2ufw default deny incoming # Block all incoming by default 3ufw default allow outgoing # Allow all outgoing by default 4ufw default deny routed # Deny routing/forwarding 5 6# These are typically set by default

Application Profiles

Bash
1# List available application profiles 2ufw app list 3 4# Show information about a profile 5ufw app info 'Nginx Full' 6 7# Allow by application profile 8ufw allow 'Nginx Full' # Allows both HTTP (80) and HTTPS (443) 9ufw allow 'Nginx HTTP' # Allows only HTTP (80) 10ufw allow 'Nginx HTTPS' # Allows only HTTPS (443)

Logging

Bash
1# Enable logging 2ufw logging on 3 4# Set logging level 5ufw logging low # Logs blocked packets 6ufw logging medium # Logs blocked, allowed, and rate-limited packets 7ufw logging high # Logs all packets 8ufw logging full # Maximum logging 9 10# Disable logging 11ufw logging off 12 13# View logs 14tail -f /var/log/ufw.log

UFW Best Practices

Security Recommendations:

  1. Always allow SSH before enabling - This cannot be stressed enough!
  2. Use specific protocols - Prefer
    CODE
    80/tcp
    over just
    CODE
    80
  3. Follow principle of least privilege - Only open ports you actually need
  4. Use rate limiting for SSH -
    CODE
    ufw limit 22/tcp
    prevents brute force
  5. Regular audits - Periodically review rules with
    CODE
    ufw status numbered
  6. Remove unused rules - Delete rules for services you no longer run
  7. Use comments - Unfortunately UFW doesn't support comments, so document separately
  8. Test carefully - Always have a backup access method before making changes

Important Security Notes:

  • Not all services need open ports in the firewall
  • Services running locally (only for other local services) don't need firewall rules
  • Many web services can run through Nginx as a reverse proxy (only need ports 80/443)
  • Database services (MySQL, PostgreSQL, Redis) should usually NOT be exposed to the internet
  • Use VPN or SSH tunneling for accessing internal services remotely

Troubleshooting UFW

Locked Out of Server

If you enabled UFW without allowing SSH:

  • Access through your VPS provider's web console
  • Run
    CODE
    ufw allow 22/tcp
    and
    CODE
    ufw reload
  • Consider using a recovery mode or console access

Rules Not Working

Bash
1# Verify UFW is enabled 2ufw status 3 4# Check rule order (rules are processed top to bottom) 5ufw status numbered 6 7# Reload UFW 8ufw reload 9 10# Check logs for blocked connections 11tail -f /var/log/ufw.log 12 13# Verify no conflicting iptables rules 14iptables -L -n

Testing Firewall Rules

Bash
1# Test from another machine 2telnet your-server-ip 80 3nc -zv your-server-ip 80 4 5# Check which ports are listening 6netstat -tlnp 7ss -tlnp 8 9# Test specific port availability 10nmap your-server-ip

Security Hardening

Hide Nginx Version Number

By default, Nginx displays its version number on error pages and in HTTP headers. This information can help attackers identify known vulnerabilities for your specific version.

Why hide the version?

  • Prevents attackers from knowing your exact Nginx version
  • Reduces attack surface if security vulnerabilities are discovered
  • Makes reconnaissance harder for potential attackers
  • Industry best practice for production servers

How to Disable Version Display

Step 1: Edit Main Configuration

Open the main Nginx configuration file:

Bash
nano /etc/nginx/nginx.conf

Step 2: Find and Uncomment

Look for this line in the

CODE
http
block:

NGINX
# server_tokens off;

Uncomment it by removing the

CODE
#
:

NGINX
server_tokens off;

Step 3: Test and Apply

Bash
1# Test configuration syntax 2nginx -t 3 4# If successful, reload Nginx 5systemctl reload nginx

Verify the Change

Before the change:

CODE
1HTTP/1.1 404 Not Found 2Server: nginx/1.18.0

After the change:

CODE
1HTTP/1.1 404 Not Found 2Server: nginx

Additional Security Recommendations

Keep Software Updated

Regularly update your system and Nginx to get the latest security patches:

Bash
1# Update package lists 2apt update 3 4# Upgrade all packages 5apt upgrade 6 7# Upgrade only Nginx 8apt install --only-upgrade nginx 9 10# Check for available updates 11apt list --upgradable

Set Up Automatic Security Updates

For Debian/Ubuntu systems:

Bash
1# Install unattended-upgrades 2apt install unattended-upgrades 3 4# Enable automatic security updates 5dpkg-reconfigure -plow unattended-upgrades

Security Checklist

  • Hide Nginx version (
    CODE
    server_tokens off
    )
  • Keep Nginx and system packages updated
  • Install and configure SSL/TLS certificates (HTTPS)
  • Configure firewall (UFW) properly
  • Use strong passwords for all accounts
  • Disable unnecessary Nginx modules
  • Set up regular automated backups
  • Monitor logs for suspicious activity
  • Implement rate limiting for preventing DoS attacks
  • Configure security headers (CSP, HSTS, X-Frame-Options)
  • Restrict access to sensitive files and directories
  • Use fail2ban to block repeated failed login attempts

Testing Your Website

Access Your Website

Now that everything is configured, it's time to test your website!

Open your web browser and navigate to:

CODE
http://example.org

(Replace

CODE
example.org
with your actual domain name)

What You Should See

Success: Your HTML content appears in the browser
⚠️ "Not Secure" warning: This is normal - you haven't set up HTTPS yet

The browser will show a "Not secure" or unlocked padlock icon because the site is using HTTP (unencrypted). This is expected and will be resolved when you add an SSL certificate in the next step.

Verification Commands

Check if your website is serving correctly:

Bash
1# Test nginx is running 2systemctl status nginx 3 4# Test from command line 5curl http://example.org 6 7# Test with headers 8curl -I http://example.org 9 10# Test locally 11curl http://localhost
Bash
1# Check nginx status 2systemctl status nginx 3 4# Test configuration syntax 5nginx -t 6 7# View error logs 8tail -f /var/log/nginx/error.log 9 10# View access logs 11tail -f /var/log/nginx/access.log

Essential Nginx Commands

Service Management Commands

Bash
1# Start Nginx 2systemctl start nginx 3 4# Stop Nginx 5systemctl stop nginx 6 7# Restart Nginx (full restart with brief downtime) 8systemctl restart nginx 9 10# Reload configuration (no downtime - preferred) 11systemctl reload nginx 12 13# Check Nginx status 14systemctl status nginx 15 16# Enable Nginx to start on boot 17systemctl enable nginx 18 19# Disable Nginx from starting on boot 20systemctl disable nginx 21 22# Check if Nginx is enabled 23systemctl is-enabled nginx

Configuration Testing Commands

Always test configuration before reloading!

Bash
1# Test configuration syntax (doesn't apply changes) 2nginx -t 3 4# Test and display full configuration 5nginx -T 6 7# Test specific configuration file 8nginx -t -c /etc/nginx/nginx.conf

Log Management Commands

Error Logs

Bash
1# View error log in real-time 2tail -f /var/log/nginx/error.log 3 4# View last 50 lines of error log 5tail -n 50 /var/log/nginx/error.log 6 7# View entire error log 8cat /var/log/nginx/error.log 9 10# Search error log for specific term 11grep "404" /var/log/nginx/error.log

Access Logs

Bash
1# View access log in real-time 2tail -f /var/log/nginx/access.log 3 4# View last 100 lines 5tail -n 100 /var/log/nginx/access.log 6 7# Search for specific IP 8grep "192.168.1.1" /var/log/nginx/access.log 9 10# Count requests by IP 11awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn

Configuration File Operations

Bash
1# Edit main Nginx configuration 2nano /etc/nginx/nginx.conf 3 4# Edit site configuration 5nano /etc/nginx/sites-available/mywebsite 6 7# List all available sites 8ls -la /etc/nginx/sites-available/ 9 10# List enabled sites 11ls -la /etc/nginx/sites-enabled/ 12 13# Enable a site (create symlink) 14ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/ 15 16# Disable a site (remove symlink) 17rm /etc/nginx/sites-enabled/mysite 18 19# Check which sites are enabled 20ls -l /etc/nginx/sites-enabled/

Process and Port Information

Bash
1# Check if Nginx is running 2ps aux | grep nginx 3 4# See which ports Nginx is listening on 5netstat -tlnp | grep nginx 6# or 7ss -tlnp | grep nginx 8 9# See Nginx process tree 10pstree -p | grep nginx 11 12# Check Nginx version 13nginx -v 14 15# Check Nginx version and configuration 16nginx -V

Permission and Ownership Commands

Bash
1# Fix ownership of website directory 2chown -R www-data:www-data /var/www/mysite 3 4# Fix directory permissions (755 = rwxr-xr-x) 5chmod -R 755 /var/www/mysite 6 7# Fix file permissions (644 = rw-r--r--) 8find /var/www/mysite -type f -exec chmod 644 {} \; 9 10# Fix directory permissions specifically 11find /var/www/mysite -type d -exec chmod 755 {} \; 12 13# Verify permissions 14ls -la /var/www/mysite/

Common Configuration Patterns

Multiple Websites (Virtual Hosts)

Host multiple websites on the same server with different domains:

NGINX
1# First website - example.org 2server { 3 listen 80; 4 listen [::]:80; 5 server_name example.org www.example.org; 6 root /var/www/example; 7 index index.html; 8 9 location / { 10 try_files $uri $uri/ =404; 11 } 12} 13 14# Second website - another-site.com 15server { 16 listen 80; 17 listen [::]:80; 18 server_name another-site.com www.another-site.com; 19 root /var/www/another; 20 index index.html; 21 22 location / { 23 try_files $uri $uri/ =404; 24 } 25}

Redirect www to Non-www

Redirect all www traffic to the non-www version:

NGINX
1# Redirect www to non-www 2server { 3 listen 80; 4 listen [::]:80; 5 server_name www.example.org; 6 return 301 http://example.org$request_uri; 7} 8 9# Main server block 10server { 11 listen 80; 12 listen [::]:80; 13 server_name example.org; 14 root /var/www/mysite; 15 index index.html; 16 17 location / { 18 try_files $uri $uri/ =404; 19 } 20}

Redirect Non-www to www

Redirect all traffic to the www version:

NGINX
1# Redirect non-www to www 2server { 3 listen 80; 4 listen [::]:80; 5 server_name example.org; 6 return 301 http://www.example.org$request_uri; 7} 8 9# Main server block 10server { 11 listen 80; 12 listen [::]:80; 13 server_name www.example.org; 14 root /var/www/mysite; 15 index index.html; 16 17 location / { 18 try_files $uri $uri/ =404; 19 } 20}

Custom Error Pages

Create custom error pages for better user experience:

NGINX
1server { 2 listen 80; 3 server_name example.org; 4 root /var/www/mysite; 5 index index.html; 6 7 # Custom 404 page 8 error_page 404 /404.html; 9 location = /404.html { 10 internal; 11 } 12 13 # Custom 50x pages 14 error_page 500 502 503 504 /50x.html; 15 location = /50x.html { 16 internal; 17 } 18 19 location / { 20 try_files $uri $uri/ =404; 21 } 22}

PHP Support (PHP-FPM)

Configure Nginx to work with PHP:

NGINX
1server { 2 listen 80; 3 server_name example.org; 4 root /var/www/mysite; 5 index index.php index.html; 6 7 location / { 8 try_files $uri $uri/ =404; 9 } 10 11 # PHP processing 12 location ~ \.php$ { 13 include snippets/fastcgi-php.conf; 14 fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; 15 } 16 17 # Deny access to .htaccess files 18 location ~ /\.ht { 19 deny all; 20 } 21}

Reverse Proxy Configuration

Use Nginx as a reverse proxy to forward requests to another server:

NGINX
1server { 2 listen 80; 3 server_name example.org; 4 5 location / { 6 proxy_pass http://localhost:3000; 7 proxy_http_version 1.1; 8 proxy_set_header Upgrade $http_upgrade; 9 proxy_set_header Connection 'upgrade'; 10 proxy_set_header Host $host; 11 proxy_cache_bypass $http_upgrade; 12 proxy_set_header X-Real-IP $remote_addr; 13 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 14 proxy_set_header X-Forwarded-Proto $scheme; 15 } 16}

Static File Caching

Improve performance by caching static files:

NGINX
1server { 2 listen 80; 3 server_name example.org; 4 root /var/www/mysite; 5 index index.html; 6 7 location / { 8 try_files $uri $uri/ =404; 9 } 10 11 # Cache static files 12 location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ { 13 expires 30d; 14 add_header Cache-Control "public, immutable"; 15 } 16}

Gzip Compression

Enable compression to reduce bandwidth and improve load times:

NGINX
1# Add to /etc/nginx/nginx.conf in the http block 2http { 3 # ... other settings ... 4 5 # Gzip compression 6 gzip on; 7 gzip_vary on; 8 gzip_proxied any; 9 gzip_comp_level 6; 10 gzip_types text/plain text/css text/xml text/javascript 11 application/json application/javascript application/xml+rss 12 application/rss+xml font/truetype font/opentype 13 application/vnd.ms-fontobject image/svg+xml; 14 gzip_disable "msie6"; 15}

Rate Limiting (DoS Protection)

Protect against abuse and DoS attacks:

NGINX
1# Add to /etc/nginx/nginx.conf in the http block 2http { 3 # Define rate limit zone (10MB can store ~160k IP addresses) 4 limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s; 5 6 server { 7 listen 80; 8 server_name example.org; 9 root /var/www/mysite; 10 11 location / { 12 # Apply rate limit (burst allows temporary exceeding) 13 limit_req zone=one burst=20 nodelay; 14 try_files $uri $uri/ =404; 15 } 16 } 17}

Security Headers

Add security headers to protect against common vulnerabilities:

NGINX
1server { 2 listen 80; 3 server_name example.org; 4 root /var/www/mysite; 5 6 # Security headers 7 add_header X-Frame-Options "SAMEORIGIN" always; 8 add_header X-Content-Type-Options "nosniff" always; 9 add_header X-XSS-Protection "1; mode=block" always; 10 add_header Referrer-Policy "no-referrer-when-downgrade" always; 11 add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always; 12 13 location / { 14 try_files $uri $uri/ =404; 15 } 16}

Website Directory Structure Best Practices

CODE
1/var/www/ 2├── example.org/ 3│ ├── html/ 4│ │ ├── index.html 5│ │ ├── about.html 6│ │ ├── contact.html 7│ │ └── assets/ 8│ │ ├── css/ 9│ │ │ └── style.css 10│ │ ├── js/ 11│ │ │ └── main.js 12│ │ └── images/ 13│ │ ├── logo.png 14│ │ └── banner.jpg 15│ └── logs/ # Optional: site-specific logs 16│ ├── access.log 17│ └── error.log 18├── another-site.com/ 19│ └── html/ 20│ └── index.html 21└── default/ 22 └── html/ 23 └── index.html

File Permission Best Practices

Bash
1# Set correct ownership (www-data is nginx's default user) 2chown -R www-data:www-data /var/www/mysite 3 4# Set directory permissions (755 = rwxr-xr-x) 5find /var/www/mysite -type d -exec chmod 755 {} \; 6 7# Set file permissions (644 = rw-r--r--) 8find /var/www/mysite -type f -exec chmod 644 {} \; 9 10# Verify permissions 11ls -la /var/www/mysite/

Permission Breakdown:

  • CODE
    755
    for directories: Owner can read/write/execute, others can read/execute
  • CODE
    644
    for files: Owner can read/write, others can only read
  • CODE
    www-data
    user: Default Nginx process user

Complete Workflow - Step by Step

Here's the complete setup process from start to finish:

Bash
1# Step 1: Update system 2apt update && apt upgrade 3apt install nginx ufw 4 5# Step 2: Create site configuration 6nano /etc/nginx/sites-available/mysite 7# Add your server block configuration (see examples above) 8 9# Step 3: Create website directory and content 10mkdir -p /var/www/mysite 11nano /var/www/mysite/index.html 12# Add your HTML content 13 14# Step 4: Set correct permissions 15chown -R www-data:www-data /var/www/mysite 16chmod -R 755 /var/www/mysite 17 18# Step 5: Enable the site 19ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/ 20 21# Step 6: Test configuration 22nginx -t 23 24# Step 7: Reload Nginx (if test passes) 25systemctl reload nginx 26 27# Step 8: Configure firewall (CRITICAL: Allow SSH first!) 28ufw allow 22/tcp # SSH access - DO THIS FIRST! 29ufw allow 80/tcp # HTTP 30ufw allow 443/tcp # HTTPS 31ufw enable # Enable firewall 32ufw status verbose # Verify configuration 33 34# Step 9: Security hardening 35nano /etc/nginx/nginx.conf 36# Uncomment: server_tokens off; 37systemctl reload nginx 38 39# Step 10: Verify everything works 40systemctl status nginx # Check Nginx status 41curl http://localhost # Test locally 42curl http://your-domain.com # Test remotely 43 44# Step 11: Monitor logs 45tail -f /var/log/nginx/access.log # Watch access log 46tail -f /var/log/nginx/error.log # Watch error log

Next Steps

Essential Follow-up Tasks

  1. SSL/TLS Certificate: Use Certbot for HTTPS encryption
  2. Security Headers: Add security-related HTTP headers
  3. Performance: Enable gzip compression
  4. Caching: Configure browser caching
  5. Monitoring: Set up log monitoring and alerts
  • Certbot and HTTPS setup
  • Nginx performance tuning
  • Security best practices
  • Load balancing configurations

Important Security Reminders

Regular Maintenance

Bash
1# Update system regularly 2apt update && apt upgrade 3 4# Update nginx 5apt install --only-upgrade nginx 6 7# Check for security patches 8apt list --upgradable

Security Checklist

  • Hide nginx version (
    CODE
    server_tokens off
    )
  • Keep software updated
  • Use HTTPS (install SSL certificate)
  • Configure firewall properly
  • Use strong passwords
  • Disable unnecessary modules
  • Regular backups
  • Monitor logs for suspicious activity

Troubleshooting Guide

Website Not Loading

Symptom: Cannot access website in browser

Check Nginx Status:

Bash
1# Verify Nginx is running 2systemctl status nginx 3 4# If not running, start it 5systemctl start nginx

Test Configuration:

Bash
1# Check for syntax errors 2nginx -t 3 4# View error log 5tail -50 /var/log/nginx/error.log

Check Network:

Bash
1# Verify Nginx is listening on port 80 2netstat -tlnp | grep :80 3# or 4ss -tlnp | grep :80 5 6# Test local connection 7curl http://localhost 8 9# Test from outside (using your domain) 10curl http://example.org

Check Firewall:

Bash
1# Verify ports are open 2ufw status 3 4# If not, allow them 5ufw allow 80/tcp 6ufw allow 443/tcp

404 Not Found Errors

Symptom: Nginx is running but shows 404 errors

Common Causes and Solutions:

1. Incorrect

CODE
root
directive:

Bash
1# Verify root path in config 2grep "root" /etc/nginx/sites-enabled/mywebsite 3 4# Check if directory exists 5ls -la /var/www/mysite

2. Missing index file:

Bash
1# Check for index.html 2ls -la /var/www/mysite/index.html 3 4# Create if missing 5nano /var/www/mysite/index.html

3. Wrong

CODE
server_name
:

Bash
1# Verify server_name matches your domain 2grep "server_name" /etc/nginx/sites-enabled/mywebsite 3 4# Test with curl 5curl -H "Host: example.org" http://localhost

4. File permissions:

Bash
1# Check current permissions 2ls -la /var/www/mysite/ 3 4# Fix if needed 5chown -R www-data:www-data /var/www/mysite 6chmod -R 755 /var/www/mysite

Configuration Changes Not Taking Effect

Symptom: Made changes but website looks the same

Solution Steps:

Bash
1# 1. Test configuration syntax 2nginx -t 3 4# 2. If successful, reload Nginx 5systemctl reload nginx 6 7# 3. If reload doesn't work, try restart 8systemctl restart nginx 9 10# 4. Check for errors 11tail -f /var/log/nginx/error.log 12 13# 5. Clear browser cache or use incognito mode

Permission Denied Errors

Symptom: Permission errors in error log

Check Error Log:

Bash
tail -50 /var/log/nginx/error.log | grep "Permission denied"

Fix Ownership:

Bash
1# Set correct owner 2chown -R www-data:www-data /var/www/mysite 3 4# Set correct permissions 5chmod -R 755 /var/www/mysite

Check SELinux (if applicable):

Bash
1# Check if SELinux is enforcing 2getenforce 3 4# If yes, you may need to adjust contexts 5chcon -R -t httpd_sys_content_t /var/www/mysite

Port Already in Use

Symptom: Cannot start Nginx - port 80 already in use

Find what's using the port:

Bash
1# Check what's listening on port 80 2netstat -tlnp | grep :80 3# or 4ss -tlnp | grep :80 5 6# Alternative: use lsof 7lsof -i :80

Common Solutions:

If Apache is running:

Bash
1# Stop Apache 2systemctl stop apache2 3 4# Disable Apache from starting on boot 5systemctl disable apache2

If another Nginx instance:

Bash
1# Kill all Nginx processes 2killall nginx 3 4# Start Nginx fresh 5systemctl start nginx

SSL/HTTPS Issues

Common HTTPS problems and solutions

Certificate not found:

Bash
1# Verify certificate files exist 2ls -la /etc/letsencrypt/live/example.org/ 3 4# Check certificate paths in config 5grep "ssl_certificate" /etc/nginx/sites-enabled/mywebsite

Mixed content warnings:

  • Ensure all resources (images, CSS, JS) use HTTPS
  • Update internal links from
    CODE
    http://
    to
    CODE
    https://
  • Or use protocol-relative URLs:
    CODE
    //example.org/style.css

Debugging Tools and Commands

Bash
1# Check overall system logs 2journalctl -xe 3 4# Follow Nginx error log in real-time 5tail -f /var/log/nginx/error.log 6 7# Check access log for recent requests 8tail -50 /var/log/nginx/access.log 9 10# Test DNS resolution 11nslookup example.org 12dig example.org 13 14# Test HTTP response 15curl -I http://example.org 16 17# Verbose HTTP test 18curl -v http://example.org 19 20# Test with specific host header 21curl -H "Host: example.org" http://server-ip

Best Practices

Commit Message Best Practices (for version control)

When working with configuration files in version control:

  • Use descriptive commit messages
  • Document why changes were made
  • Keep backups before major changes
  • Test configurations before deploying to production

Nginx Configuration Best Practices

General Guidelines:

  1. Keep
    CODE
    main
    branch stable
    - Test changes in development first
  2. Use descriptive file names - Name configs after domain names
  3. Comment your configurations - Explain complex rules
  4. Test before reload - Always run
    CODE
    nginx -t
    first
  5. Use version control - Track configuration changes with Git
  6. Regular backups - Backup configs before major changes
  7. Monitor logs - Regularly check error and access logs
  8. Keep it simple - Don't over-complicate configurations
  9. Use includes - Split large configs into smaller files
  10. Document customizations - Note why non-standard settings exist

Security Best Practices

  • Always use HTTPS with valid SSL certificates
  • Keep Nginx and system packages updated
  • Hide server version information
  • Implement rate limiting to prevent DoS
  • Use security headers (CSP, HSTS, X-Frame-Options)
  • Restrict access to sensitive files and directories
  • Regular security audits of configurations
  • Monitor logs for suspicious activity
  • Use fail2ban to block malicious IPs
  • Implement strong firewall rules

Performance Best Practices

  • Enable gzip compression
  • Configure browser caching for static files
  • Use HTTP/2 when possible
  • Optimize worker processes and connections
  • Implement CDN for static content
  • Minimize use of server-side includes
  • Use efficient location block matching
  • Monitor and optimize slow requests

Documentation

Configuration Generator

  • Mozilla SSL Configuration Generator
  • Nginx configuration generator tools

Community

  • Nginx mailing list
  • Stack Overflow nginx tag
  • Reddit r/nginx

Quick Reference Card

Essential Daily Commands

Bash
1# Installation & Setup 2apt update && apt upgrade # Update system 3apt install nginx # Install Nginx 4apt install ufw # Install firewall 5 6# Service Control 7systemctl start nginx # Start Nginx 8systemctl stop nginx # Stop Nginx 9systemctl restart nginx # Restart Nginx 10systemctl reload nginx # Reload config (no downtime) 11systemctl status nginx # Check status 12systemctl enable nginx # Start on boot 13 14# Configuration Management 15nano /etc/nginx/sites-available/mysite # Edit site config 16ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/ # Enable site 17rm /etc/nginx/sites-enabled/mysite # Disable site 18nginx -t # Test configuration 19nginx -T # Show full configuration 20 21# Logs 22tail -f /var/log/nginx/error.log # Watch error log 23tail -f /var/log/nginx/access.log # Watch access log 24tail -n 50 /var/log/nginx/error.log # Last 50 errors 25 26# Firewall (UFW) 27ufw allow 22/tcp # SSH - ALLOW FIRST! 28ufw allow 80/tcp # HTTP 29ufw allow 443/tcp # HTTPS 30ufw enable # Enable firewall 31ufw status verbose # Check status 32ufw status numbered # Show rule numbers 33ufw delete [number] # Delete rule 34ufw disable # Disable firewall 35ufw reload # Reload rules 36 37# File Permissions 38chown -R www-data:www-data /var/www/mysite # Fix ownership 39chmod -R 755 /var/www/mysite # Fix directory permissions 40find /var/www/mysite -type f -exec chmod 644 {} \; # Fix file permissions 41 42# Debugging 43systemctl status nginx # Service status 44netstat -tlnp | grep nginx # Check listening ports 45ps aux | grep nginx # Check processes 46nginx -V # Show version and config options

Quick Workflow Reference

Bash
1# Complete setup from scratch 2apt update && apt upgrade 3apt install nginx ufw 4 5# Configure site 6nano /etc/nginx/sites-available/mysite 7mkdir -p /var/www/mysite 8nano /var/www/mysite/index.html 9ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/ 10 11# Test and apply 12nginx -t 13systemctl reload nginx 14 15# Configure firewall 16ufw allow 22/tcp 17ufw allow 80/tcp 18ufw allow 443/tcp 19ufw enable 20ufw status 21 22# Verify 23systemctl status nginx 24curl http://localhost

Conclusion

This comprehensive guide covers everything you need to set up, configure, and maintain an Nginx web server on Debian/Ubuntu Linux systems. From initial installation to advanced configurations, security hardening, and troubleshooting, you now have a complete reference for deploying professional web servers.

Key Takeaways:

  • Always test configurations with
    CODE
    nginx -t
    before applying changes
  • Enable UFW firewall but remember to allow SSH first to avoid lockouts
  • Keep your server and Nginx updated for security patches
  • Use HTTPS with SSL certificates for production websites
  • Monitor logs regularly for issues and security threats
  • Follow best practices for file permissions and directory structure

Remember: The best way to learn Nginx is by using it. Start with the basics, test thoroughly, and gradually incorporate more advanced features as you become comfortable.

Next Steps:

  1. Set up SSL/TLS certificates using Certbot for HTTPS
  2. Configure a reverse proxy for Node.js/Python applications
  3. Implement load balancing for high-traffic sites
  4. Set up automated backups of configurations
  5. Learn about Nginx caching for better performance

Happy server administration! 🚀

Last updated: January 2025

Additional Resources

Official Documentation

Configuration Tools

Security Resources

Community and Learning

Books and Guides