Section 1 — Introduction to Servers

1.1 What Is a Server?

Think of a server as a powerful computer that runs 24/7, waiting for people to connect and ask for things — web pages, images, database data, etc.

Real-world analogy: A restaurant kitchen. The client is the customer. The server is the kitchen. When the customer (browser) orders food (a web page), the kitchen (server) prepares it and sends it to the table (browser).

Your LaptopA Server
Turned off at nightRuns 24 hours a day, 7 days a week
Used by 1 personUsed by hundreds to millions simultaneously
Has a screen & keyboardUsually no screen — managed remotely via SSH
Consumer hardwareHigh-performance hardware (more RAM, CPU, RAID)
Runs Windows or macOSUsually runs Linux
Located at your deskLocated in a Data Center

Linux Distributions

90%+ of all web servers run Linux. Linux comes in different "flavors" called distributions (distros):

DistributionUsed For
UbuntuWeb servers, development (most popular for beginners)
DebianStable production servers
CentOS / AlmaLinuxEnterprise environments
AlpineDocker containers (very minimal)
ℹ️
At WEBONICTECH

We primarily use Ubuntu 20.04 LTS or Ubuntu 22.04 LTS on all production and staging servers.

1.2 VPS & Cloud Hosting

What Is a VPS?

VPS = Virtual Private Server. A VPS is a virtual machine hosted in a data center. A physical server is divided into multiple virtual servers using virtualization software (KVM, VMware).

Physical Server (64GB RAM, 32 CPU cores)
├── VPS 1 (4GB RAM, 2 CPU)  → Your client's live server
├── VPS 2 (8GB RAM, 4 CPU)  → Another client's server
├── VPS 3 (2GB RAM, 1 CPU)  → Staging server
└── VPS 4 (16GB RAM, 8CPU)  → Large e-commerce server
FeatureShared HostingVPS
ControlVery LimitedFull Root Access
PerformanceAffected by other usersDedicated resources
Price$3–$10/month$5–$80/month
CustomizationAlmost noneFully customizable
Use caseSimple WordPress sitesBusiness apps, custom setups

Local Machine vs Production Server

Your Local Machine               Production Server
─────────────────                ──────────────────
Windows / macOS / Ubuntu         Ubuntu Linux (headless)
XAMPP / Laragon / WAMP           Apache2 / Nginx + PHP-FPM
MySQL (local)                    MySQL (production, secured)
localhost:8000                   yourdomain.com
Only you access it               Thousands of users access it
.env has debug=true              .env has debug=false (NEVER expose)
Loose file permissions (777 OK)  Strict permissions (644, 755)
No SSL needed                    SSL mandatory
⚠️
Golden Rule for Freshers

What works on your local machine may NOT work on the server immediately. Always check permissions, paths, environment variables, and PHP versions.

1.3 Client–Server Architecture

Every website interaction follows this pattern:

Browser (Client)
     │
     │  HTTP Request: GET /index.php HTTP/1.1
     ▼
Web Server (Apache2 / Nginx)     ← Port 80 / 443
     │
     │  Dynamic request
     ▼
Application Layer (PHP / Node.js / Python)
     │
     │  Database query
     ▼
Database (MySQL / MongoDB / Redis)
     │
     │  Response data
     ▼
Application → Web Server → Browser
     └── Browser renders the HTML, CSS, JS

1.4 What Happens When You Type a Domain?

This is one of the most common interview questions. Know this process deeply.

User types: https://www.example.com
     │
     ▼
1. Browser Cache Check
     │
     ▼
2. OS hosts file check (/etc/hosts on Linux)
     │
     ▼
3. DNS Resolver (ISP or Google 8.8.8.8)
     │
     ▼
4. Root DNS → TLD Server (.com) → Authoritative DNS
   └── Returns IP: 203.0.113.42
     │
     ▼
5. Browser connects to 203.0.113.42 on Port 443
     │
     ▼
6. TCP Handshake (SYN → SYN-ACK → ACK)
     │
     ▼
7. SSL/TLS Handshake (certificate verification)
     │
     ▼
8. HTTP Request sent:
   GET / HTTP/1.1
   Host: www.example.com
     │
     ▼
9. Web Server matches Virtual Host / Server Block
     │
     ▼
10. Application processes, queries DB
     │
     ▼
11. HTTP 200 OK response + HTML sent back
     │
     ▼
12. Browser renders the page ✓

1.5 Ports, Protocols & DNS Records

PortService
22SSH (remote access)
80HTTP (web)
443HTTPS (secure web)
3306MySQL / MariaDB
27017MongoDB
6379Redis
3000Node.js apps (common default)
9000PHP-FPM
25 / 587SMTP (email)
DNS RecordPurposeExample
A RecordMaps domain to IPv4example.com → 203.0.113.42
AAAA RecordMaps domain to IPv6example.com → 2001:db8::1
CNAME RecordAlias to another domainwww → example.com
MX RecordMail servermail.example.com
TXT RecordVerification, SPF, DKIMVarious
NS RecordNameservers for domainns1.cloudflare.com

Section 2 — Linux Fundamentals

2.1 The Linux Directory Structure

Unlike Windows (C:\, D:\), Linux has ONE root directory: /. Everything branches from it.

/                          ← Root (top of everything)
├── etc/                   ← All system configuration files
│   ├── apache2/           ← Apache config
│   ├── nginx/             ← Nginx config
│   ├── mysql/             ← MySQL config
│   ├── ssh/sshd_config    ← SSH config
│   └── crontab            ← System cron jobs
├── home/                  ← Home folders for regular users
│   └── ubuntu/            ← SSH user's home
├── tmp/                   ← Temporary files (cleared on reboot)
├── var/
│   ├── log/               ← ALL system logs
│   │   ├── apache2/       ← Apache access + error logs
│   │   ├── nginx/         ← Nginx logs
│   │   └── syslog         ← General system log
│   └── www/               ← Web files root
│       └── html/          ← Default web root
└── opt/                   ← Manually installed software (Node.js via nvm)
💡
Three Most Important Directories

/etc — all config files  |  /var/www — your website files  |  /var/log — all log files for debugging

2.2 Connecting via SSH

# Connect using password
ssh ubuntu@203.0.113.42

# Connect using SSH key (recommended and more secure)
ssh -i /path/to/private-key.pem ubuntu@203.0.113.42

# Connect on a different port
ssh -p 2222 ubuntu@203.0.113.42
# Where am I right now?
pwd

# List files
ls -la          # Long format + hidden files
ls -lh          # Human-readable file sizes
ls -lt          # Sort by time (newest first)

# Change directory
cd /var/www/html          # Go to absolute path
cd ..                     # Go up one level
cd ~                      # Go to home folder
cd -                      # Go to previous directory

# View file contents
cat /etc/nginx/nginx.conf
less /var/log/nginx/error.log   # Page by page (q to quit)
tail -f /var/log/nginx/error.log   # Follow live (Ctrl+C to stop)
tail -n 50 -f /var/log/apache2/error.log

2.4 File & Directory Operations

# Create directories
mkdir -p /var/www/myproject/public   # -p creates parent dirs

# Create/edit files
touch index.php
nano .env
echo "APP_ENV=production" >> .env   # >> appends, > overwrites

# Copy
cp -r /var/www/oldsite /var/www/newsite

# Move / rename
mv oldname.php newname.php

# Delete — VERY CAREFUL
rm filename.php
rm -rf /var/www/mysite   # Deletes everything inside — no undo!

# Search files
find /var/www -name "wp-config.php"
grep -r "database_error" /var/www/mysite/
grep -n "APP_DEBUG" .env   # -n shows line numbers
🚨
rm -rf Warning

rm -rf does NOT have an undo. There is no Recycle Bin. Always run ls on the path first to confirm what you're deleting. NEVER run rm -rf /.

2.5 File Permissions & Ownership

Linux permissions control who can read, write, or execute a file. Every file has three sets of permissions: owner, group, others.

PermissionSymbolNumber
Readr4
Writew2
Executex1
No permission-0
ValueMeaningUse Case
644rw-r--r--Standard PHP/HTML files
755rwxr-xr-xDirectories, scripts
600rw-------.env file (owner only)
775rwxrwxr-xLaravel storage/, bootstrap/cache/
777rwxrwxrwx⚠️ NEVER use on production
# Change permissions
chmod 644 index.php
chmod -R 755 /var/www/mysite
chmod 600 .env

# Change ownership (Apache/Nginx run as www-data)
chown www-data:www-data /var/www/mysite
chown -R www-data:www-data /var/www/mysite

# Typical Laravel permissions
sudo chown -R www-data:www-data /var/www/laravel-app
sudo chmod -R 755 /var/www/laravel-app
sudo chmod -R 775 /var/www/laravel-app/storage
sudo chmod -R 775 /var/www/laravel-app/bootstrap/cache
ℹ️
Why Ownership Matters

Apache2 and Nginx run as www-data. If your files are owned by root and www-data can't read them, you get 403 Forbidden. Understanding ownership is essential.

2.6 Package Management (APT) & Service Control

# APT — Advanced Package Tool
sudo apt update                    # Update package list (always do this first)
sudo apt upgrade                   # Upgrade all packages
sudo apt install nginx php8.2 git  # Install packages
sudo apt remove nginx              # Remove package
sudo apt purge nginx               # Remove + delete config files
sudo apt autoremove                # Remove unused dependencies

# systemctl — Service Management
sudo systemctl status nginx        # Check status
sudo systemctl start nginx         # Start service
sudo systemctl stop nginx          # Stop service
sudo systemctl restart nginx       # Full restart
sudo systemctl reload nginx        # Graceful reload (preferred for web servers)
sudo systemctl enable nginx        # Auto-start on boot
sudo systemctl disable nginx       # Disable auto-start

# View service logs
sudo journalctl -u nginx -f        # Follow logs in real-time
sudo journalctl -u nginx -n 50     # Last 50 lines

Disk & Memory Usage

df -h                    # Disk usage (human readable)
du -sh /var/www/*        # Size of each website directory
free -h                  # Memory usage
top                      # Real-time process monitor
htop                     # Better visual version (install with apt)
ps aux | grep nginx      # Find running process

2.7 Cron Jobs — Scheduled Tasks

Cron jobs are automated tasks that run on a schedule.

# Edit cron jobs for current user
crontab -e

# Cron syntax:
# ┌─── minute (0-59)
# │ ┌─── hour (0-23)
# │ │ ┌─── day of month (1-31)
# │ │ │ ┌─── month (1-12)
# │ │ │ │ ┌─── day of week (0-7, Sun=0)
# * * * * *  command

# Examples:
* * * * *   php /var/www/myapp/artisan schedule:run   # Every minute (Laravel)
0 2 * * *   mysqldump mydb > /backup/mydb.sql          # Daily at 2 AM
0 0 * * 0   certbot renew                              # Weekly SSL renewal
0 * * * *   php /var/www/mysite/cron.php               # Every hour

Section 3 — Apache2 Complete Guide

Apache HTTP Server (Apache2) is the world's most popular web server software, running since 1995. Its job: listen for HTTP/HTTPS requests, find the right files or pass the request to PHP, and send the response back.

3.1 Installation & Directory Structure

sudo apt update
sudo apt install apache2

apache2 -v                 # Check version
sudo systemctl status apache2
sudo apache2ctl configtest  # Test config (should output: Syntax OK)
/etc/apache2/
├── apache2.conf         ← Main configuration file
├── ports.conf           ← Which ports Apache listens on
├── sites-available/     ← All virtual host config files
│   ├── 000-default.conf ← Default site
│   └── mysite.conf      ← Your site config
├── sites-enabled/       ← SYMLINKS to active sites
├── mods-available/      ← All available modules
└── mods-enabled/        ← Enabled modules (symlinks)

/var/log/apache2/
├── access.log           ← Every request (IP, URL, status code)
└── error.log            ← All errors ← CHECK THIS FIRST when debugging

Essential Modules

sudo a2enmod rewrite    # URL rewriting (required for Laravel/WordPress)
sudo a2enmod ssl        # HTTPS support
sudo a2enmod headers    # HTTP security headers
sudo a2enmod expires    # Browser caching
sudo a2enmod proxy      # Reverse proxy
sudo a2enmod proxy_http # HTTP reverse proxy
sudo a2dismod autoindex # Disable directory listing (security)

sudo systemctl reload apache2  # Always reload after enabling modules

3.2 Virtual Hosts — Host Multiple Sites

A Virtual Host lets one Apache server host multiple websites on the same IP. Apache decides which site to show based on the domain in the request.

# 1. Create directory
sudo mkdir -p /var/www/mysite/public
sudo chown -R www-data:www-data /var/www/mysite

# 2. Create virtual host config
sudo nano /etc/apache2/sites-available/mysite.conf
<VirtualHost *:80>
    ServerName mysite.com
    ServerAlias www.mysite.com

    DocumentRoot /var/www/mysite/public

    ErrorLog ${APACHE_LOG_DIR}/mysite-error.log
    CustomLog ${APACHE_LOG_DIR}/mysite-access.log combined

    <Directory /var/www/mysite/public>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>
# 3. Enable the site
sudo a2ensite mysite.conf

# 4. Test config
sudo apache2ctl configtest   # Should say: Syntax OK

# 5. Reload Apache
sudo systemctl reload apache2

3.3 Apache VirtualHost for Laravel

ℹ️
Key Point

Laravel's DocumentRoot must point to the public/ subdirectory, NOT the project root. This prevents exposing .env, source code, and other sensitive files.

<VirtualHost *:80>
    ServerName mylaravelapp.com
    ServerAlias www.mylaravelapp.com
    DocumentRoot /var/www/laravel-app/public

    <Directory /var/www/laravel-app/public>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/laravel-app-error.log
    CustomLog ${APACHE_LOG_DIR}/laravel-app-access.log combined
</VirtualHost>
# Laravel permissions
sudo chown -R www-data:www-data /var/www/laravel-app
sudo chmod -R 755 /var/www/laravel-app
sudo chmod -R 775 /var/www/laravel-app/storage
sudo chmod -R 775 /var/www/laravel-app/bootstrap/cache

3.4 Apache VirtualHost for WordPress

<VirtualHost *:80>
    ServerName mywordpresssite.com
    ServerAlias www.mywordpresssite.com
    DocumentRoot /var/www/mywordpresssite

    <Directory /var/www/mywordpresssite>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/wordpress-error.log
    CustomLog ${APACHE_LOG_DIR}/wordpress-access.log combined
</VirtualHost>
# Enable mod_rewrite for WordPress pretty permalinks
sudo a2enmod rewrite
sudo systemctl reload apache2

3.5 .htaccess Reference

The .htaccess file is a per-directory config that overrides the main Apache config. Requires AllowOverride All in the VirtualHost.

.htaccess for WordPress

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

.htaccess for Laravel

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews -Indexes
    </IfModule>
    RewriteEngine On
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]
</IfModule>

.htaccess for Security

# Deny access to .env files (CRITICAL)
<Files ".env">
    Order allow,deny
    Deny from all
</Files>

# Disable directory listing
Options -Indexes

# Security headers
<IfModule mod_headers.c>
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-XSS-Protection "1; mode=block"
</IfModule>

# Force HTTPS
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

3.6 Apache with SSL (Let's Encrypt)

# Install Certbot
sudo apt install certbot python3-certbot-apache

# Get SSL certificate (auto-configures Apache)
sudo certbot --apache -d mysite.com -d www.mysite.com

# Test auto-renewal
sudo certbot renew --dry-run

3.7 Apache Troubleshooting Quick Reference

ErrorCommon CausesFix
403 Forbidden Wrong ownership, permissions too strict, AllowOverride not set chown -R www-data:www-data /var/www/mysite & set AllowOverride All
500 Internal Server Error PHP syntax error, .htaccess error, missing extension Check tail -f /var/log/apache2/error.log for the exact error
404 on pretty URLs mod_rewrite not enabled, AllowOverride None a2enmod rewrite then set AllowOverride All
Wrong site shows up VirtualHost conflict, default site catching requests Run apache2ctl -S to see VirtualHost routing

Section 4 — Nginx Complete Guide

Nginx (pronounced "Engine-X") is a high-performance web server that also acts as a reverse proxy, load balancer, and HTTP cache. Created to handle massive concurrent connections efficiently.

FeatureApache2Nginx
ArchitectureProcess/Thread-basedEvent-driven (async)
ConcurrencyStruggles at thousandsHandles 10,000+ connections easily
.htaccess support✅ Yes❌ No — config only in server blocks
PHP supportNative mod_phpRequires PHP-FPM (FastCGI)
Static filesGoodExcellent
Memory usageHigherLower
Best forPHP apps, WordPressHigh traffic, Node.js, reverse proxy, Next.js

4.1 Installation & Directory Structure

sudo apt update
sudo apt install nginx

nginx -v                  # Check version
sudo systemctl status nginx
sudo nginx -t             # Test configuration syntax

sudo systemctl enable nginx
sudo systemctl start nginx
/etc/nginx/
├── nginx.conf           ← Main configuration file
├── sites-available/     ← All server block configs
│   ├── default          ← Default server block
│   └── mysite.conf      ← Your site config
├── sites-enabled/       ← Symlinks to active configs
├── conf.d/              ← Additional config snippets
└── snippets/
    └── fastcgi-php.conf ← PHP-FPM settings

/var/log/nginx/
├── access.log
└── error.log

4.2 Nginx Server Blocks (Virtual Hosts)

In Nginx, virtual hosts are called server blocks.

server {
    listen 80;
    listen [::]:80;

    server_name mysite.com www.mysite.com;

    root /var/www/mysite/public;
    index index.php index.html;

    location / {
        try_files $uri $uri/ =404;
    }

    # PHP processing
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    }

    # Deny sensitive files
    location ~ /\.env { deny all; }
    location ~ /\.ht  { deny all; }

    access_log /var/log/nginx/mysite-access.log;
    error_log  /var/log/nginx/mysite-error.log;
}
# Enable the site
sudo ln -s /etc/nginx/sites-available/mysite.conf /etc/nginx/sites-enabled/

sudo nginx -t              # Test
sudo systemctl reload nginx

4.3 Nginx Server Block for Laravel

server {
    listen 80;
    server_name laravelapp.com www.laravelapp.com;
    root /var/www/laravel-app/public;
    index index.php;

    # Laravel URL rewriting (replaces .htaccess)
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

    # Deny all dotfiles (security)
    location ~ /\.(?!well-known).* {
        deny all;
    }

    error_log  /var/log/nginx/laravel-error.log;
    access_log /var/log/nginx/laravel-access.log;
}

4.4 Nginx Reverse Proxy for Node.js / Express

The most common use of Nginx in modern development: act as a gateway to a Node.js application.

Internet → Port 80/443 → Nginx (reverse proxy) → Port 3000 → Node.js App
server {
    listen 80;
    server_name nodeapp.com www.nodeapp.com;

    location / {
        proxy_pass http://127.0.0.1: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;

        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    access_log /var/log/nginx/nodeapp-access.log;
    error_log  /var/log/nginx/nodeapp-error.log;
}

4.5 Nginx Reverse Proxy for Next.js

server {
    listen 80;
    server_name mynextapp.com www.mynextapp.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # Serve Next.js static assets directly (performance)
    location /_next/static/ {
        alias /var/www/mynextapp/.next/static/;
        expires 365d;
        add_header Cache-Control "public, immutable";
    }
}

4.6 Nginx for React App (Static Build)

server {
    listen 80;
    server_name myreactapp.com www.myreactapp.com;

    root /var/www/myreactapp/build;
    index index.html;

    # Critical for React Router — prevents 404 on refresh
    location / {
        try_files $uri $uri/ /index.html;
    }

    # Cache static assets for 1 year
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}
💡
React Router & Nginx

Without try_files $uri $uri/ /index.html, refreshing a page like /about returns 404 because Nginx looks for a file named about on disk. This directive tells Nginx to fall back to index.html for all routes.

4.7 Nginx with SSL (Let's Encrypt)

# Install Certbot for Nginx
sudo apt install certbot python3-certbot-nginx

# Get and auto-configure SSL
sudo certbot --nginx -d mysite.com -d www.mysite.com

# Test auto-renewal
sudo certbot renew --dry-run
# Manual SSL configuration
server {
    listen 80;
    server_name mysite.com www.mysite.com;
    return 301 https://$server_name$request_uri;  # Redirect to HTTPS
}

server {
    listen 443 ssl http2;
    server_name mysite.com www.mysite.com;

    ssl_certificate     /etc/letsencrypt/live/mysite.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mysite.com/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;

    # HSTS — tell browsers to always use HTTPS
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;

    root /var/www/mysite/public;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}