🎁 New User? Get 20% off your first purchase with code NEWUSER20 Register Now β†’
Menu

Categories

How to Set Up a Production-Ready Linux Web Server from Scratch in 2026

How to Set Up a Production-Ready Linux Web Server from Scratch in 2026

Setting up a production web server is one of the most fundamental skills for any Linux administrator. While managed hosting and cloud platforms have simplified deployment, understanding how to build a server from scratch gives you complete control over performance, security, and cost. This guide walks you through every step, from a fresh OS installation to a fully hardened, monitored production server.

Choosing Your Operating System

For production web servers in 2026, we recommend one of these distributions:

  • Ubuntu Server 24.04 LTS β€” Wide community support, extensive package availability, 10 years of security updates
  • AlmaLinux 9 β€” RHEL-compatible, enterprise-grade stability, ideal for organizations standardized on Red Hat
  • Debian 12 (Bookworm) β€” Exceptional stability, minimal attack surface, preferred by security-conscious administrators

This guide uses Ubuntu Server 24.04 LTS for examples, with notes for AlmaLinux/RHEL where commands differ.

Step 1: Initial Server Setup

First Login and System Update

# Update package lists and upgrade all packages
sudo apt update && sudo apt upgrade -y

# Set timezone
sudo timedatectl set-timezone UTC

# Set hostname
sudo hostnamectl set-hostname webserver01

# Reboot to apply kernel updates
sudo reboot

Create a Non-Root Admin User

# Create a new admin user
sudo adduser deployer

# Add to sudo group
sudo usermod -aG sudo deployer

# Set up SSH key authentication for the new user
sudo mkdir -p /home/deployer/.ssh
sudo cp ~/.ssh/authorized_keys /home/deployer/.ssh/
sudo chown -R deployer:deployer /home/deployer/.ssh
sudo chmod 700 /home/deployer/.ssh
sudo chmod 600 /home/deployer/.ssh/authorized_keys

Step 2: SSH Hardening

SSH is your primary access method, so securing it properly is critical:

# Edit SSH configuration
sudo nano /etc/ssh/sshd_config

Apply these settings:

# Disable root login
PermitRootLogin no

# Disable password authentication (use keys only)
PasswordAuthentication no

# Change default port (optional but reduces automated scans)
Port 2222

# Limit login attempts
MaxAuthTries 3

# Set idle timeout (10 minutes)
ClientAliveInterval 300
ClientAliveCountMax 2

# Restrict to specific users
AllowUsers deployer

# Use only strong algorithms
KexAlgorithms sntrup761x25519-sha512@openssh.com,curve25519-sha256
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
# Restart SSH (keep your current session open!)
sudo systemctl restart sshd

# Test the new configuration from another terminal before closing this one

Step 3: Firewall Configuration

# Install and enable UFW
sudo apt install ufw -y

# Set default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Allow SSH (use your custom port if changed)
sudo ufw allow 2222/tcp comment "SSH"

# Allow HTTP and HTTPS
sudo ufw allow 80/tcp comment "HTTP"
sudo ufw allow 443/tcp comment "HTTPS"

# Enable the firewall
sudo ufw enable

# Verify rules
sudo ufw status verbose

Step 4: Install and Configure NGINX

# Install NGINX
sudo apt install nginx -y

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

# Verify installation
curl -I http://localhost

Optimize NGINX Configuration

# Edit main configuration
sudo nano /etc/nginx/nginx.conf

Key optimizations:

worker_processes auto;
worker_rlimit_nofile 65535;

events {
    worker_connections 4096;
    multi_accept on;
    use epoll;
}

http {
    # Basic settings
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    server_tokens off;

    # Gzip compression
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 5;
    gzip_types text/plain text/css application/json application/javascript
               text/xml application/xml application/xml+rss text/javascript
               image/svg+xml;

    # Security headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # Rate limiting
    limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

Create a Virtual Host

sudo nano /etc/nginx/sites-available/example.com
server {
    listen 80;
    server_name example.com www.example.com;
    root /var/www/example.com/public;
    index index.html index.php;

    access_log /var/log/nginx/example.com_access.log;
    error_log /var/log/nginx/example.com_error.log;

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

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

    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
}

# Enable the site
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Step 5: SSL Certificate with Let's Encrypt

# Install Certbot
sudo apt install certbot python3-certbot-nginx -y

# Obtain and install certificate
sudo certbot --nginx -d example.com -d www.example.com \
    --non-interactive --agree-tos --email admin@example.com

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

# The timer for auto-renewal is set up automatically
sudo systemctl status certbot.timer

Step 6: Install Fail2ban

# Install fail2ban
sudo apt install fail2ban -y

# Create local configuration
sudo nano /etc/fail2ban/jail.local
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5
banaction = ufw

[sshd]
enabled = true
port = 2222
maxretry = 3

[nginx-http-auth]
enabled = true

[nginx-limit-req]
enabled = true
logpath = /var/log/nginx/*error.log
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
sudo fail2ban-client status

Step 7: Automatic Security Updates

sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure -plow unattended-upgrades

Step 8: Basic Monitoring

# Install monitoring tools
sudo apt install htop iotop nethogs logwatch -y

# Set up logwatch for daily reports
sudo nano /etc/cron.daily/00logwatch
#!/bin/bash
/usr/sbin/logwatch --output mail --mailto admin@example.com --detail high

Step 9: Backup Configuration

# Create backup script
sudo nano /usr/local/bin/backup.sh
#!/bin/bash
BACKUP_DIR="/backup/$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"

# Backup NGINX configuration
tar czf "$BACKUP_DIR/nginx.tar.gz" /etc/nginx/

# Backup website files
tar czf "$BACKUP_DIR/www.tar.gz" /var/www/

# Backup SSL certificates
tar czf "$BACKUP_DIR/letsencrypt.tar.gz" /etc/letsencrypt/

# Remove backups older than 30 days
find /backup -type d -mtime +30 -exec rm -rf {} +

echo "Backup completed: $BACKUP_DIR"
sudo chmod +x /usr/local/bin/backup.sh

# Add to cron for daily execution at 2 AM
echo "0 2 * * * root /usr/local/bin/backup.sh" | sudo tee /etc/cron.d/daily-backup

Post-Setup Verification Checklist

  1. SSH access works with key authentication only
  2. Root login is disabled
  3. Firewall is active with only necessary ports open
  4. NGINX is serving your site with HTTPS
  5. SSL certificate is valid and auto-renewal works
  6. Fail2ban is protecting against brute force
  7. Automatic security updates are enabled
  8. Backups are configured and tested
  9. Monitoring is in place for resource usage and logs

Recommended Reading

Build on your web server skills with these comprehensive Dargslan guides:

Share this article:
Miles Everhart
About the Author

Miles Everhart

Senior Linux System Administrator, Infrastructure Engineer, Technical Author

Miles Everhart is an experienced Linux system administrator and infrastructure specialist with a strong focus on reliable, secure, and performance-oriented Linux environments.

He has spent years working with Linux servers in production environments, managing system deployments, user access, networking services, and sec...

Linux Administration Server Management Shell Scripting System Monitoring Network Services

Stay Updated

Subscribe to our newsletter for the latest tutorials, tips, and exclusive offers.