Modular, production-ready server hardening script for Debian/Ubuntu systems.
- ✅ Ubuntu: 20.04 LTS, 22.04 LTS, 24.04 LTS
- ✅ Debian: 11 (Bullseye), 12 (Bookworm)
- ✅ AMD64/x86_64: Fully supported (primary platform)
- ✅ ARM64/aarch64: Fully supported (tested on Raspberry Pi 4, AWS Graviton)
⚠️ ARM32/armv7l: Limited support (basic features)
See PLATFORM_COMPATIBILITY.md for detailed compatibility information.
curl -sSL https://raw.githubusercontent.com/crxnit/Linux-Base-Setup-2026/main/install.sh | sudo bashAfter installation, run from anywhere:
sudo harden --dry-run # Preview changes
sudo harden # Run hardening# Clone the repository
git clone https://github.com/crxnit/Linux-Base-Setup-2026.git
cd Linux-Base-Setup-2026
# Preview changes (dry run)
sudo ./harden.sh --dry-run
# Run with default configuration
sudo ./harden.sh
# Run with custom configuration
cp config/custom.conf.template config/custom.conf
nano config/custom.conf
sudo ./harden.sh --config config/custom.conf- Multi-Architecture Support: Full support for AMD64, ARM64, and ARM32
- Platform Detection: Automatic distribution and architecture detection
- Essential Tools Auto-Install: Automatically installs sudo, curl, vim on minimal systems
- Improved Dry-Run Mode: No files created during preview, works on fresh systems
- Symlink Support: Works correctly when installed via
/usr/local/bin/harden
- Modular Architecture: Clean separation of concerns with dedicated modules
- Configuration Files: Manage settings without editing scripts
- Dry-Run Mode: Preview all changes before applying
- Better Error Handling: Comprehensive error checking and rollback capability
- Enhanced Logging: Detailed, color-coded logging with timestamps
- Progress Indicators: Visual feedback for long-running operations
- Non-Interactive Mode: Full automation support for provisioning
- Modern Security: Updated SSH ciphers, CrowdSec, AppArmor, and more
- Comprehensive Testing: Pre-flight checks and validation
-
✅ SSH Hardening
- Custom port configuration
- Disable root login and password authentication
- Modern key exchange algorithms and ciphers
- Optional two-factor authentication (2FA)
- Connection rate limiting
-
✅ Firewall Configuration
- UFW or firewalld support
- Automatic SSH port allowance
- Customizable port rules
- Rate limiting for services
-
✅ Kernel Hardening (sysctl)
- IP spoofing protection
- SYN flood protection
- ICMP broadcast/redirect protection
- Kernel information restriction
- Memory randomization (ASLR)
-
✅ User Management
- Automated admin user creation
- SSH key deployment
- Password policy enforcement
- Umask configuration
- 🛡️ CrowdSec: Modern, collaborative intrusion prevention with real-time threat intelligence
- 📊 Auditd: Comprehensive file integrity and system call auditing
- 🔍 RKHunter: Rootkit detection
- 🔐 Lynis: Security auditing (optional)
- 🗃️ AIDE: Advanced intrusion detection (optional)
- ⏰ Time Synchronization: Chrony or systemd-timesyncd
- 🔄 Unattended Upgrades: Automatic security updates
- 🏷️ Hostname Management: Auto-generated or custom hostnames
- 🚫 Protocol Filtering: Disable uncommon network protocols
- 🔒 AppArmor: Mandatory access control (optional)
linux-base-setup-v2/
├── harden.sh # Main orchestration script
├── config/
│ ├── default.conf # Default configuration
│ └── custom.conf.template # Template for customization
├── modules/
│ ├── utils.sh # Utility functions
│ ├── user.sh # User management
│ ├── ssh.sh # SSH hardening
│ ├── firewall.sh # Firewall configuration
│ ├── hardening.sh # Kernel hardening
│ ├── security_tools.sh # Security tool installation
│ └── updates.sh # System updates & NTP
├── logs/ # Execution logs
└── README.md
- Create custom configuration:
cp config/custom.conf.template config/custom.conf
nano config/custom.conf- Modify settings:
# Example custom.conf
ADMIN_USERNAME="johndoe"
SSH_PORT=2222
FIREWALL_TYPE="ufw"
UFW_ALLOWED_PORTS="22/tcp,80/tcp,443/tcp,3000/tcp"
TIMEZONE="America/New_York"- Run with custom config:
sudo ./harden.sh --config config/custom.conf| Setting | Default | Description |
|---|---|---|
SSH_PORT |
2222 | Custom SSH port |
SSH_PASSWORD_AUTH |
no | Allow password authentication |
FIREWALL_TYPE |
ufw | Firewall type (ufw/firewalld/none) |
INSTALL_CROWDSEC |
true | Install and configure CrowdSec |
INSTALL_AUDITD |
true | Install and configure Auditd |
ENABLE_UNATTENDED_UPGRADES |
true | Enable automatic security updates |
NTP_SERVICE |
chrony | NTP service (chrony/systemd-timesyncd) |
See config/default.conf for complete list of options.
sudo ./harden.shScript will prompt for:
- Admin username
- Passwords
- SSH key deployment
- Hostname
- Timezone
- Optional features
# Configure in custom.conf
INTERACTIVE=false
ADMIN_USERNAME="admin"
HOSTNAME="web-server-01"
TIMEZONE="UTC"
# Run
sudo ./harden.sh --non-interactivesudo ./harden.sh --dry-runShows what would be changed without applying modifications.
# Skip updates and firewall
sudo ./harden.sh --skip-updates --skip-firewall
# Skip security tools
sudo ./harden.sh --skip-crowdsec --skip-auditd# Use specific config file
sudo ./harden.sh --config /path/to/myconfig.conf
# Combine with other options
sudo ./harden.sh --config config/custom.conf --dry-run# config/custom.conf
CONFIGURE_SSH=true
SSH_PORT=2222
CONFIGURE_FIREWALL=true
INSTALL_CROWDSEC=true
CONFIGURE_SYSCTL=true# Add to basic configuration
INSTALL_AUDITD=true
INSTALL_RKHUNTER=true
CONFIGURE_PASSWORD_POLICY=true
PASSWORD_MIN_LENGTH=12
DISABLE_UNCOMMON_PROTOCOLS=true# Add to medium configuration
SSH_PASSWORD_AUTH="no"
CONFIGURE_APPARMOR=true
DISABLE_USB_STORAGE=true
PASSWORD_MIN_LENGTH=16
CROWDSEC_ENROLL=true # Enroll in CrowdSec Console for shared threat intelligence
CROWDSEC_ENROLL_KEY="your-key" # Get from app.crowdsec.net
# Enable 2FA during interactive setupUFW_ALLOWED_PORTS="22/tcp,80/tcp,443/tcp"
FIREWALL_TYPE="ufw"
INSTALL_CROWDSEC=true
ENABLE_UNATTENDED_UPGRADES=trueUFW_ALLOWED_PORTS="22/tcp,3306/tcp,5432/tcp"
FIREWALL_TYPE="ufw"
CONFIGURE_APPARMOR=true
INSTALL_AUDITD=trueUFW_ALLOWED_PORTS="22/tcp,80/tcp,443/tcp,3000/tcp,8000/tcp,8080/tcp"
INSTALL_DOCKER=true
CONFIGURE_SYSCTL=true- Backup Access: Ensure you have alternative access to the server
- Test Environment: Test on a non-production server first
- Firewall Rules: Verify required ports are in allowed list
- SSH Keys: Have your SSH public key ready
- Documentation: Review log files after completion
- DO NOT CLOSE your current SSH session
- Test new SSH connection from separate terminal before disconnecting
- Verify firewall allows SSH on new port
- Confirm SSH key authentication works
# After script completion, from ANOTHER terminal:
ssh -p <NEW_PORT> <ADMIN_USER>@<SERVER_IP>
# Verify you can:
1. Connect with SSH key
2. Escalate to sudo
3. Access required services
# Only then close original session# Main execution log
/var/log/hardening/hardening-YYYYMMDD_HHMMSS.log
# Backup directory
/var/backups/hardening-YYYYMMDD_HHMMSS/
# Completion report
/var/backups/hardening-YYYYMMDD_HHMMSS/completion_report.txt# View CrowdSec status
sudo cscli metrics
sudo cscli decisions list
sudo cscli alerts list
# View auditd logs
sudo ausearch -k identity
sudo ausearch -k sshd_config
# View firewall status
sudo ufw status verbose
# or
sudo firewall-cmd --list-all
# View SSH connections
sudo journalctl -u sshd -n 50
# Run security audit
sudo lynis audit system# Test SSH config
sudo sshd -t
# Check SSH service
sudo systemctl status sshd
sudo journalctl -u sshd -n 50
# Verify firewall
sudo ufw status
sudo ufw allow <PORT>/tcp# If locked out, access via console/KVM and:
sudo ufw disable
sudo ufw allow <SSH_PORT>/tcp
sudo ufw enable# Find backup
ls -la /var/backups/hardening-*/
# Restore SSH config
sudo cp /var/backups/hardening-*/sshd_config /etc/ssh/sshd_config
sudo systemctl restart sshd| Code | Description |
|---|---|
| 0 | Success |
| 1 | General error |
| 2 | Invalid arguments |
| 3 | Not running as root |
| 4 | Unsupported distribution |
| 5 | Pre-flight check failed |
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly
- Submit a pull request
MIT License - see LICENSE file for details
- Original script: linux-base-setup v1.0
- Modernized and modularized: v2.0
- Security best practices from CIS Benchmarks and NIST guidelines
- Issues: https://github.com/crxnit/Linux-Base-Setup-2026/issues
- Discussions: https://github.com/crxnit/Linux-Base-Setup-2026/discussions
- Documentation: https://github.com/crxnit/Linux-Base-Setup-2026/wiki
- 2FA Grace Period: 15-minute grace period for SSH 2FA
- No TOTP prompt if successfully authenticated within last 15 minutes
- Uses
pam_timestamp.soto track recent authentications - Reduces friction for frequent SSH sessions
- Fixed SSH 2FA: Public key + TOTP without password prompt
- Comments out
@include common-authin PAM to disable password - Authentication flow: public key first, then TOTP code only
- Added
KbdInteractiveAuthentication yesfor newer OpenSSH versions
- Comments out
- Improved Post-Install Instructions: Clear guidance for activating sudo access
- Shows
exec su -l $USERcommand to activate sudo without logout - Simplified Quick Start instructions with sudo prefix
- Reordered steps for better workflow
- Shows
- Sudoers Configuration: Automatically adds users to sudo group
- If run via sudo, adds the invoking user to sudo group
- If run as root, adds all regular users (UID >= 1000) to sudo group
- Prevents "user is not in the sudoers file" errors
- Enhanced Install Script: Full automation for fresh minimal installations
- Runs apt update && apt upgrade before installation
- Automatically installs essential tools (sudo, curl, git, vim, gnupg, ca-certificates)
- Creates sudo group if missing
- Clear progress indicators during installation
- CrowdSec Integration: Replaced Fail2Ban with CrowdSec for modern intrusion prevention
- Collaborative threat intelligence from global community
- Automatic IP reputation checking
- Support for iptables and nftables bouncers
- Optional CrowdSec Console enrollment
- Updated configuration options for CrowdSec
- Updated documentation and examples
- Script now continues on component failures instead of exiting
- Added failure tracking and summary report at end
- Fixed Fail2Ban "no log file found" error on fresh installs
- Fixed root check to run before any directory operations
- Fixed Fail2Ban failing to start on Debian 12/Ubuntu 22.04+
- Made RKHunter database update non-fatal
- Moved root check to run before banner display
- Fixed backup warnings for files that don't exist yet
- Fixed fail2ban-client status causing script exit
- Removed dist-upgrade prompt (now config-driven)
- Added one-line install instructions to README
- Fixed dry-run mode exiting on missing directories
- Fixed repository URLs in install.sh and documentation
- Improved dry-run handling for essential tools installation
- Fixed symlink path resolution for installed command
- Works correctly when called via
/usr/local/bin/harden
- Added essential tools auto-installation (sudo, curl, vim)
- Works on minimal server installations
- Multi-architecture support (AMD64, ARM64, ARM32)
- Distribution-specific configurations
- Enhanced platform detection and validation
- Complete modular rewrite
- Configuration file support
- Dry-run mode
- Enhanced error handling
- Modern security standards
- Comprehensive logging
- Initial release
- Basic hardening features
- Single-file script
Remember: Security is a process, not a product. Regular updates, monitoring, and audits are essential.