Operations 30 min read

One-Click Linux Server Initialization: From Bare Metal to Production-Ready

This guide shares a comprehensive one‑click script that hardens SSH, configures firewalls, tunes kernel parameters, manages logs, disables unused services, installs essential tools and Docker, and provides a verification checklist to turn a fresh Linux server into a production‑grade system.

AI Agent Super App
AI Agent Super App
AI Agent Super App
One-Click Linux Server Initialization: From Bare Metal to Production-Ready

1. Security Hardening: Stop the Server from Running Bare

The author recounts a server that was compromised within 48 hours due to default SSH settings, then presents a step‑by‑step hardening process.

1.1 SSH Hardening

Backup the original /etc/ssh/sshd_config and apply the following changes:

# Backup original config
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak

# Change key parameters
sed -i 's/^#\?Port 22/Port 2222/' /etc/ssh/sshd_config
sed -i 's/^#\?PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/^#\?PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i 's/^#\?X11Forwarding yes/X11Forwarding no/' /etc/ssh/sshd_config
sed -i 's/^#\?MaxAuthTries 6/MaxAuthTries 3/' /etc/ssh/sshd_config
echo 'PermitEmptyPasswords no' >> /etc/ssh/sshd_config
systemctl restart sshd

Key points: change port to 2222, disable root login, disable password authentication, limit auth attempts, and add PermitEmptyPasswords no.

1.2 Configure Key‑Based Login

# Generate key pair on local machine
ssh-keygen -t ed25519 -C "[email protected]"

# Copy public key to server (using the new port)
ssh-copy-id -p 2222 user@server_ip

# Test login before disabling passwords
ssh -p 2222 user@server_ip

Uses ed25519 for better performance and security.

1.3 Firewall Configuration

Uses firewalld on CentOS/RHEL and ufw on Ubuntu/Debian:

# CentOS/RHEL – firewalld
systemctl enable firewalld
systemctl start firewalld
firewall-cmd --permanent --remove-service=ssh
firewall-cmd --permanent --add-port=2222/tcp
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.0.0/8" accept'
firewall-cmd --reload

# Ubuntu/Debian – ufw
apt install -y ufw
ufw default deny incoming
ufw default allow outgoing
ufw allow 2222/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw allow from 10.0.0.0/8
ufw --force enable

Allows internal network traffic while exposing only required ports.

1.4 User & Permission Management

# Create admin user
useradd -m -s /bin/bash admin
passwd admin

# Add to sudo group (CentOS/RHEL)
usermod -aG wheel admin
# or Ubuntu/Debian
usermod -aG sudo admin

# Optional password‑less sudo for key‑login only
echo 'admin ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/admin
chmod 440 /etc/sudoers.d/admin

# Lock unnecessary system accounts
for user in games lp news uucp proxy list irc gnats; do
    usermod -L $user 2>/dev/null
done

Enforces strong password policy via pam_pwquality with settings such as minlen=12, minclass=3, maxrepeat=3, difok=5, and password expiry of 90 days.

1.5 Install and Configure fail2ban

# Install
yum install -y epel-release fail2ban   # CentOS/RHEL
apt install -y fail2ban               # Ubuntu/Debian

# jail.local
cat > /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
banaction = firewallcmd-ipset

[sshd]
enabled = true
port = 2222
maxretry = 3
bantime = 86400
findtime = 300
EOF

systemctl enable fail2ban
systemctl start fail2ban

Blocks IPs after three failed attempts within ten minutes for 24 hours.

1.6 System Security Baseline

# Disable Ctrl+Alt+Del reboot
systemctl mask ctrl-alt-del.target

# Restrict su to wheel group
sed -i 's/^#?auth.*pam_wheel.so/\tauth\trequired\tpam_wheel.so use_uid/' /etc/pam.d/su

# Set umask
echo 'umask 027' >> /etc/profile

# Make critical files immutable
chattr +i /etc/passwd /etc/shadow /etc/group /etc/gshadow

# Harden history logging
echo 'export HISTSIZE=10000' >> /etc/profile
echo 'export HISTFILESIZE=20000' >> /etc/profile
echo 'export HISTTIMEFORMAT="%F %T "' >> /etc/profile
echo 'export PROMPT_COMMAND="history -a"' >> /etc/profile

# Disable unused filesystems
for fs in cramfs freevxfs jffs2 hfs hfsplus squashfs udf; do
    echo "install $fs /bin/true" >> /etc/modprobe.d/disablefs.conf
done

Notes the need to unlock immutable files with chattr -i before editing.

2. Kernel Parameter Tuning: Boost Performance and Stability

All parameters reside in /etc/sysctl.conf and are applied with sysctl -p. The author provides a curated set:

cat >> /etc/sysctl.conf << 'EOF'
# Network
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 1024
net.core.somaxconn = 2048
net.ipv4.tcp_max_tw_buckets = 6000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_fastopen = 3
net.ipv4.ip_local_port_range = 1024 65535

# Memory
vm.swappiness = 10
vm.overcommit_memory = 1
vm.overcommit_ratio = 90
vm.panic_on_oom = 0

# Filesystem
fs.file-max = 1048576
fs.inotify.max_user_watches = 524288

# Misc
kernel.core_pattern = /var/crash/core-%e-%p-%t
kernel.dmesg_restrict = 1
kernel.yama.ptrace_scope = 1
EOF
sysctl -p

Key explanations: net.core.somaxconn=2048 raises the listen backlog; vm.swappiness=10 keeps swap usage low; vm.overcommit_memory=1 allows aggressive memory allocation; net.ipv4.tcp_tw_reuse=1 reuses TIME_WAIT sockets.

File descriptor and process limits are raised in /etc/security/limits.conf to 65535 for both nofile and nproc. The author cites an e‑commerce case where raising nofile eliminated “too many open files” errors at 20 k QPS.

3. System Optimization and Cleanup

3.1 Log Management

# Journald limit
mkdir -p /etc/systemd/journald.conf.d
cat > /etc/systemd/journald.conf.d/limit.conf << 'EOF'
[Journal]
SystemMaxUse=500M
SystemMaxFileSize=100M
MaxRetentionSec=30day
ForwardToSyslog=no
EOF
systemctl restart systemd-journald

# Logrotate for traditional logs
cat > /etc/logrotate.d/custom << 'EOF'
/var/log/messages
/var/log/secure
/var/log/cron {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    create 0640 root root
    sharedscripts
    postrotate
        /bin/kill -HUP $(cat /var/run/syslogd.pid 2>/dev/null) 2>/dev/null || true
    endscript
}
EOF

Retains up to 500 MB of system logs, each file ≤ 100 MB, and keeps 7 days of rotated logs.

3.2 Disable Unused Services

# Stop and disable common unnecessary services
for svc in avahi-daemon cups bluetooth postfix ModemManager accounts-daemon; do
    systemctl stop $svc 2>/dev/null
    systemctl disable $svc 2>/dev/null
done

# Switch to multi‑user target (no GUI)
systemctl set-default multi-user.target

# Optional: disable IPv6 if not used
echo 'net.ipv6.conf.all.disable_ipv6 = 1' >> /etc/sysctl.conf
echo 'net.ipv6.conf.default.disable_ipv6 = 1' >> /etc/sysctl.conf
sysctl -p

3.3 NTP Time Synchronization

# Install chrony (fallback to ntpdate)
yum install -y chrony 2>/dev/null || apt install -y chrony
systemctl enable chronyd
systemctl start chronyd

# Quick sync alternative
ntpdate ntp.aliyun.com

3.4 System Updates

# CentOS/RHEL
yum update -y --exclude=kernel*
yum clean all

# Ubuntu/Debian
apt update && apt upgrade -y
apt autoremove -y
apt clean

The kernel is excluded from the first update to avoid unexpected reboots; it can be upgraded later.

4. Automated Installation of Common Tools

Installs a standard toolbox for troubleshooting and monitoring.

# CentOS/RHEL
yum install -y vim wget curl net-tools lsof tree htop iotop iftop nmon ncdu bash-completion lrzsz bind-utils tcpdump strace sysstat rsync unzip bzip2 xz psmisc fail2ban

# Ubuntu/Debian
apt install -y vim wget curl net-tools lsof tree htop iotop iftop nmon ncdu bash-completion lrzsz dnsutils tcpdump strace sysstat rsync unzip bzip2 xz psmisc fail2ban

4.1 Vim Configuration

cat > /etc/vimrc.local << 'EOF'
set number
set tabstop=4
set shiftwidth=4
set expandtab
set autoindent
set smartindent
set ruler
set showmode
set showcmd
set hlsearch
set incsearch
set ignorecase
set smartcase
syntax on
EOF

echo 'source /etc/vimrc.local' >> /etc/vimrc

4.2 Bash Enhancements

cat > /etc/profile.d/custom.sh << 'EOF'
alias ls='ls --color=auto'
alias ll='ls -lh'
alias la='ls -lha'
alias grep='grep --color=auto'
alias df='df -h'
alias du='du -h'
alias free='free -h'
alias netstat='netstat -tlnp'
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
EOF

4.3 Optional Docker Installation

# One‑click Docker install
curl -fsSL https://get.docker.com | sh -s docker --mirror Aliyun

# Daemon config for mirrors and log limits
cat > /etc/docker/daemon.json << 'EOF'
{
  "registry-mirrors": ["https://mirror.baidubce.com","https://docker.1ms.run"],
  "log-driver": "json-file",
  "log-opts": {"max-size": "50m", "max-file": "3"},
  "storage-driver": "overlay2",
  "live-restore": true
}
EOF
systemctl enable docker
systemctl start docker
usermod -aG docker admin

5. Full One‑Click Initialization Script

#!/bin/bash
# ============================================
# Linux server initialization script v2.0
# Supports: CentOS/RHEL 7+, Ubuntu 20.04+, Debian 11+
# Usage: bash init_server.sh
# ============================================
set -e

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

info() { echo -e "${GREEN}[+] $1${NC}"; }
warn() { echo -e "${YELLOW}[!] $1${NC}"; }
error() { echo -e "${RED}[-] $1${NC}"; exit 1; }

# Detect OS
if [ -f /etc/redhat-release ]; then
    OS="centos"
elif [ -f /etc/debian_version ]; then
    OS="debian"
else
    error "Unsupported OS"
fi
info "Detected OS: $OS"

# Ensure root
if [ "$(id -u)" -ne 0 ]; then
    error "Run as root"
fi

# ---- 1. SSH hardening ----
info "Hardening SSH..."
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sed -i 's/^#\?Port 22/Port 2222/' /etc/ssh/sshd_config
sed -i 's/^#\?PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/^#\?PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i 's/^#\?X11Forwarding yes/X11Forwarding no/' /etc/ssh/sshd_config
sed -i 's/^#\?MaxAuthTries 6/MaxAuthTries 3/' /etc/ssh/sshd_config
echo 'PermitEmptyPasswords no' >> /etc/ssh/sshd_config

# ---- 2. Create admin user ----
info "Creating admin user..."
if ! id admin &>/dev/null; then
    useradd -m -s /bin/bash admin
    echo "Set password for admin:"
    passwd admin
    if [ "$OS" = "centos" ]; then
        usermod -aG wheel admin
    else
        usermod -aG sudo admin
    fi
    echo 'admin ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/admin
    chmod 440 /etc/sudoers.d/admin
fi

# ---- 3. Firewall ----
info "Configuring firewall..."
if [ "$OS" = "centos" ]; then
    systemctl enable firewalld
    systemctl start firewalld
    firewall-cmd --permanent --remove-service=ssh
    firewall-cmd --permanent --add-port=2222/tcp
    firewall-cmd --permanent --add-service=http
    firewall-cmd --permanent --add-service=https
    firewall-cmd --reload
else
    apt install -y ufw
    ufw default deny incoming
    ufw allow 2222/tcp
    ufw allow 80/tcp
    ufw allow 443/tcp
    ufw --force enable
fi

# ---- 4. Kernel tuning ----
info "Optimizing kernel parameters..."
cat >> /etc/sysctl.conf << 'SYSCTL'
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 1024
net.core.somaxconn = 2048
net.ipv4.tcp_max_tw_buckets = 6000
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_fastopen = 3
net.ipv4.ip_local_port_range = 1024 65535
vm.swappiness = 10
vm.overcommit_memory = 1
fs.file-max = 1048576
kernel.dmesg_restrict = 1
kernel.yama.ptrace_scope = 1
SYSCTL
sysctl -p

# File descriptor limits
cat >> /etc/security/limits.conf << 'LIMITS'
*    soft    nofile    65535
*    hard    nofile    65535
*    soft    nproc     65535
*    hard    nproc     65535
root soft    nofile    65535
root hard    nofile    65535
LIMITS

# ---- 5. Log management ----
info "Setting up log management..."
mkdir -p /etc/systemd/journald.conf.d
cat > /etc/systemd/journald.conf.d/limit.conf << 'JOURNAL'
[Journal]
SystemMaxUse=500M
SystemMaxFileSize=100M
MaxRetentionSec=30day
ForwardToSyslog=no
JOURNAL
systemctl restart systemd-journald

# ---- 6. Time sync ----
info "Configuring time sync..."
if [ "$OS" = "centos" ]; then
    yum install -y chrony
    systemctl enable chronyd
    systemctl start chronyd
else
    apt install -y chrony
    systemctl enable chrony
    systemctl start chrony
fi

# ---- 7. Install common tools ----
info "Installing common tools..."
if [ "$OS" = "centos" ]; then
    yum install -y epel-release
    yum install -y vim wget curl net-tools lsof tree htop iotop iftop nmon ncdu bash-completion lrzsz bind-utils tcpdump strace sysstat rsync unzip bzip2 xz psmisc fail2ban
else
    apt install -y vim wget curl net-tools lsof tree htop iotop iftop nmon ncdu bash-completion lrzsz dnsutils tcpdump strace sysstat rsync unzip bzip2 xz psmisc fail2ban
fi

# ---- 8. Disable unused services ----
info "Disabling unused services..."
for svc in avahi-daemon cups bluetooth; do
    systemctl stop $svc 2>/dev/null
    systemctl disable $svc 2>/dev/null
done
systemctl set-default multi-user.target

# ---- 9. Vim config ----
info "Configuring Vim..."
cat > /etc/vimrc.local << 'VIM'
set number
set tabstop=4
set shiftwidth=4
set expandtab
set autoindent
set hlsearch
set incsearch
syntax on
VIM
grep -q "vimrc.local" /etc/vimrc 2>/dev/null || echo 'source /etc/vimrc.local' >> /etc/vimrc

# ---- 10. System update ----
info "Updating system..."
if [ "$OS" = "centos" ]; then
    yum update -y --exclude=kernel*
    yum clean all
else
    apt update && apt upgrade -y
    apt autoremove -y
    apt clean
fi

info "=========================================="
info "Server initialization complete!"
info "Next steps:"
info "1. Test key login: ssh -p 2222 admin@IP"
info "2. After confirming login, reboot: reboot"
info "3. Verify services after reboot"
info "=========================================="

6. Verification Checklist

After the script finishes, run the following checks:

SSH verification : log in with the new key on port 2222 before closing the root session.

Firewall verification : firewall-cmd --list-all or ufw status to confirm rules.

Kernel parameters : sysctl -a | grep somaxconn to ensure values are active.

fail2ban : fail2ban-client status sshd to see banned IPs.

Time sync : chronyc tracking for NTP status.

Service list : systemctl list-units --type=service --state=running.

Disk usage : df -h to ensure no partition is full.

Reboot test : reboot and verify that sysctl and limits persist.

Following this checklist guarantees that the server meets production standards.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

automationLinuxSecuritysysadminserver hardeningkernel tuninginit script
AI Agent Super App
Written by

AI Agent Super App

AI agent applications, installation, large-model testing, computer fundamentals, IT operations and maintenance exchange, network technology exchange, Linux learning

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.