A default Webmin installation is a target the moment it goes online. Port 10000 is scanned continuously by botnets, and with no built-in rate limiting or brute-force protection, attackers can attempt thousands of password guesses per hour without restriction. This guide covers the complete security hardening workflow: locking down SSH, configuring Fail2Ban to protect both SSH and Webmin's login page, and using firewall rules to limit who can even reach the admin interface in the first place.
Understanding the Attack Surface
Webmin's default configuration has several security gaps that need addressing before it's production-safe:
- Port 10000 is well-known — every automated scanner knows to check it
- No rate limiting on login attempts — unlimited password guessing by default
- Root login enabled — a successful brute force gives immediate root access
- Self-signed SSL certificate — traffic may be intercepted if the connection is downgraded
- SSH on port 22 — constant brute-force background noise in auth logs
The goal is defense in depth: even if one layer fails, the others prevent access. The layers covered here are: hardened SSH configuration → Fail2Ban intrusion prevention → UFW host firewall → IP allowlisting in Webmin itself.
Step 1: Harden SSH Configuration
SSH is the primary access method for your server — securing it is the foundation of everything else. Edit /etc/ssh/sshd_config:
Port 2222
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
MaxAuthTries 3
LoginGraceTime 30
X11Forwarding no
AllowUsers youradminuser
Key settings explained:
- Port 2222 — Moving SSH off port 22 eliminates the majority of automated brute-force noise. Not a security control on its own, but dramatically reduces log pollution and background attack traffic.
- PermitRootLogin no — Attackers cannot log in directly as root even with the correct password. Access as a non-root user and use
sudo. - PasswordAuthentication no — This alone stops virtually all SSH brute-force attacks. Use SSH keys only. Generate a key pair on your local machine with
ssh-keygen -t ed25519and copy the public key to the server before enabling this setting. - AllowUsers youradminuser — Restricts SSH login to only the named user(s), even if other accounts exist on the system.
Before restarting SSH, open a second terminal window and keep it connected. Test the new configuration in a third window before closing anything:
sshd -t # Test config syntax — fix any errors before restarting
systemctl restart sshd
Update your firewall to allow the new SSH port: ufw allow 2222/tcp (do this before restarting SSH).
Step 2: Install and Configure Fail2Ban
Fail2Ban monitors authentication logs and bans IP addresses that exceed a configurable number of failed login attempts. Install it:
apt install fail2ban # Debian/Ubuntu
yum install fail2ban # CentOS/AlmaLinux
systemctl enable --now fail2ban
Create a local configuration file (never edit jail.conf directly — it gets overwritten on updates):
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
Edit /etc/fail2ban/jail.local and configure the SSH and Webmin jails:
[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600
[webmin-auth]
enabled = true
port = 10000
filter = webmin-auth
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600
Verify the webmin-auth filter exists:
ls /etc/fail2ban/filter.d/webmin-auth.conf
If it doesn't exist, create it:
cat > /etc/fail2ban/filter.d/webmin-auth.conf << 'EOF'
[Definition]
failregex = webmin.*Invalid password for user .* from
webmin.*Login from as .* failed
ignoreregex =
EOF
Restart Fail2Ban and verify it's active:
systemctl restart fail2ban
fail2ban-client status
fail2ban-client status webmin-auth
fail2ban-client status sshd
Step 3: Configure UFW Firewall Rules
A host firewall (UFW on Ubuntu/Debian, firewalld on RHEL/AlmaLinux) is your outermost layer. The strategy is to allow only the ports you need, from the IPs that need them — and deny everything else.
ufw default deny incoming
ufw default allow outgoing
ufw allow 2222/tcp # SSH on new port
ufw allow 80/tcp # HTTP
ufw allow 443/tcp # HTTPS
ufw allow 10000/tcp # Webmin — will restrict further below
ufw enable
For maximum security, restrict Webmin access to specific IP addresses only. If your office or VPN has a static IP:
ufw delete allow 10000/tcp
ufw allow from YOUR.OFFICE.IP to any port 10000
Replace YOUR.OFFICE.IP with your static IP. This means Webmin is completely invisible to anyone scanning from outside your allowed IPs — the most effective protection possible.
If you don't have a static IP, use a VPN instead: connect to your server's VPN, then access Webmin over the VPN's internal IP. Never expose Webmin to the public internet without IP restrictions.
💡 None of these worked? Skip the guesswork.
Get Expert Help →Step 4: Enable IP Allowlisting in Webmin Itself
Webmin has its own built-in access control layer that works independently of the firewall — useful as an additional backstop.
1. Log in to Webmin and go to Webmin → Webmin Configuration → IP Access Control.
2. Select "Only allow from listed addresses" and add your management IP(s) — your office IP, VPN IP, or specific admin workstations.
3. Click Save. Anyone connecting from an unlisted IP will be refused by Webmin before they even see the login page.
Also configure: Webmin → Webmin Configuration → Authentication:
- Set Block hosts with more than N failed logins to 3, block for 600 seconds
- Enable Log logins and logouts to syslog
- Disable Allow login by root user if you've created a separate admin account
Step 5: Change the Default Webmin Port
Moving Webmin off port 10000 eliminates automated scanners that specifically probe for it. This is a minor hardening step but adds measurable noise reduction to your logs.
1. Go to Webmin → Webmin Configuration → Ports and Addresses.
2. Change the "Listen on port" value from 10000 to a non-standard port like 12543 or 19080.
3. Update UFW to allow the new port: ufw allow 12543/tcp and remove the old rule: ufw delete allow 10000/tcp.
4. Update Fail2Ban in /etc/fail2ban/jail.local to use the new port number in the [webmin-auth] section.
Step 6: Verify the Hardening Is Working
Check Fail2Ban is actively catching attempts:
fail2ban-client status webmin-auth
fail2ban-client status sshd
Review banned IPs:
fail2ban-client get webmin-auth banned
Check UFW status and active rules:
ufw status verbose
Test SSH from a new terminal window before closing your existing session — confirm you can still log in with your key on the new port:
ssh -p 2222 youradminuser@yourserver.com
Check auth logs to confirm Fail2Ban is reading them:
tail -50 /var/log/auth.log | grep -E "fail2ban|webmin|sshd"
Maintaining the Security Configuration
Set a monthly calendar reminder to:
- Run
apt upgradeoryum update— keep Webmin, Fail2Ban, and OpenSSH patched - Review
/var/log/auth.logfor unusual patterns (successful logins from unexpected IPs) - Confirm Fail2Ban is running:
fail2ban-client status - Verify UFW rules haven't drifted:
ufw status verbose
If your server hosts multiple domains or services, consider a more comprehensive security monitoring approach: intrusion detection (AIDE or Tripwire for file integrity monitoring), centralized logging (Graylog, ELK stack), and automated vulnerability scanning.
For hosting companies managing security across dozens of Webmin servers, CloudHouse's server hardening service implements and maintains this entire security stack — Fail2Ban, SSH hardening, firewall rules, and ongoing monitoring — so your team can focus on growth instead of fire-fighting breaches.
