How to Secure Webmin
Harden Webmin against attack: restrict access by IP, enforce HTTPS with valid certs, set up TOTP two-factor auth, integrate Fail2ban, and lock down modules.
Before you start
- ▸Webmin 2.x installed and accessible on the target server
- ▸Root or sudo access to the server via SSH
- ▸A registered FQDN pointing to the server (required for Let's Encrypt)
- ▸A TOTP authenticator app installed on your mobile device
Webmin is a powerful web-based administration interface that exposes root-level control over your server. Out of the box it is functional but not hardened — default port, broad network access, and no multi-factor authentication. This guide walks through every practical layer of defense: network restriction, HTTPS enforcement, strong authentication, two-factor auth (TOTP), Fail2ban integration, and module-level lockdown.
Prerequisites and Assumptions
Webmin is already installed and reachable. These steps assume you are running Webmin 2.x and have root or sudo access to the underlying system. All firewall examples show both ufw (Debian/Ubuntu) and firewalld (Fedora/RHEL/Rocky) equivalents.
1. Restrict Access by IP at the Firewall
Webmin listens on TCP port 10000 by default. The first line of defense is making that port unreachable except from trusted addresses. Do this at the firewall before touching Webmin's own settings.
ufw (Debian/Ubuntu/Mint)
# Replace 203.0.113.10 with your admin IP or CIDR range
sudo ufw deny 10000
sudo ufw allow from 203.0.113.10 to any port 10000 proto tcp
sudo ufw reload
firewalld (Fedora/RHEL/Rocky)
# Create a rich rule; repeat for additional IPs
sudo firewall-cmd --permanent --add-rich-rule=\
'rule family=ipv4 source address=203.0.113.10/32 port port=10000 protocol=tcp accept'
sudo firewall-cmd --permanent --remove-service=webmin 2>/dev/null || true
sudo firewall-cmd --reload
nftables (Arch / any distro using raw nftables)
# Add to your existing inet filter input chain
sudo nft add rule inet filter input \
ip saddr 203.0.113.10 tcp dport 10000 accept
sudo nft add rule inet filter input \
tcp dport 10000 drop
If you connect over a VPN, allow only the VPN subnet and block public access entirely — that alone eliminates the majority of attack surface.
2. Enforce HTTPS with a Valid Certificate
Webmin ships with a self-signed certificate. Replace it with a real one or at minimum verify TLS is active and using modern ciphers.
Confirm SSL is enabled
In the Webmin UI: Webmin → Webmin Configuration → SSL Encryption. Ensure Enable SSL is set to Yes. Alternatively, check the config directly:
grep -E '^ssl=' /etc/webmin/miniserv.conf
# Expected output: ssl=1
Install a Let's Encrypt certificate via Webmin's built-in tool
Go to Webmin → Webmin Configuration → SSL Encryption → Let's Encrypt. Enter your FQDN (e.g., admin.example.com) and click Request Certificate. Webmin handles renewal automatically via a systemd timer it installs itself.
Set minimum TLS version and strong ciphers
Edit /etc/webmin/miniserv.conf and ensure these lines are present (add or update them):
sudo sed -i '/^ssl_version=/d; /^ssl_cipher_list=/d' /etc/webmin/miniserv.conf
echo 'ssl_version=3' | sudo tee -a /etc/webmin/miniserv.conf
echo 'ssl_cipher_list=HIGH:!aNULL:!MD5:!RC4:!DH' | sudo tee -a /etc/webmin/miniserv.conf
sudo systemctl restart webmin
ssl_version=3 tells Webmin's miniserv to use TLSv1.2 as the minimum. Versions of Webmin 2.x compiled against OpenSSL 1.1+ will negotiate TLS 1.3 automatically.
3. Enforce Strong Authentication
Disable the root account login; use a dedicated admin user
Creating a Webmin-only admin avoids exposing the system root password. In the UI: Webmin → Webmin Users → Create a new Webmin user. Grant the new user only the modules it needs, then:
# Disable root login to Webmin (keep Unix root separate)
grep -q '^not_allow_root=' /etc/webmin/miniserv.conf && \
sudo sed -i 's/^not_allow_root=.*/not_allow_root=1/' /etc/webmin/miniserv.conf || \
echo 'not_allow_root=1' | sudo tee -a /etc/webmin/miniserv.conf
sudo systemctl restart webmin
Set a password policy
Under Webmin → Webmin Configuration → Authentication, set Minimum password length to at least 16 and enable Block logins after 5 failures. Also enable Session authentication to invalidate idle sessions after a timeout (15–30 minutes is reasonable).
4. Enable Two-Factor Authentication (TOTP)
Webmin has native TOTP support via the Two-Factor Authentication module — no external package needed on Webmin 2.x.
- Navigate to Webmin → Webmin Configuration → Two-Factor Authentication.
- Select Google Authenticator (TOTP) as the provider.
- Click Save, then click Enroll for Two-Factor Authentication for your admin user.
- Scan the QR code with your authenticator app (Aegis, Google Authenticator, etc.).
- Enter the 6-digit code to confirm enrollment.
After enrollment, every login requires the one-time code. Store your backup codes somewhere safe and offline. If the server is headless and you lose your TOTP device, recovery requires editing /etc/webmin/<username>.totp directly on the host.
5. Configure Fail2ban for Webmin
Fail2ban can ban IPs that repeatedly fail Webmin authentication by watching the Webmin auth log.
Install Fail2ban
# Debian/Ubuntu
sudo apt install fail2ban -y
# Fedora/RHEL/Rocky
sudo dnf install fail2ban -y
# Arch
sudo pacman -S fail2ban
Create the Webmin filter
sudo tee /etc/fail2ban/filter.d/webmin.conf <<'EOF'
[Definition]
failregex = ^%(__prefix_line)sInvalid password for user .+ from \s*$
^%(__prefix_line)sFailed login as .+ from \s*$
ignoreregex =
EOF
Create the jail
sudo tee /etc/fail2ban/jail.d/webmin.conf <<'EOF'
[webmin]
enabled = true
filter = webmin
logpath = /var/log/webmin/miniserv.log
maxretry = 5
bantime = 1h
findtime = 10m
EOF
sudo systemctl enable --now fail2ban
sudo systemctl restart fail2ban
Verify the jail is active
sudo fail2ban-client status webmin
# Output will show Status, currently failed count, and banned IPs
6. Lock Down Webmin Modules
By default a Webmin admin user can access every module. Restrict access to only what each operator actually needs.
Per-user module access
Go to Webmin → Webmin Users, click your admin user, then click Available Webmin modules. Deselect everything not required. For a typical application admin, that might mean granting only Apache, MySQL, and System Logs — not Disk and Network Filesystems, BIND DNS, or Software Packages.
IP-based access control per module
Under Webmin → Webmin Configuration → IP Access Control, you can restrict which IPs may access Webmin at all. This is a second layer on top of your firewall rule and useful when multiple people share an admin account (not recommended, but common).
Disable unused modules globally
# List all enabled modules
ls /etc/webmin/
Each subdirectory corresponds to a module. To disable one, add a nomodule=1 line to its config file or delete the module's directory entry from /etc/webmin/webmin.acl. The cleaner way is through the UI: Webmin → Webmin Configuration → Webmin Modules → Uninstall.
7. Change the Default Port
Security through obscurity is not a primary defense, but changing port 10000 reduces automated scan noise significantly.
sudo sed -i 's/^port=10000/port=10043/' /etc/webmin/miniserv.conf
sudo systemctl restart webmin
Update your firewall rules to allow the new port and deny 10000. If you use SELinux (Fedora/RHEL/Rocky), you must also label the new port:
sudo semanage port -a -t http_port_t -p tcp 10043
Verification Checklist
- From an untrusted IP,
curl -k https://<your-server>:10000should time out or be refused. - From your trusted IP, the Webmin login page loads over HTTPS with a valid certificate (check with
openssl s_client -connect <host>:<port>). - Logging in with a wrong password five times triggers a Fail2ban ban — confirm with
sudo fail2ban-client status webmin. - TOTP prompt appears after correct username/password entry.
- The limited admin user cannot see modules they were not granted.
Troubleshooting
- Webmin won't start after SSL changes
- Check
sudo journalctl -u webmin -n 50. A badssl_cipher_listvalue causes miniserv to abort. Remove the line and restart to confirm, then correct the cipher string. - Fail2ban not banning — log path wrong
- Webmin's log location varies: check
/var/log/webmin/miniserv.logand/var/webmin/miniserv.log. Use whichever exists in the jail config. - Locked out after enabling TOTP
- SSH into the server and delete or rename
/etc/webmin/<username>.totp. Webmin will skip TOTP for that user on next login. - SELinux blocking Webmin on the new port
- Run
sudo ausearch -m avc -ts recent | audit2whyto identify the denial, then usesemanage portas shown above.
Frequently asked questions
- Can I put Webmin behind an Nginx reverse proxy instead of exposing miniserv directly?
- Yes, and it is a good approach. Proxy HTTPS through Nginx on port 443, set ssl=0 in miniserv.conf so miniserv handles plain HTTP on localhost only, and bind miniserv to 127.0.0.1 by adding 'bind=127.0.0.1' to miniserv.conf. Nginx handles TLS termination and you can add rate-limiting at the proxy layer.
- Does enabling Fail2ban for Webmin interfere with the login lockout built into Webmin itself?
- No, they operate independently. Webmin's built-in lockout works at the application layer per user, while Fail2ban bans at the IP level using the firewall backend. Running both gives you defence in depth.
- Is it safe to use Webmin on a public-facing server at all?
- With the hardening in this guide applied — IP restriction, HTTPS, TOTP, and Fail2ban — the risk is significantly reduced. The safest posture is still to allow access only from a VPN or bastion host so no login interface is reachable from the public internet.
- How do I recover if Fail2ban bans my own IP?
- SSH in on port 22 (which Fail2ban is not monitoring here) and run: sudo fail2ban-client set webmin unbanip YOUR_IP. To prevent self-bans, add your admin IP to the ignoreip line in /etc/fail2ban/jail.local.
- Does Webmin's TOTP work with hardware keys like YubiKey?
- Webmin's native two-factor module supports TOTP and Authy but not FIDO2/WebAuthn natively in version 2.x. For hardware key support you would need to front Webmin with an SSO proxy (e.g., Authelia) that supports WebAuthn, or use the PAM module path if Webmin is configured to authenticate via PAM.
Related guides
Manage Secrets with Ansible Vault
Encrypt Ansible secrets with AES-256 using ansible-vault: encrypt files and inline vars, automate with password files, and isolate group-level secrets with vault IDs.
AppArmor Explained
Learn how AppArmor profiles work, how to switch between enforce and complain mode, create new profiles, and diagnose access denials on Ubuntu, Debian, and Arch.
Apply CIS Benchmarks with OpenSCAP
Use OpenSCAP and scap-security-guide to evaluate, report on, and remediate Linux systems against CIS Benchmarks — covering install, eval, and automation.
How to Audit a Linux System with auditd
Set up auditd on Linux to track file access, syscalls, and privilege use. Covers persistent rules, file watches, ausearch, and aureport across major distros.