Initial VPS Configuration Guide: Building a solid foundation for your web application

Table of contents
- Rent Your Virtual Private Server (VPS).
- Secure Your Root Account.
- Create a Non-Root User
- Enhance Security with SSH Keys.
- Install and Configure UFW (Uncomplicated Firewall).
- Set the Correct Timezone and Locale.
- Enable SSH Rate Limiting with Fail2ban.
- Install Malware/Rootkit Scanners.
- Uninstall Default Applications (If Unnecessary).
- Set Up Your Hostname.
- Install NGINX (Reverse Proxy for Dockerized Apps).

Using a Virtual Private Server (VPS) offers a powerful and budget-friendly way to gain full control over your hosting environment. Whether you're making your first deployment or migrating from shared hosting to something more robust, a proper initial setup makes all the difference. This guide will walk you through getting your new VPS ready—secure, optimized, and prepared for deploying your applications, especially if you're aiming for a Dockerized setup. If you aim to deploy your web app without using Docker, check out this guideline Host .NET 8 Asp Net Core and Blazor on Linux VPS
You can skip some steps if you want to and choose what's best for you.
Rent Your Virtual Private Server (VPS).
The first step is to choose a reputable hosting provider. Popular options include DigitalOcean, Vultr, and Hetzner. When selecting a plan, consider your application's resource requirements:
CPU: More cores generally translate to better performance, crucial if you anticipate significant traffic or compute-intensive tasks.
RAM: Ample memory ensures your applications run smoothly, preventing slowdowns and crashes under load.
Storage: Opt for SSD (Solid State Drive) storage for significantly faster read/write speeds, which benefits database operations and application loading times. Ensure you have enough capacity for your application files, databases, and any future growth.
Bandwidth: Important if your application handles a large volume of data transfers, such as file downloads, streaming media, or high traffic.
For a small application or testing environment, a basic plan might suffice. However, for larger or production-ready applications, investing in a more powerful plan from the start can save you headaches down the line and ensure a scalable foundation.
Secure Your Root Account.
Upon initial login to your new VPS (usually as the root
user), the very first thing you should do is change the default password. This is a critical security measure as default passwords are often weak or publicly known.
To change it, simply type:
passwd
You'll be prompted to enter your new password twice. Choose a strong, unique password that combines uppercase and lowercase letters, numbers, and symbols.
Create a Non-Root User
Working directly as the root
user is a significant security risk. The root
user has absolute control over the system, and a single misplaced command can lead to irreversible damage. To mitigate this, it's a best practice to create a new, unprivileged user for your day-to-day operations and grant it sudo
privileges for administrative tasks. This aligns with the principle of "least privilege" and contributes to a more secure and maintainable system.
To create a new user (replace myusername
with your desired username):
adduser myusername
Follow the prompts to set a strong password for this new user and fill in any additional information (you can usually press Enter to skip these if not needed).
Next, grant this new user sudo
permissions, allowing them to execute commands with root
privileges when necessary, by prefixing the command with sudo
.
usermod -aG sudo myusername
Now, you can log out of the root
user and log in as myusername
. From this point forward, you'll use sudo
for any administrative operations.
Enhance Security with SSH Keys.
After changing your password, the next level of security involves disabling password-based SSH logins entirely and exclusively using SSH keys. SSH keys provide a much stronger authentication mechanism, making brute-force password attacks virtually impossible. This is a fundamental step in securing your server.
Step-by-Step SSH Key Setup:
Generate an SSH key on your local machine: Open your local terminal and generate a new SSH key pair.
ed25519
is the modern and recommended algorithm due to its strong security and smaller key sizes, butrsa
is also an option.ssh-keygen -t ed25519
Press
Enter
when prompted for a file to save the key (it will default to~/.ssh/id_ed25519
) and when asked for a passphrase. While a passphrase adds an extra layer of security, it means you'll need to enter it every time you use the key. For convenience, many users opt not to set one for their primary key, but consider it for higher-security scenarios.Copy the public key to your server: This command securely copies your public key (
id_
ed25519.pub
) to theauthorized_keys
file on your VPS, allowing you to log in with your key. Replacemyusername
andyour-server-ip
with your actual details.ssh-copy-id myusername@your-server-ip
You will be asked for your
myusername
's password one last time.Test your SSH key login: Before proceeding, try logging in to your VPS using your new user and SSH key to ensure it works correctly.
ssh myusername@your-server-ip
If successful, you should be logged in without being prompted for a password.
Disable password login on the server: Once you've confirmed SSH key login works, edit the SSH daemon configuration file to disallow password authentication. This significantly hardens your server against unauthorized access.
sudo nano /etc/ssh/sshd_config
Find the line
PasswordAuthentication yes
and change it to:PasswordAuthentication no
You might also want to ensure
PermitRootLogin no
is set to prevent direct root logins via SSH, forcing you to use your non-root user and thensudo
if needed.Save and exit nano (Ctrl+O, Enter, Ctrl+X).
Restart the SSH service: Apply the changes by restarting the SSH service.
sudo systemctl restart ssh
Now, your server is much more secure, relying solely on cryptographic SSH keys for authentication.
Install and Configure UFW (Uncomplicated Firewall).
A firewall is your server's first line of defense, controlling what network traffic is allowed in and out. UFW (Uncomplicated Firewall) is a user-friendly front-end for iptables
, making it easier to manage firewall rules. It's critical to configure your firewall before deploying any applications.
Here's a safe baseline configuration, ideal for web applications:
sudo ufw default deny incoming # Deny all incoming connections by default
sudo ufw default allow outgoing # Allow all outgoing connections by default
sudo ufw allow OpenSSH # Allow SSH connections (port 22)
sudo ufw allow 80/tcp # Allow HTTP traffic (port 80)
sudo ufw allow 443/tcp # Allow HTTPS traffic (port 443)
sudo ufw enable # Enable the firewall
You'll be asked to confirm enabling the firewall; type y
and press Enter.
To verify your firewall's status and rules:
sudo ufw status verbose
This setup allows essential services while blocking all other unsolicited incoming connections, significantly reducing your server's attack surface.
Set the Correct Timezone and Locale.
Proper timezone and locale settings are essential for accurate logging, scheduling tasks, and ensuring your applications behave as expected across different geographical locations.
Timezone Configuration:
Set your server's timezone. For example, if you are in Jakarta, Indonesia, you'd set it to Asia/Jakarta
.
sudo timedatectl set-timezone Asia/Jakarta
Verify the change:
timedatectl
This command will display current system time, RTC time, and your configured timezone.
Locale Configuration:
The locale determines the language, character encoding, and cultural conventions for your system. For most English-speaking systems, en_US.UTF-8
is a common and robust choice.
Check your current locale:
locale
If you need to set a new one:
sudo update-locale LANG=en_US.UTF-8
You can list all available locales with:
locale -a
After changing the locale, it's best to log out and log back in to ensure the changes are fully applied to your session.
Enable SSH Rate Limiting with Fail2ban.
Fail2ban is a powerful intrusion prevention framework that scans log files (like those for SSH, web servers, etc.) for repeated failed login attempts and automatically bans the offending IP addresses for a specified period. This is an excellent defense against brute-force attacks.
Installation:
sudo apt update
sudo apt install fail2ban -y
Basic Configuration:
Copy the default configuration file to a local override. This is a best practice, as it ensures your custom settings won't be overwritten during future
fail2ban
package updates.sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
Edit the local configuration file:
sudo nano /etc/fail2ban/jail.local
Look for the
[sshd]
section. Ensure it is enabled and review themaxretry
andbantime
settings:Ini, TOML
[sshd] enabled = true port = ssh filter = sshd logpath = %(sshd_log)s maxretry = 5 ; How many failed attempts allowed before banning bantime = 1h ; How long to block the IP (e.g., 1h for 1 hour, 1d for 1 day)
The
port
setting typically defaults tossh
(which resolves to port 22). If you've changed your SSH port, update this accordingly.maxretry
defines the number of failed attempts before a ban, andbantime
specifies the duration of the ban.Save and exit nano.
Restart and Enable Fail2ban:
sudo systemctl restart fail2ban sudo systemctl enable fail2ban # Ensure it starts on boot
Check Status:
sudo fail2ban-client status sudo fail2ban-client status sshd
These commands will show you the active jails and any currently banned IPs for the SSH service. Fail2ban will now diligently monitor
/var/log/auth.log
(or your configured log path) and automatically ban repeat SSH failures, significantly enhancing your server's security posture.
Install Malware/Rootkit Scanners.
While your primary defense should be proactive security measures, having tools to detect compromises is also vital. rkhunter
(Rootkit Hunter) is a popular utility for scanning for rootkits, backdoors, and other potential vulnerabilities.
sudo apt install rkhunter -y && \
sudo rkhunter --update && \
sudo rkhunter --propupd && \
sudo rkhunter --check
--update
: Updates the data files used byrkhunter
.--propupd
: Updates the file properties database. You should run this after a fresh install or major system updates to prevent false positives.--check
: Performs the actual scan.
You should re-run sudo rkhunter --check
regularly as part of your server maintenance routine to check for new issues.
Uninstall Default Applications (If Unnecessary).
Many VPS providers pre-install common application stacks like LAMP (Linux, Apache, MySQL, PHP) to get users up and running quickly. However, if you plan to deploy your applications using Docker, these pre-installed components are often redundant and can introduce conflicts or unnecessary attack surfaces. Removing them provides a cleaner environment and ensures Docker has full control over application orchestration.
Here's how to remove common default software on an Ubuntu-based VPS:
# Stop and Remove Apache
sudo systemctl stop apache2
sudo apt remove --purge apache2 apache2-utils apache2-bin apache2.2-common
# Stop and Remove MySQL (if installed directly, not in Docker)
sudo systemctl stop mysql
sudo apt remove --purge mysql-server mysql-client mysql-common
# Stop and Remove MariaDB (if installed directly, not in Docker)
sudo systemctl stop mariadb
sudo apt remove --purge mariadb-server mariadb-client
# Remove PHP and its modules (if installed directly)
sudo apt remove --purge php*
# Clean up any residual packages and orphaned dependencies
sudo apt autoremove
sudo apt autoclean
How to check what's installed:
If you're unsure what services are running or installed, you can use dpkg -l
to list packages and grep
to filter for specific ones:
dpkg -l | grep apache
dpkg -l | grep mysql
dpkg -l | grep php
dpkg -l | grep mariadb
Remove anything that's not explicitly needed for your Dockerized environment. This contributes to a "clean architecture" for your server itself, reducing clutter and potential vulnerabilities.
Set Up Your Hostname.
When you first provision your VPS, it's often assigned a generic hostname. It's good practice to map this properly within your system for easier identification and to ensure services that rely on hostname resolution function correctly.
Check your current hostname:
hostname
Edit your
/etc/hosts
file: This file maps hostnames to IP addresses locally on your server.sudo nano /etc/hosts
Look for a line that might resemble
127.0.1.1 oldhostname
and update it to reflect your VPS provider's assigned hostname, or a custom one if you prefer. For example:127.0.1.1 your-vps-hostname
Also, ensure you have the standard localhost entry:
127.0.0.1 localhost
So, a typical
/etc/hosts
file will look something like this:127.0.0.1 localhost 127.0.1.1 your-vps-hostname # The following lines are desirable for IPv6 capable hosts ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters
💡Important Note: This/etc/hosts
mapping only affects local name resolution within your VPS. External clients will still need to use your domain name (with proper DNS records configured at your domain registrar) to reach your server.Save and exit nano (Ctrl+O, Enter, Ctrl+X).
Install NGINX (Reverse Proxy for Dockerized Apps).
NGINX is an incredibly versatile and high-performance web server that excels as a reverse proxy. For modern, Docker-based application deployments, NGINX is almost indispensable.
Why use NGINX?
Reverse Proxy: It acts as a single entry point for all incoming web traffic, routing requests to the appropriate Docker containers based on rules you define. This decouples your application containers from direct public exposure, enhancing security.
Load Balancing: NGINX can distribute incoming traffic across multiple instances of your application (e.g., multiple Docker containers), improving scalability and fault tolerance.
Static File Serving: It's highly efficient at serving static assets (HTML, CSS, JavaScript, images), offloading this task from your application containers.
SSL Termination: NGINX can handle SSL/TLS encryption and decryption, allowing your application containers to run on plain HTTP internally, simplifying their configuration.
Security: By sitting in front of your application, NGINX can filter malicious requests and provide an additional layer of defense.
In a Dockerized setup, NGINX often serves as the public-facing component, directing requests to your backend services running in containers. This aligns perfectly with a "clean architecture" by clearly separating concerns.
Installation:
sudo apt update
sudo apt install nginx
After installation, verify that NGINX is running:
sudo systemctl status nginx
You should see output indicating that the service is active (running)
.
Enable NGINX to start automatically on boot:
sudo systemctl enable nginx
To test if NGINX is working, open your VPS's IP address in a web browser. You should see the default NGINX welcome page, confirming that your web server is operational.
Subscribe to my newsletter
Read articles from Kristiadhy directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Kristiadhy
Kristiadhy
Experienced Full Stack .NET developer with a proven track record of designing and implementing robust business applications. Proficient in using ASP.NET Core Web API, Blazor, and WinForms to deliver high-quality, efficient code and scalable solutions. Strong focus on implementing industry best practices for cleaner and scalable outcomes.