Linux Post-Installation Checklist: Initial Server Configuration
Level: Beginner / Intermediate
Estimated time: ~40 minutes
Goal: Complete the essential initial server configuration on a Linux VPS - harden SSH access, create a sudo user, configure a firewall, set up automatic security updates, and schedule basic maintenance tasks with cron.
Introduction
The first 30 minutes after provisioning a VPS are the most important. A freshly installed Linux server is wide open: root login over SSH is usually enabled, no firewall rules are in place, and packages are already outdated. This linux post-installation checklist covers every step that matters for a production-ready or dev environment setup - from creating a sudo user and configuring SSH key authentication, to enabling UFW and scheduling automatic security updates. Following this guide once protects you from the most common attack vectors before you deploy anything on top.
This guide covers Ubuntu, Debian, and AlmaLinux (RHEL-compatible) VPS instances.
Prerequisites
Before you begin, make sure the following conditions are met:
- Operating system: Ubuntu 20.04/22.04/24.04 LTS, Debian 11/12/13, or AlmaLinux 8/9/10
- Access: Root SSH access to the server (password or key - you will harden this during the guide)
- Local machine: SSH client available (ssh on Linux/macOS, PuTTY or Windows Terminal on Windows)
- Required knowledge: Basic Linux command line usage - navigating directories, editing files with nano
- Estimated time: ~40 minutes for a clean first run
This guide is tested on Ubuntu 24.04 LTS, Debian 12/13, and AlmaLinux 9/10. The steps are identical unless noted otherwise.
Step 1: Set the Server Hostname
A proper hostname makes logs readable and prevents confusion when managing multiple servers.
First, update /etc/hosts so the system can resolve its new hostname locally. Open the file:
sudo nano /etc/hosts
Add or update the line for 127.0.1.1 (or 127.0.0.1 if 127.0.1.1 does not exist) to match your new hostname. For example, if you plan to use web-01:
127.0.1.1 web-01
Save and exit (Ctrl+O, Enter, Ctrl+X).
Next, set the hostname globally with hostnamectl:
sudo hostnamectl set-hostname <YOUR_HOSTNAME>
Verify it was applied:
hostnamectl
Expected output:
Static hostname: web-01 Icon name: computer-vm Chassis: vm Machine ID: a1b2c3d4e5f6... Boot ID: ... Operating System: Ubuntu 24.04.1 LTS Kernel: Linux 6.8.0-31-generic Architecture: x86-64
Many services - including Postfix (mail) and SSL certificate tools like Certbot - rely on the hostname being resolvable locally. Updating /etc/hosts before running hostnamectl avoids subtle resolution failures.
Step 2: Update All Packages
Run a full system update immediately. Packages shipped with a fresh VPS image are almost always behind.
Ubuntu/Debian (APT):
sudo apt update && sudo apt upgrade -y
AlmaLinux/RHEL (DNF):
sudo dnf update -y
After the update completes, check whether a reboot is required.
Debian/Ubuntu:
cat /var/run/reboot-required 2>/dev/null && echo "Reboot required" || echo "No reboot needed"
AlmaLinux/RHEL:
sudo dnf install -y dnf-utils needs-restarting -r
If a reboot is required, reboot now before continuing - some kernel and library updates only take effect after a restart:
sudo reboot
Skipping the reboot when it is required means your running kernel and some libraries remain on the old version. This can leave known vulnerabilities unpatched even after the update.
Step 3: Create a Sudo User
Logging in as root for day-to-day work is unsafe and bad practice. Create a regular user and grant it sudo privileges.
3.1 Add the user
sudo adduser <YOUR_USERNAME>
On Ubuntu/Debian, the command will prompt you to set a password and fill in optional contact fields. Fill in the password; skip the rest by pressing Enter.
On AlmaLinux/RHEL, adduser is a symlink to useradd and runs non-interactively without prompting for a password, leaving the account locked. You must set the password manually:
sudo passwd <YOUR_USERNAME>
3.2 Grant sudo privileges
Ubuntu/Debian - add the user to the sudo group:
sudo usermod -aG sudo <YOUR_USERNAME>
AlmaLinux/RHEL - add the user to the wheel group:
sudo usermod -aG wheel <YOUR_USERNAME>
3.3 Verify access
Switch to the new user and test sudo:
su - <YOUR_USERNAME> sudo whoami
Expected output:
root
If you see root, the user has working sudo privileges. You can now log out of the root session:
exit
On AlmaLinux, wheel group membership is defined in /etc/sudoers via the %wheel ALL=(ALL) ALL line, which is enabled by default. On Ubuntu/Debian, the sudo group serves the same purpose.
Step 4: Configure SSH Key Authentication
Password-based SSH is vulnerable to brute-force attacks. SSH key authentication replaces the password with a cryptographic key pair - much harder to attack. This is one of the most important SSH configuration best practices you can apply.
4.1 Generate an SSH key pair (on your local machine)
If you do not already have an SSH key pair, generate one on your local machine (not the server):
ssh-keygen -t ed25519 -C "<YOUR_USERNAME>@<YOUR_HOSTNAME>"
Accept the default file location. Set a passphrase when prompted - this protects the key if your local machine is ever compromised.
ed25519 is the preferred key type. It is faster, shorter, and more secure than the older rsa (2048-bit). If your SSH client does not support it, use ssh-keygen -t rsa -b 4096 instead.
4.2 Copy the public key to the server
From your local machine, copy the key to the new user's account:
ssh-copy-id <YOUR_USERNAME>@<YOUR_SERVER_IP>
If ssh-copy-id is not available (e.g., Windows), manually copy the contents of ~/.ssh/id_ed25519.pub and append it to ~/.ssh/authorized_keys on the server.
4.3 Test the key-based login
Open a new terminal window (do not close the current session yet) and test the login:
ssh <YOUR_USERNAME>@<YOUR_SERVER_IP>
You should log in without being asked for a password (only the key passphrase, if you set one).
Do not close your existing SSH session until you have confirmed the key-based login works. If something is misconfigured, you will still have the existing session to fix it.
Step 5: Harden SSH Configuration and Disable Root Login
With key-based login confirmed (Step 4), lock down the SSH daemon. Disabling root login and password authentication over SSH is one of the most effective steps in any Linux server hardening checklist.
On all three distributions, /etc/ssh/sshd_config has an Include /etc/ssh/sshd_config.d/*.conf line near the top of the file, and SSH applies the first value it finds for each setting. Vendor drop-in files are already present and override anything you add later in the main file:
- Ubuntu 24.04: 50-cloud-init.conf sets PasswordAuthentication yes
- AlmaLinux: 50-redhat.conf sets X11Forwarding yes
For that reason, editing the main sshd_config is unreliable. Instead, create a hardening drop-in with a low number (00-) so it is read first and overrides the vendor files. The same file works on all three distributions.
Create the drop-in file:
sudo tee /etc/ssh/sshd_config.d/00-hardening.conf > /dev/null <<'EOF' PermitRootLogin no PasswordAuthentication no PubkeyAuthentication yes AuthorizedKeysFile .ssh/authorized_keys X11Forwarding no EOF
A 00- prefix guarantees this file is parsed before vendor drop-ins like 50-cloud-init.conf and 50-redhat.conf. Because SSH uses first-match-wins, you do not need to edit those files.
Validate the configuration syntax before restarting the service:
sudo sshd -t
If the command returns no output, the syntax is valid. Now verify the effective settings the daemon will actually use:
sudo sshd -T | grep -iE "permitrootlogin|passwordauthentication|x11forwarding"
Expected output:
permitrootlogin no passwordauthentication no x11forwarding no
Confirm all three values are correct before restarting. If passwordauthentication still shows yes, a vendor drop-in is overriding your file – check that 00-hardening.conf was saved correctly. Do not close your existing SSH session until you have verified that key-based login still works.
Restart the SSH daemon to apply the changes.
Ubuntu 24.04 (socket activation):
sudo systemctl restart ssh.socket
Debian and older Ubuntu:
sudo systemctl restart ssh
AlmaLinux/RHEL:
sudo systemctl restart sshd
Verify the service is running (use sshd on AlmaLinux, ssh.socket on Ubuntu 24.04):
sudo systemctl status ssh
You should see Active: active (running) (or active (listening) for socket-activated SSH).
Now confirm that root login is blocked. From your local machine:
ssh root@<YOUR_SERVER_IP>
Expected result: the connection is refused with Permission denied (publickey). Root login over SSH is now disabled.
Step 6: Configure Firewall (UFW)
UFW (Uncomplicated Firewall) is the standard firewall tool on Ubuntu and Debian. On AlmaLinux, firewalld is the default, but UFW can be installed there too. This step covers both approaches.
Before enabling any firewall, make sure SSH (port 22) is explicitly allowed. Getting this wrong will lock you out of the server.
6.1 UFW (Ubuntu/Debian)
On Debian (especially Debian 13), ufw might not be installed by default. Install it first:
sudo apt update && sudo apt install -y ufw
Check current status:
sudo ufw status
Allow SSH before enabling the firewall:
sudo ufw allow ssh
Allow HTTP and HTTPS if you plan to run a web server:
sudo ufw allow http sudo ufw allow https
Enable the firewall:
sudo ufw enable
Verify the active rules:
sudo ufw status verbose
Expected output:
Status: active Logging: on (low) Default: deny (incoming), allow (outgoing), disabled (routed) To Action From -- ------ ---- 22/tcp ALLOW IN Anywhere 80/tcp ALLOW IN Anywhere 443/tcp ALLOW IN Anywhere
6.2 Firewalld (AlmaLinux/RHEL)
Enable and start firewalld:
sudo systemctl enable --now firewalld
Allow SSH, HTTP, and HTTPS:
sudo firewall-cmd --permanent --add-service=ssh sudo firewall-cmd --permanent --add-service=http sudo firewall-cmd --permanent --add-service=https sudo firewall-cmd --reload
Verify:
sudo firewall-cmd --list-all
configure firewall linux means choosing the right tool for your distribution and not running two firewall daemons at once. If you installed UFW on AlmaLinux, disable firewalld first with sudo systemctl disable --now firewalld.
Step 7: Synchronize the System Clock (NTP)
Accurate time is required for security protocols (SSL/TLS validation, Kerberos), correct log timestamps, and scheduled jobs. An out-of-sync clock can cause SSL certificate errors, failed authentication, and confusing log entries.
Check the current synchronization state:
timedatectl status
Expected output:
System clock synchronized: yes NTP service: active
On Ubuntu 24.04 and Debian 13, NTP is typically active via systemd-timesyncd. On AlmaLinux 10, it is usually active via chrony. If timedatectl shows System clock synchronized: yes and NTP service: active, you do not need to change anything.
If NTP service shows as inactive or n/a, install and enable chrony - the recommended NTP daemon for production servers:
Ubuntu/Debian:
sudo apt install chrony -y sudo systemctl enable --now chrony
On Debian 13, installing chrony might cause `timedatectl` to show `NTP service: n/a`. Use `chronyc tracking` to verify instead.
AlmaLinux/RHEL:
sudo dnf install chrony -y sudo systemctl enable --now chronyd
Wait 30–60 seconds after starting the service, then verify synchronization is active:
chronyc tracking
Look for Leap status: Normal. That confirms the system clock is synchronized and NTP is working correctly.
If you manage servers in multiple time zones, set the system time zone before configuring NTP so that log timestamps are in the expected local time. Example: sudo timedatectl set-timezone Europe/Warsaw.
Step 8: Enable Automatic Security Updates
Manual updates work, but they depend on you remembering to do them. Automatic security updates are a safety net - especially critical for unattended VPS instances. This is how you configure automatic security updates linux without affecting stability.
8.1 Ubuntu/Debian - unattended-upgrades
Install the package:
sudo apt install unattended-upgrades -y
Enable and configure it:
sudo dpkg-reconfigure --priority=low unattended-upgrades
It is critical to select Yes when prompted. If you select No, the necessary configuration file (/etc/apt/apt.conf.d/20auto-upgrades) will not be created, and subsequent checks will fail with a "No such file or directory" error. This enables automatic installation of security updates only - regular feature updates remain manual.
Verify the configuration:
cat /etc/apt/apt.conf.d/20auto-upgrades
Expected output:
APT::Periodic::Update-Package-Lists "1"; APT::Periodic::Unattended-Upgrade "1";
To test without applying changes:
sudo unattended-upgrade --dry-run --debug
8.2 AlmaLinux/RHEL - dnf-automatic
Install:
sudo dnf install dnf-automatic -y
Open the configuration file and set the upgrade type to security only. First, make a backup:
sudo cp /etc/dnf/automatic.conf /etc/dnf/automatic.conf.bak sudo nano /etc/dnf/automatic.conf
Find and set:
apply_updates = yes upgrade_type = security
Enable and start the timer:
sudo systemctl enable --now dnf-automatic.timer
Verify:
sudo systemctl status dnf-automatic.timer
Step 9: Schedule Basic Maintenance with Cron
Cron handles scheduled tasks - things that need to happen regularly without manual intervention. A simple cron job for tasks like log cleanup or certificate renewal checks is standard practice on any managed server.
AlmaLinux/RHEL preparation:
On a clean AlmaLinux 10 system, nano might not be installed, and crontab -e will open vi. To use nano instead, run this single line to execute it cleanly in sequence and ensure the environment variable persists:
sudo dnf install nano -y && export EDITOR=nano && crontab -e
For other systems (like Ubuntu/Debian), just open the crontab for the current user:
crontab -e
On the first run (on Ubuntu/Debian), you will be asked to choose an editor. Select nano (option 1).
Common cron job examples
Run a task every night at 2:00 AM:
0 2 * * * /usr/local/bin/my-maintenance-script.sh >> /var/log/maintenance.log 2>&1
Renew SSL certificates weekly (for Certbot users):
0 3 * * 0 certbot renew --quiet >> /var/log/certbot-renew.log 2>&1
Clear temporary files monthly:
0 4 1 * * find /tmp -type f -atime +30 -delete
Cron uses the format minute hour day-of-month month day-of-week command. The >> /var/log/task.log 2>&1 part redirects both stdout and stderr to a log file, so you can review what happened.
Verify your cron jobs are registered:
crontab -l
You should see the entries you added. Cron reads the file automatically - no reload needed. To check if the cron service is running, use:
Ubuntu/Debian:
sudo systemctl status cron
AlmaLinux/RHEL:
sudo systemctl status crond
Verification
Run through this checklist to confirm everything was applied correctly:
Check the hostname:
hostnamectl | grep hostname
Confirm no root SSH login and password authentication are disabled (this checks the active runtime configuration):
sudo sshd -T | grep -iE "permitrootlogin|passwordauthentication"
Expected:
permitrootlogin no passwordauthentication no
Confirm the SSH service is running:
# For Ubuntu 24.04: sudo systemctl status ssh.socket # For Debian / Older Ubuntu: sudo systemctl status ssh # For AlmaLinux: sudo systemctl status sshd
Check firewall status (Ubuntu/Debian):
sudo ufw status verbose
Check NTP sync:
timedatectl status | grep -E "synchronized|NTP"
Expected:
System clock synchronized: yes NTP service: active
Check automatic updates (Ubuntu/Debian):
cat /etc/apt/apt.conf.d/20auto-upgrades
List active cron jobs:
crontab -l
Rollback
To undo specific steps if something went wrong:
Re-enable root SSH login (if you locked yourself out and are recovering via console):
# Re-enable root/password login temporarily for recovery sudo rm /etc/ssh/sshd_config.d/00-hardening.conf sudo sshd -t # Restart SSH (use the variant for your system): sudo systemctl restart ssh.socket # Ubuntu 24.04 sudo systemctl restart ssh # Debian / older Ubuntu sudo systemctl restart sshd # AlmaLinux/RHEL
Disable UFW:
sudo ufw disable
Remove unattended-upgrades (Ubuntu/Debian):
sudo apt remove unattended-upgrades -y
Remove dnf-automatic (AlmaLinux):
sudo systemctl disable --now dnf-automatic.timer sudo dnf remove dnf-automatic -y
Remove a cron job:
crontab -e # Delete the relevant line, save and exit
Re-enabling root login or password authentication undoes most of the security hardening done in this guide. Only do this temporarily to recover access, then lock it back down.
Conclusion
That covers the full linux post-installation checklist. You now have a server with a proper hostname, fully updated packages, a non-root sudo user, SSH key authentication in place, root login disabled, a firewall configured, NTP synchronized, automatic security updates running, and a cron job schedule ready to extend. This is the baseline linux server setup after install that every VPS should have before anything else is deployed on it.
From here, the logical next steps depend on what the server is for:
- Web server: Install Nginx or Apache, set up a virtual host, and configure SSL with Certbot
- Database: Install and harden MySQL/MariaDB or PostgreSQL
- Monitoring: Set up log aggregation (e.g., logrotate) or a lightweight monitoring agent
- Access control: Review sudoers configuration and add team members using the same pattern from Step 3
The initial server configuration linux checklist does not end here - it evolves as the server's role grows. But this baseline is the non-negotiable starting point.
Document Version: 1.0
Last Updated: May 2026
Owner: Technical Documentation Team