Table of Contents
URL: https://www.progressiverobot.com/initial-server-setup-with-ubuntu-20-04/
Introduction
When you first create a new Ubuntu server, you should immediately create a non-root user with sudo privileges, configure SSH key authentication, and enable a firewall. These three steps form the foundation of server security and prevent common attack vectors like brute-force password attempts and unauthorized access.
Performing proper initial server setup is critical because a fresh Ubuntu installation defaults to root access, which poses significant security risks. Without hardening, your server becomes a target for automated attacks that scan for default configurations and weak passwords. This guide walks you through essential security steps that take approximately 10–15 minutes but dramatically reduce your attack surface.
[info]
When you create a cloud servers, you can choose an Ubuntu version that will be added to your new Droplet automatically. Simplify your setup with our out-of-the-box solutions.
This tutorial is compatible with Ubuntu 20.04 and later versions. While most commands work across these releases, minor differences may exist in default SSH configurations and file locations between versions. For more information about Ubuntu on the cloud provider, see our product documentation.
Key Takeaways
Before diving into the step-by-step process, here are the essential concepts you'll learn:
- Create a non-root user with sudo privileges to follow the principle of least privilege and reduce the risk of accidental system damage.
- Configure SSH key authentication instead of passwords to eliminate brute-force attack vectors and improve security posture.
- Enable UFW firewall to control network traffic and block unauthorized access attempts, allowing only necessary services.
- Verify access before closing root session to prevent SSH lockout scenarios that could leave you unable to access your server.
- Understand the security tradeoffs between password and key-based authentication, and when each approach is appropriate.
- Automate repeatable setups using scripts or configuration management tools for consistency across multiple servers.
By following this guide, you'll establish a secure foundation that protects your server from common threats while maintaining usability for day-to-day operations.
Prerequisites
Before you begin, ensure you have:
- A fresh Ubuntu server (20.04 or later) with root or sudo access. This guide assumes you're starting with a clean installation.
- Your server's public IP address, which you'll need to connect via SSH. You can find this in your hosting provider's dashboard.
- SSH access credentials: Either the root password or an SSH private key that was configured during server creation.
- A local terminal or SSH client installed on your computer. On macOS and Linux, SSH comes pre-installed. On Windows, you can use PowerShell, PuTTY, or Windows Terminal.
[warning]
Critical: Do not close your root SSH session until you've verified that your new user can log in and use sudo. If you lock yourself out, you'll need to use your hosting provider's recovery console or console access to regain entry.
Step 1 — Logging in as root user
To log into your server, you will need to know your server's public IP address. You will also need the password or — if you installed an SSH key for authentication — the private key for the root user's account. If you have not already logged into your server, you may want to follow our guide on how to Connect to Droplets with SSH or how to use SSH to connect to a remote server, which cover this process in detail.
If you are not already connected to your server, log in now as the root user using the following command (substitute the highlighted portion of the command with your server's public IP address):
[environment local]
ssh root@your_server_ip
Accept the warning about host authenticity if it appears. If you are using password authentication, provide your root password to log in. If you are using an SSH key that is passphrase protected, you may be prompted to enter the passphrase the first time you use the key each session. If this is your first time logging into the server with a password, you may also be prompted to change the root password.
Security Note: The host authenticity warning appears the first time you connect to a new server. This is normal and helps prevent man-in-the-middle attacks. Type yes to accept and continue. The server's fingerprint will be saved to ~/.ssh/known_hosts on your local machine.
About root
The root user is the administrative user in a Linux environment that has very broad privileges. Because of the heightened privileges of the root account, you are _discouraged_ from using it on a regular basis. This is because the root account is able to make very destructive changes, even by accident.
Why avoid root for daily use:
- No safety checks: Commands run as root execute immediately without confirmation, making typos potentially catastrophic (e.g.,
rm -rf /instead ofrm -rf ./).
- Poor audit trails: All actions appear as "root" in logs, making it difficult to track which human user performed specific operations.
- Increased attack surface: Root accounts are primary targets for attackers. Using a non-root user with sudo reduces visibility and limits damage if credentials are compromised.
The next step is setting up a new user account with reduced privileges for day-to-day use. Later, we'll show you how to temporarily gain increased privileges for the times when you need them.
Step 2 — Creating a New User
Once you are logged in as root, you'll be able to add the new user account. In the future, we'll log in with this new account instead of root.
This example creates a new user called sammy, but you should replace that with a username that you like:
adduser sammy
You will be asked a few questions, starting with the account password.
Enter a strong password and, optionally, fill in any of the additional information if you would like. This is not required and you can just hit ENTER in any field you wish to skip.
Username Best Practices: Choose a username that:
- Is not a common name like "admin", "user", or "test" (these are frequently targeted)
- Doesn't reveal your identity or organization unnecessarily
- Is easy to type and remember
- Follows standard Linux username conventions (lowercase letters, numbers, hyphens, underscores; no spaces)
Verification: After creating the user, verify the account was created successfully:
id sammy
You should see output showing the user ID, group ID, and group memberships. The user should exist in their primary group but not yet have sudo privileges.
Step 3 — Granting Administrative Privileges
Now we have a new user account with regular account privileges. However, we may sometimes need to perform administrative tasks.
To avoid having to log out of our normal user and log back in as the root account, we can set up what is known as _superuser_ or root privileges for our normal account. This will allow our normal user to run commands with administrative privileges by putting the word sudo before the command.
To add these privileges to our new user, we need to add the user to the sudo group. By default, on Ubuntu, users who are members of the sudo group are allowed to use the sudo command.
As root, run this command to add your new user to the sudo group (substitute the highlighted username with your new user):
usermod -aG sudo sammy
Understanding the Command: The -aG flags mean:
-a(append): Adds the user to the group without removing them from other groups
-G(groups): Specifies the group(s) to add
Without -a, the user would be removed from all other groups except the ones specified, which could break existing permissions.
Now, when logged in as your regular user, you can type sudo before commands to run them with superuser privileges.
Verification: Verify sudo access is configured correctly:
su - sammy
sudo whoami
You should see root as the output, confirming that sudo is working. You'll be prompted for the user's password the first time you use sudo in a session.
[warning]
Important: Don't log out of your root session yet as we will test the new user's SSH access in the next step before closing the root connection.
Step 4 — Setting Up a Basic Firewall
Ubuntu servers can use the UFW (Uncomplicated Firewall) to make sure only connections to certain services are allowed. We can set up a basic firewall using this application.
Note: If your servers are running on the cloud provider, you can optionally use the cloud provider Cloud Firewalls instead of the UFW firewall. We recommend using only one firewall at a time to avoid conflicting rules that may be difficult to debug.
Why UFW? UFW provides a simple interface for managing iptables, the underlying Linux firewall. While you can configure iptables directly, UFW's application profiles and straightforward commands make it much easier to manage, especially for beginners.
Applications can register their profiles with UFW upon installation. These profiles allow UFW to manage these applications by name. OpenSSH, the service allowing us to connect to our server now, has a profile registered with UFW.
You can see this by typing:
ufw app list
Available applications:
OpenSSH
We need to make sure that the firewall allows SSH connections so that we can log back in next time. We can allow these connections by typing:
ufw allow OpenSSH
Alternative Syntax: You can also use ufw allow ssh or ufw allow 22/tcp (where 22 is the default SSH port). The OpenSSH profile name is preferred because it's more descriptive and works regardless of which port SSH is configured to use.
Afterwards, we can enable the firewall by typing:
ufw enable
Type y and press ENTER to proceed. You can see that SSH connections are still allowed by typing:
ufw status
Status: active
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
OpenSSH (v6) ALLOW Anywhere (v6)
Common UFW Rules for Web Servers:
If you plan to run a web server, you'll need to allow HTTP and HTTPS traffic:
Note: Application profiles like 'Nginx Full' and 'Apache Full' only exist after the respective service is installed. If you haven't installed Nginx or Apache yet, use port-based rules instead.
ufw allow 'Nginx Full'
Or for Apache:
ufw allow 'Apache Full'
Or manually specify ports (use this if the service isn't installed yet):
ufw allow 80/tcp
ufw allow 443/tcp
[warning]
Critical: Always allow SSH (port 22) before enabling UFW. If you enable the firewall without allowing SSH first, you'll be locked out of your server and will need console access to fix it.
As the firewall is currently blocking all connections except for SSH, if you install and configure additional services, you will need to adjust the firewall settings to allow traffic in. You can learn some common UFW operations in our _UFW Essentials_ guide.
Step 5 — Enabling External Access for Your Regular User
Now that we have a regular user for daily use, we need to make sure we can SSH into the account directly.
The process for configuring SSH access for your new user depends on whether your server's root account uses a password or SSH keys for authentication.
If the root account uses password authentication
If you logged in to your root account _using a password_, then password authentication is _enabled_ for SSH. You can SSH to your new user account by opening up a new terminal session and using SSH with your new username:
[environment local]
ssh <^>sammy<^>@<^>your_server_ip<^>
After entering your regular user's password, you will be logged in. Remember, if you need to run a command with administrative privileges, type sudo before it like this:
sudo <command_to_run>
You will be prompted for your regular user password when using sudo for the first time each session (and periodically afterwards).
[warning]
Security Recommendation: While password authentication works, it's vulnerable to brute-force attacks. Attackers can attempt thousands of password combinations per hour. We strongly recommend switching to SSH key authentication as soon as possible.
To enhance your server's security, we strongly recommend setting up SSH keys instead of using password authentication. Follow our guide on setting up SSH keys on Ubuntu to learn how to configure key-based authentication.
If the root account uses SSH key authentication
If you logged in to your root account _using SSH keys_, then password authentication is _disabled_ for SSH. You will need to add a copy of your local public key to the new user's ~/.ssh/authorized_keys file to log in successfully.
Since your public key is already in the root account's ~/.ssh/authorized_keys file on the server, we can copy that file and directory structure to our new user account in our existing session.
The simplest way to copy the files with the correct ownership and permissions is with the rsync command. This will copy the root user's .ssh directory, preserve the permissions, and modify the file owners, all in a single command. Make sure to change the highlighted portions of the command below to match your regular user's name:
Note: The rsync command treats sources and destinations that end with a trailing slash differently than those without a trailing slash. When using rsync below, be sure that the source directory (~/.ssh) does not include a trailing slash (check to make sure you are not using ~/.ssh/).
If you accidentally add a trailing slash to the command, rsync will copy the _contents_ of the root account's ~/.ssh directory to the new user's home directory instead of copying the entire ~/.ssh directory structure. The files will be in the wrong location and SSH will not be able to find and use them.
rsync --archive --chown=sammy:sammy ~/.ssh /home/sammy
What this command does:
--archivepreserves permissions, timestamps, and other attributes
--chownchanges ownership to the new user
- Copies the entire
.sshdirectory structure with correct permissions
Verification: Check that the files were copied correctly:
ls -la /home/sammy/.ssh/
You should see authorized_keys with permissions -rw------- (read/write for owner only) and ownership set to your new user.
Now, open up a new terminal session on your local machine, and use SSH with your new username:
[environment local]
ssh sammy@your_server_ip
You should be logged in to the new user account without using a password. Remember, if you need to run a command with administrative privileges, type sudo before it like this:
sudo command_to_run
You will be prompted for your regular user password when using sudo for the first time each session (and periodically afterwards).
[success]
Success: Once you've confirmed you can log in as the new user and use sudo, you can safely log out of your root session. Your server is now configured with a non-root user and basic security measures.
Step 6 — (Optional) Hardening SSH Configuration
While the basic setup is secure, you can further harden SSH by disabling password authentication and root login. Only do this after confirming your SSH key access works, as misconfiguration can lock you out.
[warning]
Critical: Complete this step only after you've verified that:
- You can SSH into your new user account using SSH keys
- You can use
sudosuccessfully
- You have console/recovery access available as a backup
If you don't have console access and something goes wrong, you'll be locked out permanently.
Disabling Password Authentication
Once SSH key authentication is working, disable password authentication to prevent brute-force attacks:
sudo nano /etc/ssh/sshd_config
Find the line that says #PasswordAuthentication yes (it may be commented out) and change it to:
PasswordAuthentication no
Finding the Setting: Use Ctrl+W in nano to search for "PasswordAuthentication". The line may be commented with #—remove the # if present and change yes to no.
Disabling Root Login
For additional security, disable direct root login via SSH:
Find #PermitRootLogin yes or PermitRootLogin prohibit-password and change it to:
PermitRootLogin no
Understanding the Options:
PermitRootLogin yes: Allows root login with password (least secure)
PermitRootLogin prohibit-password: Allows root login only with SSH keys (moderate security)
PermitRootLogin no: Completely disables root login (most secure, recommended)
Since you have a sudo user, disabling root login is the safest option.
Applying Changes
After making changes, test the configuration for syntax errors:
sudo sshd -t
If there are no errors (no output), restart the SSH service:
sudo systemctl restart sshd
[warning]
Important: Test logging in with your new user from a new terminal before closing the original session.
Verification: In a new terminal, test SSH access:
[environment local]
ssh sammy@your_server_ip
If you can still log in, the configuration is correct. If you can't, use your console access to revert the changes.
Step 7 — (Optional) Additional Security Hardening
For production servers, consider these additional security measures:
Setting Up Automatic Security Updates
Ubuntu's unattended-upgrades package can automatically install security updates:
sudo apt update
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
Select "Yes" when prompted. This ensures critical security patches are applied automatically.
What Gets Updated: By default, unattended-upgrades only installs security updates, not regular package updates. This balances security with stability, preventing unexpected changes to your system.
Configuring Timezone
Set your server's timezone for accurate logging:
sudo timedatectl set-timezone America/New_York
Replace with your timezone. List available timezones with:
timedatectl list-timezones
Installing Fail2Ban (Optional)
Fail2Ban monitors logs and automatically bans IPs that show malicious behavior:
sudo apt install fail2ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
Fail2Ban works out of the box with default settings, but you can customize it in /etc/fail2ban/jail.local if needed.
Fail2Ban vs UFW: Fail2Ban provides application-level protection (banning IPs based on log patterns), while UFW provides network-level protection (blocking ports). They complement each other and can be used together.
Automation Tips for Repeatable Setups
If you manage multiple servers, automating the initial setup saves time and ensures consistency. Here are practical approaches:
Using a Bash Script
Create a setup script that you can run on new servers:
#!/bin/bash
# Save as: initial-setup.sh
USERNAME="sammy" # Change this
PUBLIC_KEY="ssh-rsa AAAAB3NzaC1yc2E..." # Your public key
# Create user
adduser --disabled-password --gecos "" $USERNAME
usermod -aG sudo $USERNAME
# Set up SSH
mkdir -p /home/$USERNAME/.ssh
echo "$PUBLIC_KEY" > /home/$USERNAME/.ssh/authorized_keys
chmod 700 /home/$USERNAME/.ssh
chmod 600 /home/$USERNAME/.ssh/authorized_keys
chown -R $USERNAME:$USERNAME /home/$USERNAME/.ssh
# Configure firewall
ufw allow OpenSSH
ufw --force enable
echo "Setup complete! User: $USERNAME"
Security: Never hardcode passwords or private keys in scripts. Use environment variables or secure secret management for sensitive data.
Using Cloud-Init (the cloud provider)
If you're using cloud servers, you can use cloud-init to automate setup. Create a user data script when creating your Droplet:
#cloud-config
users:
- name: sammy
sudo: ALL=(ALL) ALL
groups: sudo
shell: /bin/bash
ssh_authorized_keys:
- ssh-rsa AAAAB3NzaC1yc2E... your-public-key-here
package_update: true
package_upgrade: true
write_files:
- path: /etc/ssh/sshd_config.d/99-custom.conf
content: |
PasswordAuthentication no
PermitRootLogin no
owner: root:root
permissions: '0644'
runcmd:
- ufw allow OpenSSH
- ufw --force enable
NOPASSWD Warning: The NOPASSWD:ALL setting allows sudo without a password. While convenient for automation, consider removing it for production servers that require higher security.
Troubleshooting Common Issues
Issue: Locked Out of Droplet
Symptoms: Cannot SSH into your cloud servers, connection refused or timeout.
Solutions:
- Use the cloud provider Recovery Console: Access your Droplet through the the cloud provider Recovery Console. From the the cloud provider Control Panel, select your Droplet, click "Access" → "Recovery Console" to gain access and fix SSH configuration.
- Check Firewall Rules: If you enabled UFW without allowing SSH first, use the Recovery Console to fix it:
Note: The Recovery Console typically runs as root, so you may not need sudo for these commands.
# From Recovery Console access
ufw allow OpenSSH
ufw reload
- Verify SSH Service: Ensure SSH is running on your Droplet:
systemctl status sshd
systemctl start sshd # If stopped
- Check SSH Configuration: If you modified
/etc/ssh/sshd_configincorrectly:
sshd -t # Test configuration
nano /etc/ssh/sshd_config # Fix errors
systemctl restart sshd
- Verify Droplet Networking: Check if your Droplet's networking is functioning:
ip addr show
ping -c 3 8.8.8.8 # Test internet connectivity
Issue: Permission Denied (publickey)
Symptoms: SSH key authentication fails with "Permission denied (publickey)" when connecting to your Droplet.
Solutions:
- Verify SSH Key in the cloud provider: Ensure your SSH key is added to your cloud account and assigned to the Droplet. Check in the the cloud provider Control Panel under "SSH Keys".
- Verify Key Permissions on Droplet:
ls -la ~/.ssh/
# authorized_keys should be -rw------- (600)
# .ssh directory should be drwx------ (700)
- Fix Permissions:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
- Verify Key Format: Ensure your public key is in
authorized_keyscorrectly (one key per line, no extra spaces). the cloud provider automatically adds keys when you create a Droplet, but you may need to verify manually.
- Check SSH Logs on Droplet:
sudo tail -f /var/log/auth.log
# Try connecting from your local machine and watch for error messages
- Re-add SSH Key via Recovery Console: If needed, use the Recovery Console to manually add your public key to
~/.ssh/authorized_keys.
Issue: Sudo Asks for Password Repeatedly
Symptoms: Sudo prompts for password every time on your Droplet, even within the same session.
Solutions:
- Check Sudo Configuration: Verify your user is in the sudo group:
groups
# Should show "sudo" in the list
- Verify Sudoers File: Check that sudo group has proper permissions:
sudo visudo -c # Check sudoers syntax
grep -r "%sudo" /etc/sudoers /etc/sudoers.d/ # Find sudo group definition
# Should contain: %sudo ALL=(ALL:ALL) ALL
- Check Sudo Timestamp: Verify sudo timestamp file permissions:
ls -la /var/lib/sudo/ts/
# Should be readable by your user
Issue: Firewall Blocking Legitimate Traffic
Symptoms: Services work locally on your Droplet but not from external connections.
Solutions:
- Check the cloud provider Cloud Firewall: If you're using the cloud provider Cloud Firewalls, verify rules in the Control Panel. Ensure you're not using both Cloud Firewall and UFW simultaneously, as this can cause conflicts.
- List Current UFW Rules:
sudo ufw status verbose
- Allow Required Ports:
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
sudo ufw allow 3306/tcp # MySQL (if needed)
- Check Application Profiles:
sudo ufw app list
sudo ufw allow 'Nginx Full' # Example
- Verify Droplet Firewall Settings: In the the cloud provider Control Panel, check your Droplet's networking settings to ensure no additional firewall rules are blocking traffic.
Testing Firewall Rules: Use ufw status numbered to see rules with numbers, then ufw delete [number] to remove incorrect rules. If using the cloud provider Cloud Firewalls, manage rules through the Control Panel instead.
Frequently Asked Questions
The first three steps are: (1) create a non-root user with sudo privileges, (2) configure SSH key authentication, and (3) enable the UFW firewall. These steps establish basic security and prevent common attack vectors. Complete these before installing any applications or services.
Use adduser username to create the user, then usermod -aG sudo username to grant sudo privileges. Verify with sudo -l -U username to confirm the user can run sudo commands. Always test sudo access before logging out of your root session.
Yes, for production servers, disabling root login is recommended. Once you have a working sudo user with SSH key access, set PermitRootLogin no in /etc/ssh/sshd_config. This prevents attackers from targeting the root account directly. Keep console access available as a backup.
The essential steps are: (1) use SSH key authentication instead of passwords, (2) disable password authentication in /etc/ssh/sshd_config, (3) disable root login, and (4) consider changing the default SSH port (though this provides minimal security through obscurity). For advanced hardening, implement fail2ban and configure SSH to use specific ciphers and key exchange algorithms.
UFW (Uncomplicated Firewall) is the recommended firewall for Ubuntu. It provides a simple interface for managing iptables rules and includes application profiles for common services. For cloud providers like the cloud provider, you can also use cloud-level firewalls, but avoid using both simultaneously to prevent rule conflicts.
Install and configure unattended-upgrades: sudo apt install unattended-upgrades && sudo dpkg-reconfigure -plow unattended-upgrades. This automatically installs security patches without manual intervention. Review /etc/apt/apt.conf.d/50unattended-upgrades to customize which updates are installed.
Yes, you can use the same SSH public key on multiple servers by adding it to each server's ~/.ssh/authorized_keys file. However, for better security, consider using different keys for different servers or environments (development, staging, production). Use SSH agent forwarding or a key management system for teams.
UFW is a frontend for iptables that simplifies firewall management. Under the hood, UFW generates iptables rules, but you don't need to write iptables syntax directly. Use UFW for simplicity; use iptables directly only if you need advanced features that UFW doesn't support.
Add each public key as a new line in ~/.ssh/authorized_keys. Each key should be on its own line with no blank lines between them. This allows multiple users (or the same user from different machines) to access the account using different keys.
First, use the console/recovery access to access your server. Once logged in, check SSH service status by using the command (sudo systemctl status sshd), verify firewall rules (ufw status), and review SSH configuration (sudo sshd -t). Fix any misconfigurations, then test SSH access from a new terminal before closing the console session.
Conclusion
You now have a fully configured Ubuntu 20.04 server with secure SSH access, a firewall in place, automatic updates enabled, and basic hardening applied. This baseline setup significantly reduces common attack vectors while keeping the system easy to maintain.
From here, your focus should shift to production readiness. That means deploying application services, enabling automated backups, monitoring system health, and adding layered security controls such as Fail2Ban and two-factor authentication where appropriate.
A properly configured foundation saves time, prevents outages, and avoids costly recovery scenarios later. Treat this setup as your standard operating baseline for every new server you deploy.
Next Steps
At this point, you have a solid foundation for your server. You can install any of the software you need on your server now. Here are some recommended next steps:
- Set up SSH keys if you haven't already, for more secure authentication
- Install and configure a web server like Nginx or Apache
- Set up a database like MySQL or PostgreSQL
- Configure automatic backups to protect your data
- Set up monitoring and logging to track server health
For additional security hardening, consider:
- Installing and configuring fail2ban to prevent brute-force attacks
- Setting up two-factor authentication for SSH
- Configuring log monitoring to track system events