How to Set Up a Linux Server: Installation and First Steps
A Linux server is just a machine running a server-oriented distribution without a desktop, reachable over the network and doing a job: web, database, file sharing, CI runners. An old PC, a Raspberry Pi, a VM or a cloud instance all qualify. The process is the same: pick a distribution, install a minimal system, then spend half an hour on the basics that keep it secure and maintainable.
Pick a distribution
- Ubuntu Server LTS (24.04 or 26.04): five years of standard security updates, huge amount of documentation, default on most clouds.
- Debian stable (13 "trixie"): conservative, minimal, no commercial layer. Good for long-lived boxes.
- RHEL family: Red Hat Enterprise Linux 9 or 10 and its rebuilds AlmaLinux and Rocky Linux. Ten-year lifecycle per major version. RHEL is free for up to 16 systems through the Red Hat Developer Subscription for Individuals.
About CentOS: CentOS Linux 7 and 8 are end of life and get no updates. Do not install them. CentOS Stream still exists, but it is the development branch just ahead of the next RHEL minor release, not a stable rebuild. If you want "CentOS like it used to be", install AlmaLinux or Rocky Linux.
Pick what you or your team already know. The differences matter much less than consistency across your servers.
Install
On a cloud provider there is no installer: you pick an image, attach an SSH key and the instance boots ready. cloud-init applies your user, keys and initial config from user data. Skip to the first steps below.
For bare metal or a local VM:
- Download the server ISO: the Ubuntu Server "live server" image, the Debian netinst image, or the RHEL, AlmaLinux or Rocky "boot" or "DVD" image.
- Verify it against the published checksum:
sha256sum -c SHA256SUMS --ignore-missing. - Write it to a USB stick. On Linux:
lsblk # find the stick, e.g. /dev/sdc
sudo dd if=ubuntu-server.iso of=/dev/sdc bs=4M status=progress conv=fsync
dd overwrites whatever device you point it at without asking. Double-check the device name. On Windows or macOS, Rufus, balenaEtcher or Ventoy do the same.
- Boot from the stick (UEFI boot menu, often F12, F11 or Esc) and follow the installer.
Installing Ubuntu Desktop works the same way with the desktop ISO. Everything below about users, SSH and updates applies to a desktop too.
Installer choices that matter
Ubuntu Server (Subiquity installer)
- Use the default LVM layout. It makes resizing later much easier. On some versions the default leaves part of the volume group unallocated: check after install with
sudo vgsand grow the root volume if you want that space (sudo lvextend -r -l +100%FREE /dev/ubuntu-vg/ubuntu-lv). - Tick "Install OpenSSH server" and import your public keys from GitHub or Launchpad if you keep them there.
- Skip the featured snaps. Install what you need later.
Debian
- Leave the root password empty. The installer then disables root login and gives your first user sudo. If you set a root password, your user gets no sudo rights and sudo may not even be installed.
- In software selection, untick the desktop environment and tick only "SSH server" and "standard system utilities".
RHEL, AlmaLinux, Rocky (Anaconda installer)
- Choose "Minimal Install" under Software Selection.
- Create a user and tick "Make this user administrator" (adds it to
wheel). - RHEL asks you to register the system. You can also do it later with
sudo subscription-manager register.
For many identical machines, automate the installer instead of clicking through it: Kickstart for the RHEL family, autoinstall YAML for Ubuntu Server, preseed for Debian.
First steps after the first boot
Update everything
sudo apt update && sudo apt full-upgrade -y # Ubuntu, Debian
sudo dnf upgrade -y # RHEL family
sudo reboot # if a new kernel was installed
Hostname and time zone
sudo hostnamectl set-hostname web1
sudo timedatectl set-timezone UTC
timedatectl # "System clock synchronized: yes"
UTC on servers avoids confusion in logs across regions. Time sync (systemd-timesyncd or chrony, depending on the distro) is on by default. Confirm it, because TLS, Kerberos and log correlation all break with a drifting clock.
An admin user with SSH keys
If the installer created only root, or you need another admin:
sudo adduser alice # Debian/Ubuntu (interactive)
sudo usermod -aG sudo alice
sudo useradd -m -G wheel alice # RHEL family
sudo passwd alice
From your workstation, install your key and check that it works:
ssh-keygen -t ed25519
ssh-copy-id alice@192.0.2.10
ssh alice@192.0.2.10
Then turn off password logins and direct root login in a drop-in file:
sudo tee /etc/ssh/sshd_config.d/10-hardening.conf <<'EOF'
PasswordAuthentication no
PermitRootLogin no
EOF
sudo sshd -t && sudo systemctl reload ssh # sshd on RHEL family
Keep your current session open and test a new login before you log out.
Firewall
# Ubuntu (ufw is installed but inactive)
sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status
# RHEL family (firewalld is active by default)
sudo firewall-cmd --list-all
sudo firewall-cmd --permanent --add-service=http --add-service=https
sudo firewall-cmd --reload
Debian ships without an active firewall. Install ufw and use the Ubuntu commands, or write nftables rules directly. On cloud instances, the provider's security groups are the first layer. Use both.
Automatic security updates
# Ubuntu: unattended-upgrades is installed and enabled for security updates
cat /etc/apt/apt.conf.d/20auto-upgrades
# Debian
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
# RHEL family
sudo dnf install dnf-automatic
# set apply_updates = yes in /etc/dnf/automatic.conf
sudo systemctl enable --now dnf-automatic.timer
Unattended updates do not reboot by default. Kernel updates need a reboot to take effect, so schedule one, or enable automatic reboots during a maintenance window.
A static address
A server should keep its IP. The simplest way is a DHCP reservation on your router or DHCP server. To configure it on the host instead:
# Ubuntu: /etc/netplan/50-static.yaml (mode 600)
network:
version: 2
ethernets:
enp1s0:
addresses: [192.0.2.10/24]
routes:
- to: default
via: 192.0.2.1
nameservers:
addresses: [192.0.2.1]
Apply it with sudo netplan try, which rolls back automatically if you lose the connection and do not confirm. On the RHEL family, use NetworkManager:
nmcli connection show
sudo nmcli connection modify enp1s0 ipv4.method manual \
ipv4.addresses 192.0.2.10/24 ipv4.gateway 192.0.2.1 ipv4.dns 192.0.2.1
sudo nmcli connection up enp1s0
Keep it lean
Every installed package and listening service is something to patch. Check what runs and what listens, and remove what you did not ask for:
systemctl list-unit-files --type=service --state=enabled
sudo ss -tulpn
Then install the actual workload. Packages from the distro repositories or the vendor's official repository, or containers with Docker or Podman, keep the host itself small and easy to rebuild.
Before it goes live
- Backups that you have restored at least once.
- Monitoring for disk space, memory and the service itself.
- Configuration in Ansible or similar, so a replacement server is a playbook run, not an afternoon of remembering.
Quick reference
sudo apt update && sudo apt full-upgrade # or: sudo dnf upgrade
sudo hostnamectl set-hostname web1
sudo timedatectl set-timezone UTC
sudo usermod -aG sudo alice # wheel on RHEL family
ssh-copy-id alice@server # from your workstation
# /etc/ssh/sshd_config.d/10-hardening.conf: PasswordAuthentication no
sudo ufw allow OpenSSH && sudo ufw enable # or firewall-cmd on RHEL
sudo apt install unattended-upgrades # or dnf-automatic
sudo ss -tulpn # what listens on the network
