By Brian Boucheron and Vinayak Baranwal

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.
When you create a DigitalOcean Droplet, 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 DigitalOcean, see our product documentation.
Before diving into the step-by-step process, here are the essential concepts you’ll learn:
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.
Before you begin, ensure you have:
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.
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):
- 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.
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:
rm -rf / instead of rm -rf ./).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.
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:
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.
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 addWithout -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.
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.
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 DigitalOcean, you can optionally use DigitalOcean 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
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.
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 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:
- 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).
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 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:
--archive preserves permissions, timestamps, and other attributes--chown changes ownership to the new user.ssh directory structure with correct permissionsVerification: 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:
- 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. <$>
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.
Critical: Complete this step only after you’ve verified that:
sudo successfullyIf you don’t have console access and something goes wrong, you’ll be locked out permanently.
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.
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.
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
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:
- 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.
For production servers, consider these additional security measures:
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.
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
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.
If you manage multiple servers, automating the initial setup saves time and ensures consistency. Here are practical approaches:
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.
If you’re using DigitalOcean Droplets, 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.
Symptoms: Cannot SSH into your DigitalOcean Droplet, connection refused or timeout.
Solutions:
Use DigitalOcean Recovery Console: Access your Droplet through the DigitalOcean Recovery Console. From the DigitalOcean 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_config incorrectly:
- 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
Symptoms: SSH key authentication fails with “Permission denied (publickey)” when connecting to your Droplet.
Solutions:
Verify SSH Key in DigitalOcean: Ensure your SSH key is added to your DigitalOcean account and assigned to the Droplet. Check in the DigitalOcean 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_keys correctly (one key per line, no extra spaces). DigitalOcean 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.
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
Symptoms: Services work locally on your Droplet but not from external connections.
Solutions:
Check DigitalOcean Cloud Firewall: If you’re using DigitalOcean 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 DigitalOcean 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 DigitalOcean Cloud Firewalls, manage rules through the Control Panel instead.
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 DigitalOcean, 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.
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.
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:
For additional security hardening, consider:
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
Senior Technical Writer at DigitalOcean
Building future-ready infrastructure with Linux, Cloud, and DevOps. Full Stack Developer & System Administrator. Technical Writer @ DigitalOcean | GitHub Contributor | Passionate about Docker, PostgreSQL, and Open Source | Exploring NLP & AI-TensorFlow | Nailed over 50+ deployments across production environments.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
I have made a bash script to automate the setup process, hopefully this will be useful to someone else.
Followed all the steps for SSH key authentication but after the last step as root user
rsync –archive –chown=anthony:anthony ~/.ssh /home/anthony and opening a new tab in my terminal, I still had to enter my passphrase after running ssh anthony@xxx.xx.xxx.xxx
After filling in my passphrase I’m getting Connection closed by xxx.xx.xxx.xxx port 22
The last command as root should be:
$ rsync --archive --chown=sammy:sammy /root/.ssh/ /home/sammy/.ssh/
Otherwise the authorized_keys file is created in the user’s home folder.
go through all this and then try to login with the user created in the install and it doesn’t work. I’ve done it 3 times and each time I get the same result. I can’t login with those credentials. Has something changed since you wrote these instructions? Or perhaps it would have been better to give various ways of installing, which you made reference to, instead of ONLY including the install process YOU believe is the best. Choices should be offered so users can choose which path they wish to take. As it is at the moment though, your tutorial fails.
Worked flawlessly for me. I expected an extra step though. Once I have my own user, with my own name, I would like to disable the root user completely.
The usermod -aG sudo sammy command didn’t work for me, weirdly. I also tried gpasswd -a sammy sudo. I ended up having to manually add my user to the /etc/sudoers file like so:
# User privilege specification
root ALL=(ALL:ALL) ALL
sammy ALL=(ALL:ALL) ALL
Warning: As explained here, you shouldn’t edit this file with a normal text editor (but I did, because yolo).
@bboucheron I followed the steps of this tutorial exactly on a completely fresh Ubuntu 20.04 droplet, so the tutorial might need updating? Could just be that my droplet was haunted. Very strange that a very basic command like usermod wouldn’t work though.
Edit: Tested on another fresh 20.04 server and had the same problem - very strange. I also tried upgrading all packages with apt upgrade, and then trying usermod again, but no luck.
Hello,
For anyone interested, I just created a similar video demo on how to do the initial server setup as described in this tutorial:
Hope that this helps!
Regards, Bobby
This comment has been deleted
After executing this command: rsync --archive --chown=sammy:sammy ~/.ssh /home/sammy
I am still asked for a password. Note that my ssh key file is named differently, it is not named id_rsa.
I know that on login I need to add the -i flag to indicate the name of the file, and this worked when logging in as root user, but not for this new user, please help.
I’m logging in with this: ssh -i /home/MY_USER/.ssh/MYUSER_id_rsa MY_USER@MY.DROPLET.IP.ADDRESS
Where MY_USER is the name of the user I created, and notice my ssh key file is renamed, it is not id_rsa
I’m getting this error: Warning: Identity file /home/MY_USER/.ssh/MYUSER_id_rsa not accessible: No such file or directory.
Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.
Full documentation for every DigitalOcean product.
The Wave has everything you need to know about building a business, from raising funding to marketing your product.
Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.
New accounts only. By submitting your email you agree to our Privacy Policy
Scale up as you grow — whether you're running one virtual machine or ten thousand.
Sign up and get $200 in credit for your first 60 days with DigitalOcean.*
*This promotional offer applies to new accounts only.