OneLinersCommand workbench
Guides
System Administration / Security

Perform an initial Ubuntu Server setup and security hardening

Create a named administrator, prove key-based recovery access, patch the host, restrict SSH, enable a host firewall, and verify time and exposed services.

45 min10 stepsChanges system stateRevision 2
Save or explore
Save to collectionCreate a collection in the sidebar first.
0 of 10 steps completed
Goal

Turn a fresh Ubuntu Server installation into a recoverable administration baseline before deploying public workloads.

Supported environments
  • Ubuntu Server 24.04 LTS
  • OpenSSH 9.x
Prerequisites
  • Console access Keep provider, hypervisor, or physical console access until a second SSH session succeeds after every access-control change.
  • Administrator key Generate an Ed25519 key on the workstation and protect its private half with a passphrase.ssh-keygen -lf ~/.ssh/id_ed25519.pub
  • Network inventory Record the management source networks and every service that must remain reachable.ip address show && ip route show
  • Recovery snapshot Take a provider snapshot or file-level backup before upgrading packages or changing remote access.
Operating boundary

OneLiners never runs these steps or stores secrets. Review placeholders, versions, current state, and change-control requirements before using a command.

Full guide

What you will build

System
  • A patched Ubuntu Server 24.04 baseline with a named, attributable administrator instead of routine use of the provider bootstrap or root account.
  • A tested key-only OpenSSH policy introduced through a local drop-in while an independent console and the original session remain available.
  • A default-deny UFW policy permitting SSH only from the declared management network, plus scheduled security updates, synchronized time, and an exposure inventory.
Observable outcome
  • A fresh SSH connection authenticates as the named administrator with an Ed25519 key and can use sudo, while root, password, and keyboard-interactive logins are rejected.
  • Current packages are installed, any required reboot is deliberate, and unattended security updates have an observable schedule and reviewed origin policy.
  • Only reviewed listeners are reachable through the host firewall; time, services, sockets, firewall state, and recovery access have concrete acceptance evidence.

Architecture

How the parts fit together

The server retains provider or physical console recovery while access moves from a bootstrap identity to a named administrator. OpenSSH reads a small local drop-in after packaged defaults, UFW enforces inbound deny with a source-restricted management exception, and Ubuntu timers maintain security updates. Each access change is validated locally and then proven through a new remote connection before the earlier path is retired.

Recovery consoleProvides an out-of-band path when SSH, firewall, routing, or package changes prevent remote login.
Named administratorProvides attributable administration through a personal public key and Ubuntu sudo policy.
OpenSSH drop-inOverrides only reviewed authentication controls without replacing the distribution-managed main file.
UFW policyDenies unsolicited inbound traffic and admits TCP/22 only from the reviewed management CIDR.
APT maintenanceApplies current packages during commissioning and schedules future Ubuntu security updates.
Operational baselineRecords routes, listeners, failed units, time, firewall rules, and package state for later comparison.
  1. Capture the untouched host state and prove console recovery, DNS, routes, repository access, capacity, and the intended management source.
  2. Apply signed Ubuntu updates, complete any controlled reboot, and repeat service and network checks.
  3. Create a named administrator, install only the public key, and prove login plus sudo from a second terminal.
  4. Write and validate a narrow SSH drop-in, reload the service, and prove both allowed key access and rejected password access.
  5. Add the source-restricted SSH rule before enabling default-deny inbound policy, then test the intended path.
  6. Enable security-update scheduling and close with time, service, socket, firewall, and fresh-login evidence.

Assumptions

  • The target is a fresh or fully inventoried Ubuntu Server 24.04 LTS host, not a production machine whose undocumented listeners can be removed casually.
  • A provider console, hypervisor console, serial console, or physical keyboard remains usable throughout SSH and firewall changes.
  • The workstation holds the administrator private key; only its public half reaches the server, and the host-key fingerprint is verified out of band.
  • The management CIDR is stable and narrow. Dynamic addresses, VPNs, bastions, and IPv6 need an equivalent reviewed access design.
  • Official or explicitly approved repositories are reachable, and the maintenance window permits a reboot if the kernel or core libraries require one.

Key concepts

Bootstrap account
The provider-created or installer-created identity used only long enough to establish attributable administrative access.
OpenSSH drop-in
A small file under sshd_config.d that changes selected settings while keeping packaged defaults maintainable.
Effective configuration
The final sshd policy after defaults, includes, and Match rules are evaluated; `sshd -T` displays it.
Default deny
A firewall stance in which inbound traffic is blocked unless an explicit reviewed rule permits it.
Management plane
The restricted path used by administrators, distinct from public application ingress.
Unattended upgrade
Ubuntu's scheduled mechanism for applying eligible security updates from approved origins.

Before you copy

Values used in this guide

{{adminUser}}

Named personal or role administrator account used for attribution.

Example: adminops
{{bootstrapUser}}

Existing account whose reviewed authorized_keys supplies the initial public key.

Example: ubuntu
{{serverAddress}}

Stable server address whose SSH host-key fingerprint has been verified.

Example: server01.example.net
{{managementCidr}}

Narrow IPv4 or IPv6 administrator source network permitted to reach SSH.

Example: 198.51.100.32/28

Security and production boundaries

  • Never paste a private SSH key into the server, guide, shell history, ticket, or chat. The server needs only the public key.
  • Disabling passwords and root login does not compensate for stolen keys, weak workstations, excessive sudo rights, or unverified host keys.
  • The generic UFW OpenSSH application profile commonly permits every source; this guide expresses the real management boundary with an explicit CIDR.
  • Treat authorized_keys, sudo policy, sshd drop-ins, repository definitions, and unattended-upgrades origins as security-sensitive configuration.
  • Review IPv4 and IPv6 together. A narrow IPv4 rule does not secure an independently reachable IPv6 listener.

Stop before continuing if

  • Stop before changing SSH if no independent console works or the host-key fingerprint cannot be verified.
  • Do not disable an authentication method until a fresh second session proves the replacement key and sudo path.
  • Do not enable UFW until the real management source and every required listener have been inventoried.
  • Stop package work on signature, dependency, storage, or interrupted-dpkg errors; never bypass repository verification.
  • Do not close commissioning while failed services, unsynchronized time, unexplained listeners, or a required reboot remain.
01

verification

Capture the starting state

read-only

Record the release, kernel, addresses, routes, listening sockets, firewall state, failed services, and pending updates before making changes.

Why this step matters

Approve the starting baseline provides a repeatable evidence checkpoint so later changes are compared against observed state instead of assumptions.

What to understand

Save release, kernel, addresses, routes, process-owned sockets, firewall status, failed units, free storage, and pending packages before making a change.

Run listener inspection with sudo because unprivileged output can omit process ownership and make an unexplained socket appear harmless.

Confirm console login, the management source observed through SSH_CONNECTION, DNS, and repository reachability.

System changes

  • No intended persistent change; reads the current host state for verification.

Syntax explained

ip -brief address
Produces a compact interface and address inventory for later comparison.
ss -lntup
Lists listening TCP and UDP sockets with numeric endpoints and owning processes.
systemctl --failed
Displays units currently in failed state.
apt list --upgradable
Shows packages whose configured repositories offer newer candidates.
Command
cat /etc/os-release && uname -r && ip -brief address && ip route && sudo ss -lntup && sudo ufw status verbose && systemctl --failed --no-pager && apt list --upgradable
Example output / evidence
PRETTY_NAME="Ubuntu 24.04 LTS"
State: inactive
0 loaded units listed.
Listing... Done

Checkpoint: Approve the starting baseline

Continue whenUbuntu 24.04, intended addresses and routes, known listeners, and no unexplained failed unit are recorded.

Stop whenAny unexplained service, listener, route, identity, synchronization, or access failure remains.

If this step fails

The evidence is incomplete or differs between repeated runs.

Likely causeInsufficient privilege, a changing network/service, name resolution, or an unstable host is affecting observation.

Safe checks
  • date --iso-8601=seconds
  • hostnamectl
  • systemctl --failed --no-pager

ResolutionUse the documented privilege level, stabilize the host, and capture a second complete sample before proceeding.

Security notes

  • Redact public addresses, usernames, repository names, and process details before sharing evidence externally.

Alternatives

  • Capture equivalent signed evidence through approved configuration management or asset inventory.

Stop conditions

  • Do not accept a checkpoint whose expected state cannot be explained.
02

command

Install current Ubuntu updates

caution

Refresh official package metadata, apply available updates, and check whether the host needs a controlled reboot.

Why this step matters

Commissioning on current signed packages removes already-fixed vulnerabilities and avoids debugging later configuration against an obsolete kernel, OpenSSH, or package database.

What to understand

`apt update` verifies current repository metadata; signature and Release-file failures are blockers, not warnings to bypass.

`full-upgrade` may change dependencies. Review its plan on sensitive hosts and never interrupt dpkg while it writes package state.

If reboot-required exists, reboot under change control while console access is present, then repeat listener, route, and failed-unit checks.

System changes

  • Updates installed packages, may restart services or install a kernel, and can require a controlled reboot.

Syntax explained

apt update
Downloads and verifies current indexes from configured repositories.
apt full-upgrade
Applies upgrades while allowing required dependency changes.
--yes
Accepts the already reviewed package plan non-interactively.
/var/run/reboot-required
Ubuntu marker that a reboot is required to load updated components.
Command
sudo apt update && sudo apt full-upgrade --yes && if test -f /var/run/reboot-required; then cat /var/run/reboot-required; else echo 'No reboot required'; fi
Example output / evidence
0 upgraded, 0 newly installed, 0 to remove.
No reboot required

Checkpoint: Prove the patched boot

test ! -f /var/run/reboot-required && apt list --upgradable 2>/dev/null && systemctl --failed --no-pager

Continue whenNo required reboot remains, no unexpected upgrade is pending, and no service failed after patching.

Stop whenAPT reports unauthenticated repositories, dependency errors, insufficient space, interrupted dpkg, or failed services.

If this step fails

dpkg reports that it was interrupted.

Likely causeA prior package operation ended before configuration completed.

Safe checks
  • ps -ef | grep -E '[a]pt|[d]pkg'
  • sudo dpkg --audit

ResolutionConfirm no package process is active, complete `sudo dpkg --configure -a`, repair dependencies explicitly, and rerun the update.

Security notes

  • Never disable signature verification or add an unauthenticated repository to make patching succeed.

Alternatives

  • Use an approved staged repository mirror and maintenance orchestrator that preserves Ubuntu signature verification.

Stop conditions

  • Do not continue while package state or a required reboot makes later observations unreliable.
03

command

Create a named sudo administrator

caution

Use an individual account for attribution. Set a strong local password even when routine access will use SSH keys.

Why this step matters

A named account makes actions attributable and lets the shared bootstrap path be retired without enabling routine remote root login.

What to understand

`adduser` creates the home and local password interactively; keep a strong console/sudo recovery password even after SSH passwords are disabled.

Ubuntu's sudo group grants broad privilege through packaged policy. Use separate accounts and remove departing operators promptly.

Verify UID, home, login shell, group list, and effective sudo policy before installing credentials.

System changes

  • Creates a local user, home directory, password hash, primary group, and sudo-group membership.

Syntax explained

adduser
Uses Ubuntu's account-creation wrapper to establish a complete local user.
usermod --append --groups sudo
Adds sudo membership without replacing other supplementary groups.
id
Displays UID and resulting group membership.
Command
Fill variables0/1 ready

Values stay on this page and are never sent or saved.

sudo adduser {{adminUser}} && sudo usermod --append --groups sudo {{adminUser}} && id {{adminUser}}
Example output / evidence
uid=1001(adminops) gid=1001(adminops) groups=1001(adminops),27(sudo)

Checkpoint: Verify the named administrator

getent passwd {{adminUser}} && id {{adminUser}} && sudo -l -U {{adminUser}}

Continue whenThe intended home and shell exist, sudo membership is present, and policy is understood.

Stop whenThe account collides, UID/home is unexpected, or sudo policy is broader than intended.

If this step fails

The user exists but sudo denies commands.

Likely causeGroup membership was not applied, an override changes policy, or the session predates the group change.

Safe checks
  • id adminops
  • sudo -l -U adminops
  • sudo visudo -c

ResolutionCorrect membership or validated sudo policy from bootstrap access, start a fresh login, and retest.

Security notes

  • Prefer one account per human; shared administrator names weaken attribution even when keys differ.

Alternatives

  • Integrate approved central identity while retaining a tested local break-glass administrator.

Stop conditions

  • Do not retire bootstrap access until the new account succeeds remotely and through console recovery.
04

command

Install the administrator public key

caution

Copy only a public key into the new account and enforce ownership and permissions accepted by OpenSSH.

Why this step matters

Installing only a verified public key provides cryptographic access without transferring the private credential to the server.

What to understand

Inspect the bootstrap authorized_keys first; it may include provider, rescue, or automation identities that should not be inherited.

Explicit ownership and 0700/0600 modes satisfy OpenSSH StrictModes and prevent unrelated users from modifying authorization.

Compare the installed fingerprint with the workstation key over an independent channel.

System changes

  • Creates the administrator `.ssh` directory and authorized_keys with restrictive ownership and permissions.

Syntax explained

install -d -m 0700
Creates an owner-only directory.
-o user -g group
Sets ownership directly.
install -m 0600
Copies the key file as owner read/write only.
Command
Fill variables0/2 ready

Values stay on this page and are never sent or saved.

sudo install -d -m 0700 -o {{adminUser}} -g {{adminUser}} /home/{{adminUser}}/.ssh && sudo install -m 0600 -o {{adminUser}} -g {{adminUser}} /home/{{bootstrapUser}}/.ssh/authorized_keys /home/{{adminUser}}/.ssh/authorized_keys
Example output / evidence
-rw------- 1 adminops adminops 99 /home/adminops/.ssh/authorized_keys

Checkpoint: Match the installed key

sudo ssh-keygen -lf /home/{{adminUser}}/.ssh/authorized_keys && sudo namei -l /home/{{adminUser}}/.ssh/authorized_keys

Continue whenThe workstation fingerprint appears and every path component has safe ownership and mode.

Stop whenAn unknown key, private-key header, unsafe permission, or fingerprint mismatch appears.

If this step fails

The source file contains several public keys.

Likely causeProvider automation or rescue identities share bootstrap authorization.

Safe checks
  • sudo ssh-keygen -lf /home/ubuntu/.ssh/authorized_keys

ResolutionCreate the new file from only the reviewed public-key line instead of copying the complete set.

Security notes

  • A public-key comment is only a label; the fingerprint is the cryptographic identity.

Alternatives

  • Use `ssh-copy-id` from the workstation before disabling password access, then inspect server ownership and fingerprint.

Stop conditions

  • Never continue if private-key material or an unrecognized public key appears.
05

verification

Prove the new login in a second terminal

read-only

Keep the original session open. Confirm the key login and a sudo prompt before disabling any authentication method.

Why this step matters

A fresh second connection proves routing, host identity, key authentication, account policy, and sudo together before fallback access is reduced.

What to understand

Keep the original session and console open; commands in an old shell do not prove a new login works.

Verify the server host-key fingerprint rather than automatically accepting an unexpected key.

`sudo -v` exercises authentication and `sudo whoami` confirms the privileged identity.

System changes

  • May refresh the sudo timestamp; otherwise performs identity and access checks without persistent configuration changes.

Syntax explained

ssh user@host
Creates an independent session using the selected account and server identity.
sudo -v
Validates sudo credentials without running an administrative workload.
sudo whoami
Confirms the effective privileged identity.
Command
Fill variables0/2 ready

Values stay on this page and are never sent or saved.

ssh {{adminUser}}@{{serverAddress}} 'id && sudo -v && sudo whoami'
Example output / evidence
uid=1001(adminops) gid=1001(adminops) groups=1001(adminops),27(sudo)
root

Checkpoint: Keep two proven access paths

ssh {{adminUser}}@{{serverAddress}} 'id && sudo -v && sudo whoami'

Continue whenThe new connection uses the named account and prints root only for the sudo command.

Stop whenHost identity is unexpected, key login fails, sudo fails, or only the original session remains.

If this step fails

The client offers the wrong key.

Likely causeAn agent holds many identities or client configuration selects another IdentityFile.

Safe checks
  • ssh -G adminops@server01.example.net | grep -i identityfile
  • ssh-add -l

ResolutionTest with IdentitiesOnly and an explicit key, then create a reviewed local Host block.

Security notes

  • Never bypass an unexpected host-key warning merely because the user key appears correct.

Alternatives

  • Use a second trusted workstation or bastion when policy requires independent access paths.

Stop conditions

  • Do not change sshd authentication while fresh login or sudo proof is incomplete.
06

config

Add a minimal OpenSSH hardening drop-in

caution

Disable direct root and password login only after the new key-based administrator has been proven. Preserve the main vendor-managed configuration.

Why this step matters

A small reviewable drop-in disables high-risk remote methods while preserving packaged configuration and a simple rollback.

What to understand

PermitRootLogin requires named authentication before privilege escalation.

PasswordAuthentication and KbdInteractiveAuthentication close different password-like paths; leaving either enabled can defeat key-only intent.

Inspect `sshd -T -C` because includes and Match blocks may alter policy for a specific connection.

System changes

  • Creates `/etc/ssh/sshd_config.d/60-oneliners-hardening.conf`; the daemon is unchanged until reload.

Syntax explained

PermitRootLogin no
Rejects direct remote root authentication.
PasswordAuthentication no
Disables SSH password authentication.
KbdInteractiveAuthentication no
Disables keyboard-interactive authentication.
PubkeyAuthentication yes
Keeps public-key authentication enabled.
File /etc/ssh/sshd_config.d/60-oneliners-hardening.conf
Configuration
printf 'PermitRootLogin no\nPasswordAuthentication no\nKbdInteractiveAuthentication no\nPubkeyAuthentication yes\n' | sudo tee /etc/ssh/sshd_config.d/60-oneliners-hardening.conf
Example output / evidence
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes

Checkpoint: Validate proposed SSH policy

sudo sshd -t && sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication) '

Continue whenSyntax passes and effective root/password/keyboard-interactive access is disabled while public keys remain enabled.

Stop whenValidation errors, a Match rule changes intent, or the second session is unavailable.

If this step fails

`sshd -t` reports a bad option.

Likely causeA directive is misspelled, malformed, unsupported, or placed in an invalid context.

Safe checks
  • sudo sshd -t
  • sudo nl -ba /etc/ssh/sshd_config.d/60-oneliners-hardening.conf

ResolutionCorrect or remove the drop-in from retained access and do not reload until syntax and effective policy pass.

Security notes

  • Key-only login shifts risk to workstation and private-key custody; interactive keys should use passphrases.

Alternatives

  • Add a tested second factor where approved PAM and recovery design support it.

Stop conditions

  • Do not reload when effective policy differs from review.
07

warning

Validate and reload SSH without closing recovery access

danger

A syntax error can stop new logins. Test the effective configuration, reload rather than stop the service, and open another fresh session.

Why this step matters

Validation followed by reload applies new policy to future connections without intentionally terminating established recovery sessions.

What to understand

Run `sshd -t` immediately before reload so the exact on-disk files are checked.

Reload Ubuntu's `ssh` unit rather than stopping it; retain console and the old session.

Prove allowed key login and rejected password login from a genuinely new client process.

System changes

  • Reloads OpenSSH so new connections use the hardening drop-in; established sessions should remain active.

Syntax explained

sshd -t
Parses configuration and host keys without starting another daemon.
systemctl reload ssh
Requests a configuration reload through Ubuntu's service unit.
sshd -T
Prints effective server configuration after includes and defaults.
Command
sudo sshd -t && sudo systemctl reload ssh && sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication) '
Example output / evidence
permitrootlogin no
pubkeyauthentication yes
passwordauthentication no
kbdinteractiveauthentication no

Checkpoint: Prove allow and deny behavior

ssh {{adminUser}}@{{serverAddress}} 'echo key-login-ok'

Continue whenA new key login succeeds; a separately forced password-only attempt is rejected.

Stop whenKey login fails, password/root login succeeds, or the service reports an error.

If this step fails

Reload fails after an earlier syntax pass.

Likely causeFiles changed between checks, a host key is missing, or the service has another runtime error.

Safe checks
  • sudo systemctl status ssh --no-pager
  • sudo journalctl -u ssh --since '10 minutes ago' --no-pager
  • sudo sshd -t

ResolutionRestore the drop-in through retained access, validate, reload, and repeat fresh-login tests.

Security notes

  • Do not submit real passwords repeatedly during negative tests; force the method and confirm rejection.

Alternatives

  • Test unusually complex Match policy with a temporary console-only sshd instance first.

Stop conditions

  • Keep recovery sessions open until a new connection succeeds after reload.
08

warning

Enable a default-deny host firewall

danger

Preview a source-restricted SSH rule, add the exact management access required, then enable UFW while the console and original SSH session remain available.

Why this step matters

Applying a source-restricted SSH exception before default deny limits exposure while avoiding lockout from enabling a firewall without an accurate management rule.

What to understand

Use the server-observed stable management CIDR rather than a guessed workstation address or broad Anywhere profile.

Review dry-run output and add the exact TCP/22 source rule before enabling UFW; application rules belong with service deployments.

Compare provider filtering and IPv6 reachability because UFW is only one layer.

System changes

  • Adds the SSH rule, sets inbound deny and outbound allow defaults, enables UFW, and programs active firewall state.

Syntax explained

--dry-run
Prints generated policy without applying it.
allow from CIDR
Restricts acceptance to the declared source network.
port 22 proto tcp
Limits the exception to the SSH TCP listener.
default deny incoming
Blocks inbound traffic without an explicit allow rule.
Command
Fill variables0/1 ready

Values stay on this page and are never sent or saved.

sudo ufw --dry-run allow from {{managementCidr}} to any port 22 proto tcp && sudo ufw allow from {{managementCidr}} to any port 22 proto tcp && sudo ufw default deny incoming && sudo ufw default allow outgoing && sudo ufw enable && sudo ufw status verbose
Example output / evidence
Status: active
Default: deny (incoming), allow (outgoing)
22/tcp ALLOW IN 198.51.100.32/28

Checkpoint: Verify the management boundary

sudo ufw status numbered && ssh {{adminUser}}@{{serverAddress}} 'echo firewall-access-ok'

Continue whenUFW is active with one narrow SSH rule and a fresh permitted connection succeeds.

Stop whenDry-run is surprising, the source is uncertain, required traffic is omitted, or login fails.

If this step fails

The client times out despite an apparent allow rule.

Likely causeUpstream filtering, routing, address-family mismatch, nonstandard port, or the wrong observed source blocks traffic.

Safe checks
  • sudo ufw status numbered
  • sudo ss -lntp | grep sshd
  • sudo journalctl -k --since '10 minutes ago' --no-pager

ResolutionUse console access to correct the smallest relevant layer and remove any broad emergency rule after proof.

Security notes

  • UFW does not replace provider filtering, authentication, patching, or private management networking.

Alternatives

  • Prepare and peer-review rules first, then enable them during a console-backed maintenance window.

Stop conditions

  • Do not enable UFW without console access and a tested rule for the real management source.
09

command

Verify unattended security updates

caution

Ubuntu 24.04 normally includes unattended-upgrades. Enable its timer and perform a dry run so failures are visible before relying on it.

Why this step matters

A verified unattended-upgrades setup reduces exposure between maintenance windows while keeping origins, exclusions, reboots, and failures observable.

What to understand

Package installation alone does not prove APT periodic configuration, timer state, or approved origins.

A dry run explains eligible packages without installing them; third-party repositories are not automatically authorized.

Choose explicit reboot and notification policy because an unexpected reboot can be operationally damaging.

System changes

  • Installs unattended-upgrades when absent and enables the apt-daily-upgrade timer; dry-run does not install upgrades.

Syntax explained

systemctl enable --now
Persists and starts the timer schedule.
--dry-run
Evaluates eligible upgrades without installing them.
--debug
Shows origin, package, and policy decisions.
Command
sudo apt install --yes unattended-upgrades && sudo systemctl enable --now apt-daily-upgrade.timer && sudo unattended-upgrade --dry-run --debug
Example output / evidence
Packages that will be upgraded: 0
apt-daily-upgrade.timer enabled

Checkpoint: Prove automatic maintenance

systemctl is-enabled apt-daily-upgrade.timer && systemctl list-timers apt-daily-upgrade.timer --all && sudo unattended-upgrade --dry-run --debug

Continue whenThe timer has a next run and dry-run completes using only approved origins.

Stop whenThe timer is masked, origins are unexpected, package state is broken, or reboot policy is unapproved.

If this step fails

A third-party package is ignored.

Likely causeIts repository origin is not in Allowed-Origins or Origins-Pattern.

Safe checks
  • apt-cache policy
  • sudo unattended-upgrade --dry-run --debug

ResolutionApprove a narrow origin pattern or maintain that vendor through a separate staged process.

Security notes

  • Never broaden allowed origins with wildcards merely to silence a warning.

Alternatives

  • Use centralized staged maintenance with canaries and explicit reboot windows.

Stop conditions

  • Do not rely on automation until dry-run and timer evidence both pass.
10

verification

Verify synchronized time and exposed services

read-only

Accurate time is required for logs, certificates, and distributed systems. Investigate every listening socket rather than assuming it is intentional.

Why this step matters

Accurate time and an explained listener inventory are prerequisites for trustworthy logs, certificates, monitoring, and incident reconstruction.

What to understand

Confirm synchronization and the active NTP service; a plausible wall clock does not prove ongoing synchronization.

Every listener needs an owner, bind address, purpose, authentication, firewall rule, monitoring, and patch responsibility.

Investigate failed, masked, or repeatedly restarting units even when the main application is reachable.

System changes

  • No intended persistent change; reads the current host state for verification.

Syntax explained

timedatectl status
Reports timezone, synchronization, and selected network-time service.
systemctl --failed
Lists units currently in failed state.
ss -lntup
Displays process-owned TCP and UDP listeners.
Command
timedatectl status && systemctl --failed --no-pager && sudo ss -lntup
Example output / evidence
System clock synchronized: yes
NTP service: active
0 loaded units listed.
LISTEN 0 4096 0.0.0.0:22

Checkpoint: Accept the commissioned baseline

Continue whenTime is synchronized, no unit is failed, every listener is documented, and UFW permits only approved flows.

Stop whenAny unexplained service, listener, route, identity, synchronization, or access failure remains.

If this step fails

The evidence is incomplete or differs between repeated runs.

Likely causeInsufficient privilege, a changing network/service, name resolution, or an unstable host is affecting observation.

Safe checks
  • date --iso-8601=seconds
  • hostnamectl
  • systemctl --failed --no-pager

ResolutionUse the documented privilege level, stabilize the host, and capture a second complete sample before proceeding.

Security notes

  • Redact public addresses, usernames, repository names, and process details before sharing evidence externally.

Alternatives

  • Capture equivalent signed evidence through approved configuration management or asset inventory.

Stop conditions

  • Do not accept a checkpoint whose expected state cannot be explained.

Finish line

Verification checklist

Fresh remote loginssh {{adminUser}}@{{serverAddress}} 'sudo true && echo access-ok'Returns access-ok from a new connection.
Effective SSH policysudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication|pubkeyauthentication) 'Root and password login are disabled; public-key login is enabled.
Host baselinesudo ufw status verbose && timedatectl status && systemctl --failed --no-pagerFirewall is active, time is synchronized, and no service is failed.

Recovery guidance

Common problems and safe checks

The named administrator receives `Permission denied (publickey)`.

Likely causeThe wrong key was copied, ownership or modes violate StrictModes, the home path differs, or a Match rule changes AuthorizedKeysFile.

Safe checks
  • sudo namei -l /home/adminops/.ssh/authorized_keys
  • sudo sshd -T -C user=adminops,host=server01.example.net,addr=198.51.100.35 | grep authorizedkeysfile
  • sudo journalctl -u ssh --since '10 minutes ago' --no-pager

ResolutionUse console or retained bootstrap access to install the intended public key with correct ownership and modes, then test a new verbose client connection.

A new connection times out after UFW is enabled.

Likely causeThe client address is outside the CIDR, SSH uses another port, upstream filtering differs, or only one address family was covered.

Safe checks
  • sudo ufw status numbered
  • sudo ss -lntp | grep sshd
  • ip route get 198.51.100.35

ResolutionFrom console, add the smallest correct source and port rule or temporarily disable UFW, prove the corrected rule, then remove emergency access.

Unattended-upgrades reports held, unauthenticated, or disallowed-origin packages.

Likely causeA third-party repository, pin, package hold, broken dependency, or origin pattern is outside the approved policy.

Safe checks
  • apt-cache policy
  • apt-mark showhold
  • sudo grep -R --line-number 'Allowed-Origins\|Origins-Pattern' /etc/apt/apt.conf.d

ResolutionCorrect repository trust and explicit origin policy; maintain unsupported third-party packages through a separate tested process.

The clock is not synchronized or certificates appear not yet valid.

Likely causeThe selected NTP service is inactive, UDP/123 or DNS is blocked, or multiple time daemons conflict.

Safe checks
  • timedatectl timesync-status
  • systemctl status systemd-timesyncd --no-pager
  • journalctl -u systemd-timesyncd --since '30 minutes ago' --no-pager

ResolutionChoose one approved time service, restore its network path, wait for synchronization, and reassess logs and certificates.

After the procedure

Alternatives and next steps

Consider these alternatives

  • Use centrally issued short-lived SSH certificates when many administrators or servers make static authorized_keys difficult to govern.
  • Use a hardened bastion, private management VPN, or provider identity-aware access path when stable source CIDRs are unavailable.
  • Use nftables directly when policy exceeds UFW's clear capabilities, but keep exactly one authoritative host-firewall manager.
  • Use centralized staged maintenance when fleet scale requires canaries, explicit reboot windows, and richer compliance evidence.

Operate it safely

  • Enroll the host in inventory, monitoring, vulnerability management, log retention, and tested backup before deploying public workloads.
  • Create a second recovery administrator or adopt short-lived SSH certificates, then retire or constrain the provider bootstrap identity.
  • Document repositories, maintenance windows, reboot policy, listeners, management sources, DNS ownership, and escalation contacts.
  • Add service firewall rules only with the service deployment and verify reachability from permitted and denied networks.
  • Schedule quarterly recovery drills and periodic review of keys, sudo membership, listeners, updates, time, and firewall policy.

Reference

Frequently asked questions

Should the SSH port be changed from 22?

A non-default port can reduce scan noise but is not an authentication control. Keys, source restriction, host-key verification, rate controls, and patching matter more.

Should I disable the root account?

Disable direct remote root login, retain a tested sudo and console recovery path, and follow the platform recovery model instead of deleting access blindly.

Does UFW replace a cloud firewall?

No. Provider and host filtering are complementary boundaries. Keep their intent aligned and test both layers.

Recovery

Rollback

Recover access from the still-open SSH session or console, then revert one control at a time.

  1. Remove /etc/ssh/sshd_config.d/60-oneliners-hardening.conf, run sshd -t, and reload ssh if the new account cannot authenticate.
  2. Disable UFW from the console or delete only the blocking rule if required management traffic was omitted.
  3. Keep the named administrator and authorized key until another tested recovery account exists.
  4. Review package history in /var/log/apt/history.log before downgrading; do not blindly reverse security updates.

Evidence

Sources and review

Verified 2026-07-24Review due 2026-10-22
Ubuntu security suggestionsofficialUbuntu OpenSSH serverofficialUbuntu firewallofficialUbuntu automatic updatesofficialUbuntu time synchronizationofficial