How To

openSUSE Leap 16 Initial Server Setup and Hardening

A fresh openSUSE Leap 16 server is reachable over SSH the moment it boots, and straight out of the installer it still accepts password logins and lets root authenticate with a key. Before you put it on a public network, close the parts that are exposed by default.

Original content from computingforgeeks.com - post 169103

This guide hardens a new openSUSE Leap 16 server end to end: a non-root sudo account, key-only SSH, a locked-down firewall, SELinux left enforcing, fail2ban against brute force, and automatic updates now that YaST is gone. Every step was run on a real server, and the failure modes are called out where they bite.

Tested in June 2026 on openSUSE Leap 16 with SELinux left enforcing throughout.

Prerequisites

You need a fresh openSUSE Leap 16 install with root or initial sudo access, and a second terminal you keep open while you change anything to do with SSH. Do not skip the second terminal. The failure mode is locking yourself out of a remote box with no way back in.

SELinux enforcing and an active firewalld are the Leap 16 defaults. This guide keeps both on. If you have only just finished the install, work through the general post-install steps first, then come back here to lock the server down.

Step 1: Create a non-root sudo user

Running day to day as root means every typo and every compromised process runs with full control of the box. Least privilege starts with a normal account that can escalate when it needs to. Create one and put it in the wheel group:

useradd -m -G wheel -s /bin/bash ops
passwd ops

On Leap 16 that group membership is all you need. The distribution ships a sudo policy that grants wheel members full sudo using their own password:

sudo cat /usr/etc/sudoers.d/50-wheel-auth-self

The policy overrides the old openSUSE default that asked for the root password:

Defaults:%wheel !targetpw
%wheel ALL = (root) ALL

Note the path. Leap 16 moved vendor configuration to /usr/etc and reserves /etc for your own overrides, so the shipped sudoers files live under /usr/etc/sudoers.d/. Leave them alone and add your changes in /etc. Confirm the new account can escalate before you rely on it:

su - ops -c "sudo -v && echo sudo works"

It should prompt for the account’s own password and print sudo works. From here on, use this account and stop logging in as root.

Step 2: Set up SSH key authentication

Keys replace guessable passwords with a credential that brute force cannot grind down. Generate one on your own workstation, not on the server:

ssh-keygen -t ed25519 -C "ops@workstation"

Copy the public key to the new account on the server:

ssh-copy-id ops@SERVER_IP

Now test the key in a separate terminal before you change a single SSH setting. Do not skip this. If the key does not work and you have already disabled passwords in the next step, you are locked out:

ssh ops@SERVER_IP

If that session opens without asking for a password, the key is in place and you can safely tighten the daemon.

Step 3: Harden the SSH daemon

openSUSE Leap 16 has no /etc/ssh/sshd_config to edit. The shipped configuration lives at /usr/etc/ssh/sshd_config and pulls in drop-ins from /etc/ssh/sshd_config.d/. Add your hardening as a drop-in there so a package update never overwrites it. Open a new file:

sudo vim /etc/ssh/sshd_config.d/99-hardening.conf

Put the lockdown in it:

PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
X11Forwarding no
MaxAuthTries 3
AllowGroups wheel
ClientAliveInterval 300
ClientAliveCountMax 2

AllowGroups wheel means only members of the wheel group can log in over SSH at all. Confirm your account is in that group, or you will lock yourself out the moment sshd reloads. Always validate the syntax and restart only if the check passes:

sudo sshd -t && sudo systemctl restart sshd

Gating the restart on sshd -t matters. A single typo in the drop-in stops sshd from coming back up, and on a remote box that is a lockout. Confirm the effective policy:

sudo sshd -T | grep -E 'permitrootlogin|passwordauth|maxauthtries|allowgroups'

Root login and password authentication should both report off:

permitrootlogin no
passwordauthentication no
maxauthtries 3
allowgroups wheel

The daemon now refuses root logins and passwords outright, accepting only keys from members of the wheel group.

sshd -T showing PermitRootLogin no and PasswordAuthentication no on openSUSE Leap 16

With the daemon locked down, the next exposed surface is the firewall.

Step 4: Lock down the firewall

firewalld runs by default in the public zone. Check what it currently allows in:

sudo firewall-cmd --list-services

A fresh install typically exposes more than SSH:

cockpit dhcpv6-client ssh

The Cockpit web console is reachable on port 9090 unless you remove it. If this box is not a management host, take it out of the zone and reload:

sudo firewall-cmd --permanent --remove-service=cockpit
sudo firewall-cmd --reload

Expose only what the server actually serves. If you administer it from a known network, go further and accept SSH only from that subnet with a rich rule, which is stricter than leaving port 22 open to the world:

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" service name="ssh" accept'
sudo firewall-cmd --permanent --remove-service=ssh
sudo firewall-cmd --reload

One caution before you remove the broad ssh service: make sure your management subnet is correct, or you will cut off your own access. Test a new SSH session from inside that subnet before you log out.

Step 5: Keep SELinux enforcing

When a service misbehaves, the instinct is to run setenforce 0 and move on. Do not. SELinux enforcing is a Leap 16 default and one of the few things separating a contained compromise from a total one. Confirm it is on:

getenforce
sudo sestatus

It should report enforcing with the targeted policy loaded:

Enforcing
SELinux status:                 enabled
Current mode:                   enforcing
Loaded policy name:             targeted

When something is blocked, find out what the policy actually denied instead of switching it off. The denials land in the audit log:

sudo ausearch -m avc -ts recent

Read the denial, then fix it with the right boolean or file context (often a one-line setsebool or semanage fcontext plus restorecon). Disabling SELinux to make an error disappear trades a five-minute fix for a permanently weaker server.

Step 6: Block brute force with fail2ban

AllowGroups wheel and key-only auth already shut the door on password guessing, but fail2ban cuts off the noise of repeated probes and the log spam that comes with it. Install it:

sudo zypper install fail2ban

Configure a local jail so package updates never clobber your settings. Open a jail.local:

sudo vim /etc/fail2ban/jail.local

Read the SSH journal and ban with firewalld so the bans use the same backend as the rest of your rules:

[DEFAULT]
backend = systemd
bantime = 1h
findtime = 10m
maxretry = 5
banaction = firewallcmd-rich-rules

[sshd]
enabled = true

Enable the service and confirm the jail is watching:

sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

The jail reports the journal filter it matches and an empty ban list on a clean box:

Status for the jail: sshd
|- Filter
|  `- Journal matches:	_SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
   `- Banned IP list:

Configuration options for tighter jails are covered in the fail2ban project documentation, and the firewalld ban backend in the firewalld documentation.

Step 7: Enable automatic updates

An unpatched server is the most common way in, and with YaST retired there is no online-update module to lean on. The replacement on Leap 16 is the os-update package, which installs a systemd timer that patches the system on a schedule. Install it:

sudo zypper install os-update

Enable the timer so updates run unattended:

sudo systemctl enable --now os-update.timer

Confirm the next run is scheduled:

systemctl list-timers os-update.timer

The timer fires daily and can signal rebootmgr when a kernel update needs a restart:

NEXT                          LEFT  UNIT             ACTIVATES
Fri 2026-06-19 01:00:56 CEST  9h    os-update.timer  os-update.service

By default the timer applies every available update. To narrow it to security patches only, drop a one-line override that leaves the vendor config in /usr/share/os-update/os-update.conf untouched:

echo "UPDATE_CMD=security" | sudo tee /etc/os-update.conf

For interactive patching between scheduled runs, the same updates apply through the standard zypper update commands.

Step 8: Verify time synchronization

Accurate time is a security control, not a nicety. Log timestamps have to line up across hosts for an investigation to mean anything, and certificate and token validation both depend on the clock. Leap 16 installs chrony and runs it by default; confirm it is active and tracking a source:

systemctl is-active chronyd
chronyc -n sources

A healthy server shows reachable upstream sources with a low offset, which means the clock is disciplined and your logs are trustworthy.

Post-hardening security checklist

Before you call the server done, walk this list. Every item is one command, and every one should match the result shown. If any does not, that step is not finished.

  1. Root SSH refused. sudo sshd -T | grep permitrootlogin returns no.
  2. Passwords off. sudo sshd -T | grep passwordauthentication returns no.
  3. Only admins can log in. sudo sshd -T | grep allowgroups returns wheel.
  4. Firewall minimal. sudo firewall-cmd --list-services shows only what you serve, with no cockpit.
  5. SELinux enforcing. getenforce returns Enforcing.
  6. Brute force watched. sudo fail2ban-client status sshd shows the jail running.
  7. Updates scheduled. systemctl list-timers os-update.timer shows a next run.
  8. You are not root. You reached all of this as your wheel user through sudo, never by logging in as root.
SELinux enforcing, firewalld services, fail2ban sshd jail and os-update timer on openSUSE Leap 16

That covers the baseline every internet-facing Leap 16 server should have before it takes traffic. Layer service-specific controls on top as you add roles, and if you want a browser view of the running system to watch these controls hold, the Cockpit console reports SELinux, services, and accounts from one dashboard. SELinux being enforcing by default is one of the bigger shifts in this release, covered alongside the rest in what is new in Leap 16.

Keep reading

UFW Firewall Commands with Examples on Ubuntu 24.04 / 22.04 Security UFW Firewall Commands with Examples on Ubuntu 24.04 / 22.04 Setup WireGuard VPN on Ubuntu 24.04 / Debian 13 / Rocky Linux 10 Debian Setup WireGuard VPN on Ubuntu 24.04 / Debian 13 / Rocky Linux 10 Install Kali Linux 2026.1 Step by Step [Full Guide] Security Install Kali Linux 2026.1 Step by Step [Full Guide] How Security Awareness Training for Employees Reduces Human Cyber Risk Security How Security Awareness Training for Employees Reduces Human Cyber Risk How Organizations Can Turn Security Findings Into Actionable Improvements Security How Organizations Can Turn Security Findings Into Actionable Improvements SonarQube Alternatives for Security-Minded Engineering Leaders DevOps SonarQube Alternatives for Security-Minded Engineering Leaders

Leave a Comment

Press ESC to close