SECURITY / Servers & SSH · 35 min

Secure server access

Keep a way back in while you tighten SSH, review exposed ports, and plan security updates.

Before you start

Environment: Ubuntu Server 24.04 LTS VM with OpenSSH, UFW, sudo access, and a working provider or VM console. Commands use Bash. Other distributions use different service names and firewall tools.

Take a VM snapshot. Keep your current SSH session open and test console access before changing authentication or firewall rules. Use a disposable VM for your first attempt.

Commands run in your own terminal. This website cannot inspect or secure your environment.

Inspect · no configuration change

1. Find the services you expose

An unused listening service is another entry point to maintain. Start with an inventory before deciding which ports belong on the internet.

Bash · review before running
cat /etc/os-release
sudo ss -lntup
sudo ufw status verbose
systemctl --failed

What to check

Map each listening address and port to an owner and purpose. A listener on 0.0.0.0 or [::] needs an explicit exposure decision; a firewall may still block it.

Try it deliberately

Write down the administrative port, application ports, source networks, and recovery contact. Check cloud firewall rules as well as the host firewall.

Recovery & cleanup

These commands only inspect state. Do not stop unfamiliar services until you know what depends on them.

Official guidance: Ubuntu security guidance ↗

Change · authentication

2. Prove key access before disabling passwords

A key-only login reduces password-based attacks, but a syntactically valid setting can still lock out the administrator.

Bash · review before running
# On your workstation: replace admin and SERVER_IP
ssh -o PreferredAuthentications=publickey -o PasswordAuthentication=no admin@SERVER_IP

# On the server, inspect effective settings first
sudo sshd -T | grep -E "^(passwordauthentication|kbdinteractiveauthentication|permitrootlogin|pubkeyauthentication) "
sudoedit /etc/ssh/sshd_config.d/00-opsrung-lab.conf
In that new lab-only snippet, after the key login succeeds
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
Verify · run after the reviewed change
sudo sshd -t && sudo systemctl reload ssh.service
sudo sshd -T | grep -E "^(passwordauthentication|kbdinteractiveauthentication|permitrootlogin) "

What to check

The syntax check exits successfully; the effective values are no. From a second terminal, repeat the key-only login and run sudo -v. Keep the first session open until both succeed.

Try it deliberately

Check Include order and Match blocks: sshd uses the first applicable value, so a later snippet may not override earlier settings. Use sshd -T -C with the real user/address for Match rules. Do not disable keyboard-interactive authentication on an MFA system without adapting its policy.

Recovery & cleanup

From the still-open session or console, remove only the new 00-opsrung-lab.conf snippet, run sudo sshd -t, then reload ssh.service. If the file already exists, back it up and use another filename rather than overwriting it.

Official guidance: Ubuntu OpenSSH configuration ↗

Change · network access

3. Allow administration before enabling the firewall

A default-deny policy is useful only when legitimate administration and application traffic still work.

Bash · review before running
# Example only: replace the documentation address with YOUR trusted admin IP.
# Confirm the SSH port first; this example assumes TCP 22.
sudo ufw allow from 203.0.113.10 to any port 22 proto tcp
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw show added
# Enable only after reviewing all required application and monitoring rules.
sudo ufw enable
sudo ufw status numbered

What to check

A second SSH connection from the allowed address succeeds. Test application access from both an allowed source and a blocked source. Review IPv6 and the cloud firewall too.

Try it deliberately

On this practice VM, add only the application ports you actually need before enabling. Docker-published ports interact with firewall forwarding rules: UFW alone is not proof that those ports are blocked.

Recovery & cleanup

Record the previous UFW state and rules first. If this lab enabled a previously inactive firewall, use the console to run sudo ufw disable to recover access. If it was already active, restore its prior rules instead of disabling protection.

Official guidance: Ubuntu firewall guide ↗ · Docker firewall interactions ↗

Inspect · update policy

4. Make updates and recovery routine

A patch policy needs an owner, a maintenance window, and a tested restore path.

Bash · review before running
apt list --upgradable
systemctl list-timers apt-daily-upgrade.timer
sudo unattended-upgrade --dry-run --debug
test ! -f /var/run/reboot-required || cat /var/run/reboot-required

What to check

Review the proposed updates and allowed origins. A timer alone does not prove updates installed; inspect /var/log/unattended-upgrades/ and record any reboot requirement. The dry run needs unattended-upgrades installed.

Try it deliberately

Schedule a reviewed update on the VM, check your service afterward, and restore a backup into a separate VM. Record recovery time and confirm the restored data is usable. Never put real credentials in the exercise notes.

Recovery & cleanup

A package downgrade is not a universal rollback. Keep a tested snapshot or rebuild-and-restore procedure and protect backups separately from the server.

Official guidance: Ubuntu automatic updates ↗

Reviewed 31 October 2026. Adapt to your installed versions and environment; these guides cover selected controls, not a compliance certification.