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.
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
- Initial Server Access
- System Update & Nginx Installation
- Nginx Configuration Structure
- Creating Your First Website
- Enabling the Website
- Firewall Configuration (UFW)
- Security Hardening
- Testing Your Website
- Essential Nginx Commands
- Common Configuration Patterns
- Troubleshooting Guide
- Best Practices
- Quick Reference Card
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:
Bash5 lines1# 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
- Log into your VPS provider's control panel (Vultr, DigitalOcean, etc.)
- Navigate to your server instance
- Locate the root password in the server details section
- Copy the password for SSH authentication
System Update & Nginx Installation
Update Your System
Always start by updating your package lists and upgrading existing packages:
Bash2 lines1apt update # Refresh package database 2apt upgrade # Install available updates
What these commands do:
- - Checks repositories for package updatesCODE1 line
apt update - - Installs the latest versions of installed packagesCODE1 line
apt upgrade
Install Nginx
Install the Nginx web server package:
Bash1 lineapt 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:
CODE6 lines1/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:
- Create configuration file in CODE1 line
sites-available - Test the configuration
- Create symlink in to activateCODE1 line
sites-enabled - Reload Nginx to apply changes
Creating Your First Website
Step 1: Create Configuration File
Use a text editor to create a new site configuration:
Bash1 linenano /etc/nginx/sites-available/mywebsite
Note: Replace
mywebsiteblogportfolioexample.orgStep 2: Basic Nginx Configuration
Add this configuration template to your file:
NGINX10 lines1server { 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:
- - Change to your actual domainCODE1 line
server_name example.org - - Change to your preferred directory nameCODE1 line
root /var/www/mysite
Configuration Directives Explained
| Directive | Purpose | Example Value |
|---|---|---|
CODE 1 line listen 80 | Listen for IPv4 HTTP connections | Port 80 (standard HTTP) |
CODE 1 line listen [::]:80 | Listen for IPv6 HTTP connections | Port 80 with IPv6 support |
CODE 1 line server_name | Domain name(s) for this site | CODE 1 line example.org www.example.org |
CODE 1 line root | Directory containing website files | CODE 1 line /var/www/mysite |
CODE 1 line index | Default files to serve | CODE 1 line index.html index.htm |
CODE 1 line location / | URL routing configuration | Root location block |
CODE 1 line try_files | File lookup order | Try file, directory, then 404 |
Detailed Breakdown
listen directives:
- Port 80 is the standard HTTP port (unencrypted traffic)
- The enables IPv6 supportCODE1 line
[::]:80 - Both are necessary for full internet accessibility
server_name:
- Specifies which domain names this configuration handles
- When someone visits , Nginx uses this configCODE1 line
example.org - Can include multiple domains: CODE1 line
server_name example.org www.example.org;
root:
- The filesystem path where your website files are stored
- Convention is to use as the base directoryCODE1 line
/var/www/ - Full path example: CODE1 line
/var/www/mysite/index.html
index:
- Default files Nginx looks for when accessing a directory
- When visiting , it servesCODE1 line
example.org/CODE1 lineexample.org/index.html - Tries files in order from left to right
location block:
- Defines how Nginx handles different URL paths
- The location matches all requestsCODE1 line
/ - means:CODE1 line
try_files $uri $uri/ =404- Try to serve the exact file requested ()CODE1 line
$uri - Try to serve it as a directory ()CODE1 line
$uri/ - Return 404 error if neither exists
- Try to serve the exact file requested (
Step 3: Create Website Directory
Create the directory to hold your website files:
Bash1 linemkdir -p /var/www/mysite
The
-pStep 4: Create Your First Web Page
Create an HTML file that will be your website's homepage:
Bash1 linenano /var/www/mysite/index.html
Add this basic HTML content:
HTML13 lines1<!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
Create Symbolic Link
Activate your website configuration by creating a symbolic link:
Bash1 lineln -s /etc/nginx/sites-available/mywebsite /etc/nginx/sites-enabled/
What this command does:
- creates a symbolic link (like a shortcut)CODE1 line
ln -s - Links from to your configuration inCODE1 line
sites-enabledCODE1 linesites-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:
Bash1 linenginx -t
Expected output if successful:
CODE2 lines1nginx: 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:
Bash1 linesystemctl reload nginx
Service Management Commands
Bash7 lines1systemctl 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:
- - Applies configuration changes without dropping connectionsCODE1 line
reload - - Completely stops and starts the service (may drop active connections)CODE1 line
restart
Firewall Configuration (UFW)
Check UFW Status
First, verify if UFW (Uncomplicated Firewall) is installed and check its status:
Bash1 lineufw status
Install UFW (If Not Installed)
If UFW isn't installed on your system:
Bash1 lineapt install ufw
Initial UFW Setup and Configuration
⚠️ CRITICAL WARNING: Always allow SSH before enabling UFW to prevent being locked out of your server!
Bash16 lines1# 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
ufw status verboseCODE13 lines1Status: 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
Bash16 lines1# 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
Bash21 lines1# 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
Bash8 lines1# 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
Bash9 lines1# 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
| Port | Protocol | Service | When to Open |
|---|---|---|---|
| 22 | TCP | SSH | Always (CRITICAL for remote access) |
| 80 | TCP | HTTP | Web server (unencrypted) |
| 443 | TCP | HTTPS | Web server (encrypted/SSL) |
| 21 | TCP | FTP | File transfer (avoid, use SFTP instead) |
| 22 | TCP | SFTP | Secure file transfer (uses SSH) |
| 25 | TCP | SMTP | Email sending |
| 587 | TCP | SMTP | Email submission (TLS) |
| 993 | TCP | IMAPS | Email retrieval (secure) |
| 3306 | TCP | MySQL | Database (usually keep internal only) |
| 5432 | TCP | PostgreSQL | Database (usually keep internal only) |
| 6379 | TCP | Redis | Cache (usually keep internal only) |
| 27017 | TCP | MongoDB | Database (usually keep internal only) |
Advanced UFW Configuration
Rate Limiting (Prevent Brute Force)
Bash5 lines1# 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
Bash6 lines1# 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
Bash10 lines1# 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
Bash14 lines1# 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:
- Always allow SSH before enabling - This cannot be stressed enough!
- Use specific protocols - Prefer over justCODE1 line
80/tcpCODE1 line80 - Follow principle of least privilege - Only open ports you actually need
- Use rate limiting for SSH - prevents brute forceCODE1 line
ufw limit 22/tcp - Regular audits - Periodically review rules with CODE1 line
ufw status numbered - Remove unused rules - Delete rules for services you no longer run
- Use comments - Unfortunately UFW doesn't support comments, so document separately
- 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 andCODE1 line
ufw allow 22/tcpCODE1 lineufw reload - Consider using a recovery mode or console access
Rules Not Working
Bash14 lines1# 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
Bash10 lines1# 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:
Bash1 linenano /etc/nginx/nginx.conf
Step 2: Find and Uncomment
Look for this line in the
httpNGINX1 line# server_tokens off;
Uncomment it by removing the
#NGINX1 lineserver_tokens off;
Step 3: Test and Apply
Bash5 lines1# Test configuration syntax 2nginx -t 3 4# If successful, reload Nginx 5systemctl reload nginx
Verify the Change
Before the change:
CODE2 lines1HTTP/1.1 404 Not Found 2Server: nginx/1.18.0
After the change:
CODE2 lines1HTTP/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:
Bash11 lines1# 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:
Bash5 lines1# Install unattended-upgrades 2apt install unattended-upgrades 3 4# Enable automatic security updates 5dpkg-reconfigure -plow unattended-upgrades
Security Checklist
- Hide Nginx version ()CODE1 line
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:
CODE1 linehttp://example.org
(Replace
example.orgWhat 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:
Bash11 lines1# 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
Bash11 lines1# 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
Bash23 lines1# 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!
Bash8 lines1# 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
Bash11 lines1# 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
Bash11 lines1# 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
Bash20 lines1# 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
Bash16 lines1# 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
Bash14 lines1# 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:
NGINX25 lines1# 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:
NGINX20 lines1# 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:
NGINX20 lines1# 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:
NGINX22 lines1server { 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:
NGINX21 lines1server { 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:
NGINX16 lines1server { 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:
NGINX16 lines1server { 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:
NGINX15 lines1# 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:
NGINX17 lines1# 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:
NGINX16 lines1server { 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
Recommended File Organization
CODE23 lines1/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
Bash11 lines1# 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:
- for directories: Owner can read/write/execute, others can read/executeCODE1 line
755 - for files: Owner can read/write, others can only readCODE1 line
644 - user: Default Nginx process userCODE1 line
www-data
Complete Workflow - Step by Step
Here's the complete setup process from start to finish:
Bash46 lines1# 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
- SSL/TLS Certificate: Use Certbot for HTTPS encryption
- Security Headers: Add security-related HTTP headers
- Performance: Enable gzip compression
- Caching: Configure browser caching
- Monitoring: Set up log monitoring and alerts
Recommended Reading
- Certbot and HTTPS setup
- Nginx performance tuning
- Security best practices
- Load balancing configurations
Important Security Reminders
Regular Maintenance
Bash8 lines1# 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 ()CODE1 line
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:
Bash5 lines1# Verify Nginx is running 2systemctl status nginx 3 4# If not running, start it 5systemctl start nginx
Test Configuration:
Bash5 lines1# Check for syntax errors 2nginx -t 3 4# View error log 5tail -50 /var/log/nginx/error.log
Check Network:
Bash10 lines1# 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:
Bash6 lines1# 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 root
Bash5 lines1# 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:
Bash5 lines1# Check for index.html 2ls -la /var/www/mysite/index.html 3 4# Create if missing 5nano /var/www/mysite/index.html
3. Wrong server_name
Bash5 lines1# 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:
Bash6 lines1# 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:
Bash13 lines1# 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:
Bash1 linetail -50 /var/log/nginx/error.log | grep "Permission denied"
Fix Ownership:
Bash5 lines1# 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):
Bash5 lines1# 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:
Bash7 lines1# 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:
Bash5 lines1# Stop Apache 2systemctl stop apache2 3 4# Disable Apache from starting on boot 5systemctl disable apache2
If another Nginx instance:
Bash5 lines1# 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:
Bash5 lines1# 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 toCODE1 line
http://CODE1 linehttps:// - Or use protocol-relative URLs: CODE1 line
//example.org/style.css
Debugging Tools and Commands
Bash21 lines1# 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:
- Keep branch stable - Test changes in development firstCODE1 line
main - Use descriptive file names - Name configs after domain names
- Comment your configurations - Explain complex rules
- Test before reload - Always run firstCODE1 line
nginx -t - Use version control - Track configuration changes with Git
- Regular backups - Backup configs before major changes
- Monitor logs - Regularly check error and access logs
- Keep it simple - Don't over-complicate configurations
- Use includes - Split large configs into smaller files
- 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
- Official Nginx docs: https://nginx.org/en/docs/
- Nginx beginner's guide: https://nginx.org/en/docs/beginners_guide.html
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
Bash46 lines1# 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
Bash24 lines1# 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 before applying changesCODE1 line
nginx -t - 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:
- Set up SSL/TLS certificates using Certbot for HTTPS
- Configure a reverse proxy for Node.js/Python applications
- Implement load balancing for high-traffic sites
- Set up automated backups of configurations
- 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
- Nginx Forum
- Nginx Mailing List
- Stack Overflow - Nginx Tag
- Reddit r/nginx
- DigitalOcean Nginx Tutorials
Books and Guides
- "Nginx HTTP Server" by Clément Nedelcu
- "Mastering Nginx" by Dimitri Aivaliotis
- Nginx Cookbook (Free)
Related Tools
- Certbot - Free SSL certificate automation
- fail2ban - Intrusion prevention
- ModSecurity - Web application firewall
- ngxtop - Real-time metrics for Nginx