Emma Larsson
VPS Technical LeadEmma Larsson is a lead systems developer and virtualization specialist with a decade of expertise in kernel configurations and hypervisor scaling.
Setting up your first VPS server is one of the most rewarding steps you can take as a website owner, developer, or aspiring sysadmin — and it is also one of the most intimidating. The moment you move beyond the managed comfort of shared hosting into the world of root access, command-line configuration, and unmanaged infrastructure, you trade convenience for control. That trade-off pays dividends in performance, flexibility, and long-term cost efficiency, but only if you navigate the initial setup correctly. At Hosting Captain, we have walked thousands of beginners through their first VPS deployment across every major provider, operating system, and software stack, and the process that produces consistently successful results follows a clear, repeatable sequence of twelve steps. This walkthrough covers every one of those steps in order — from choosing and ordering a plan to pointing a domain and installing a free SSL certificate — with the exact commands you need to run, explanations of what each command does and why it matters, and the pitfalls that trip up newcomers at each stage. If you are still deciding whether a VPS is the right upgrade path for your project, our VPS hosting guide covers the fundamentals, including how virtualization works, how resources are allocated, and how VPS compares to shared and dedicated alternatives. For a deeper technical perspective on how VPS technology isolates resources at the hypervisor level, the Wikipedia VPS article provides a thorough historical and architectural overview.
Before we dive into the terminal, let us establish what this walkthrough assumes. We are targeting a freshly provisioned VPS running Ubuntu Server 22.04 or 24.04 LTS — the most popular Linux distribution for first-time VPS users by a wide margin — and we are building a LEMP stack: Linux, Nginx, MySQL (MariaDB), and PHP. Every command in this guide has been tested across DigitalOcean, Vultr, Linode, and Hostinger VPS instances, and they will work identically on any provider that gives you root SSH access to a standard Ubuntu image. If you choose a different distribution — Debian, AlmaLinux, Rocky Linux — the package manager commands differ (apt vs dnf), but the conceptual steps remain the same, and we note the equivalents where relevant. This walkthrough assumes no prior command-line experience beyond the ability to open a terminal, and we explain every concept as we introduce it.
The VPS plan you choose on day one determines everything about your server's performance ceiling for the lifetime of that deployment, and picking the wrong tier is the most expensive mistake a beginner can make — because you either pay monthly for resources you never use, or worse, you launch on an under-provisioned plan and suffer crashes, slow page loads, and Out-Of-Memory kills that drive visitors away before you even build an audience. The key specifications to evaluate are RAM, storage type and capacity, vCPU count, and bandwidth allocation. For a single dynamic website — a WordPress blog, a small Laravel application, a portfolio with a CMS backend — a plan with 2 GB of RAM, 1 vCPU, and 40–50 GB of NVMe SSD storage is the minimum comfortable entry point that leaves headroom for the operating system, web server, database, and occasional traffic spikes. Plans with 1 GB of RAM exist and are cheaper, but they leave almost no margin after the base operating system consumes roughly 300–500 MB, and attempting to run MySQL or MariaDB alongside any application stack on 1 GB will trigger the Linux Out-Of-Memory killer within the first week of normal operation.
Storage type matters more than storage capacity for database-driven workloads. A 50 GB NVMe SSD will deliver query response times that are 3x to 10x faster than a 100 GB SATA SSD because NVMe bypasses the SATA controller bottleneck and handles far more input/output operations per second. If your provider offers an NVMe upgrade for a few extra dollars per month, that upgrade is almost always the single highest-ROI improvement you can make to a dynamic website. Bandwidth allocation — typically measured in terabytes per month — is rarely the binding constraint for new sites, but our VPS bandwidth guide explains how to estimate your transfer needs and what happens when you exceed your allocation, including the overage fees and throttling policies that vary dramatically between providers.
When placing your order, you will encounter several configuration choices beyond the plan tier. Choose a data center location geographically closest to your primary audience — latency adds roughly 1 millisecond per 100 kilometers of network distance, and while that sounds small, it compounds across dozens of assets per page load and directly affects your Core Web Vitals scores and search rankings. Most providers let you select the operating system at checkout; choose Ubuntu 22.04 LTS or 24.04 LTS for the widest compatibility with tutorials, package availability, and community support. If your provider offers additional services — automated backups, managed database instances, monitoring add-ons — you can safely skip them during the initial order and enable them later once your server is configured and you understand the cost implications. The one exception is automated backups: if the add-on costs $1–$3 per month and stores snapshots off-server, it is worth enabling from day one, because having a restore point when you inevitably misconfigure something during the learning process can save hours of reconstruction work.
After payment processes, your VPS provider provisions your virtual machine — a process that typically takes between 30 seconds and five minutes depending on the provider's infrastructure load and whether they use pre-built images or install the operating system from scratch. Once provisioning completes, you will receive an email or a control panel notification containing four critical pieces of information: your server IP address (a public IPv4 address like 203.0.113.45), your root username (almost always root), your root password (either one you set during checkout or a randomly generated string provided by the provider), and optionally an IPv6 address if your provider supports dual-stack networking. Store these credentials securely — a password manager is ideal — because losing the root password on a provider that does not offer console-based password reset means rebuilding the server from scratch.
If you selected Ubuntu 22.04 LTS or 24.04 LTS during checkout, you are in the best possible position for a first VPS deployment. Ubuntu's Long Term Support releases receive five years of security patches from Canonical, its package repositories contain current versions of Nginx, MySQL, PHP, and Certbot, and the volume of community documentation, Stack Overflow answers, and tutorial content written for Ubuntu dwarfs every other distribution combined. Ubuntu 24.04 LTS (Noble Numbat) ships with newer kernel versions and updated package repositories compared to 22.04, and if your provider offers it, choose 24.04 for the longer remaining support window. Debian 12 (Bookworm) is an excellent alternative if you prefer a more conservative distribution with fewer pre-installed packages and a slower release cadence. AlmaLinux 9 and Rocky Linux 9 are the RHEL-compatible options for users coming from a CentOS background, but their smaller community footprint and dnf-based package management mean you will spend more time translating commands from the Ubuntu-centric tutorials that dominate search results. Whatever distribution you choose, the moment your credentials arrive, you are ready to connect.
SSH — Secure Shell — is the encrypted protocol that lets you execute commands on your remote VPS as if you were sitting at a physical terminal connected directly to the machine. Every modern operating system includes an SSH client, though the exact tool and invocation differ between platforms. This section covers connection from Windows, macOS, and Linux workstations, because beginners arrive from all three ecosystems and the first connection is often where frustration peaks if the instructions do not match the operating system in front of you.
Recent versions of Windows 10 and Windows 11 include the OpenSSH client built into both PowerShell and the Command Prompt — no third-party software required. Open PowerShell by right-clicking the Start button and selecting "Windows PowerShell" or "Terminal," then type the following command, replacing 203.0.113.45 with your server's actual IP address:
The first time you connect to a new server, SSH displays a fingerprint warning: "The authenticity of host '203.0.113.45' can't be established." This is expected behavior, not an error. Type yes and press Enter to add the server's host key to your known_hosts file, which prevents man-in-the-middle attacks on future connections. You will then be prompted for the root password — type or paste it carefully (the terminal will not show any characters as you type, which is normal) and press Enter. If the password is accepted, you will see a welcome banner and a command prompt ending in root@your-server:~#, indicating you are logged in as the root user with full administrative privileges.
An alternative that many Windows users prefer is PuTTY, a free, lightweight SSH client with a graphical interface. Download PuTTY from its official website, enter your server's IP address in the "Host Name" field, ensure port 22 is selected and the connection type is SSH, and click "Open." PuTTY handles the host key verification through a dialog box rather than a terminal prompt. For users who anticipate frequent file transfers between their local machine and the VPS, WinSCP provides a dual-pane graphical file manager that uses the same SSH protocol, making it easy to drag and drop files without learning command-line transfer tools.
macOS and Linux both ship with the OpenSSH client accessible directly from the Terminal application. On macOS, open Terminal from Applications → Utilities, or search for it with Spotlight (Command + Space, type "Terminal"). On Linux, the terminal emulator varies by desktop environment — GNOME Terminal, Konsole, or xfce4-terminal — but the command is identical across all of them:
Accept the host key fingerprint by typing yes, enter the root password when prompted, and you will be dropped into a root shell on your VPS. At this point, regardless of which operating system you connected from, you are looking at the same server environment and can follow the remaining steps identically.
The operating system image your provider used to provision your VPS is a snapshot that may be weeks or months old. In the time since that snapshot was captured, the Ubuntu security team has almost certainly published patches for the Linux kernel, system libraries, and core utilities — and the window between a vulnerability disclosure and active exploitation in the wild can be measured in hours. Your first action after connecting should be updating every installed package to the latest version available in the distribution repositories.
Run the following two commands in sequence. The first refreshes the local package index — the list of what software is available and what version — from Ubuntu's remote repositories. The second upgrades every installed package to the newest version in that index:
apt update
apt upgrade -y
The -y flag automatically answers "yes" to the confirmation prompt, which is safe because we are upgrading existing packages rather than installing new software. Depending on how outdated the provisioned image was, this may take anywhere from thirty seconds to several minutes as packages are downloaded and unpacked. If a kernel update is included, you will see messages about rebuilding the initramfs — this is normal, and the new kernel will take effect on the next reboot. On some providers, you may also want to set the correct timezone for your server, which ensures log timestamps and cron job schedules align with your local expectations:
timedatectl set-timezone America/Chicago
Replace America/Chicago with your actual timezone — run timedatectl list-timezones to see the full list of valid values. If your server's clock is significantly wrong, correct it by enabling NTP synchronization with timedatectl set-ntp true, which keeps the clock accurate automatically. With the system fully updated and the clock set correctly, we can move on to the security hardening steps that must be completed before any application software is installed.
Logging in directly as root means that any command you run — and any command a compromised application or an attacker who guesses your password runs — executes with unrestricted access to the entire filesystem. The principle of least privilege dictates that you should create a dedicated user account for day-to-day administration and reserve root access for the rare operations that genuinely require it. The sudo mechanism allows your non-root user to execute privileged commands by prefixing them with sudo and entering the user's own password, providing both an audit trail and a deliberate step between a routine command and a potentially destructive one.
Create the new user with the adduser command, replacing emma with the username of your choice — choose something that is not easily guessable by automated brute-force scripts, avoiding names like "admin," "webmaster," "deploy," or your first name:
adduser emma
You will be prompted to set a password for the new user and optionally fill in contact information fields — you can press Enter to leave those blank. Next, add the new user to the sudo group, which grants the ability to execute commands with administrative privileges:
usermod -aG sudo emma
The -aG flags mean "append to group" rather than "set group membership to," which prevents accidentally removing the user from other groups. To verify the user was added correctly, you can switch to the new account:
su - emma
Once logged in as the new user, test that sudo works by running sudo whoami — it should prompt for the user's password and then print root, confirming that the account can execute commands with elevated privileges. Type exit to return to the root shell. From this point forward, you should perform all server administration as this non-root user rather than as root directly, because the extra friction of typing sudo before every privileged command has prevented countless catastrophic mistakes — accidentally running rm -rf / as root deletes the entire filesystem, while the same command without sudo simply fails with a permission error.
Password-based SSH authentication is the weakest link in most VPS security postures. No matter how complex your password, it remains susceptible to brute-force guessing, credential-stuffing from third-party data breaches, and shoulder-surfing. SSH key pairs solve this by using asymmetric cryptography: your private key stays on your local machine and never leaves it, while the public key sits on the server. Even if an attacker intercepts the authentication handshake, they cannot derive your private key from the public half.
The setup process has two halves. First, on your local machine — not the VPS — generate an Ed25519 key pair. Ed25519 is the modern recommendation over RSA because it offers equivalent security with shorter keys and faster authentication handshakes. Open a terminal on your local computer and run:
ssh-keygen -t ed25519 -C "[email protected]"
You will be prompted for a file location (press Enter to accept the default ~/.ssh/id_ed25519) and a passphrase. Adding a passphrase encrypts your private key at rest, meaning that even if someone steals your laptop and copies the key file, they cannot use it without the passphrase. Choose a strong passphrase that you can remember — a password manager can store it if needed. The command creates two files: id_ed25519 (your private key — never share this) and id_ed25519.pub (your public key — this goes on the server).
Second, copy the public key to your VPS. On macOS and Linux, the ssh-copy-id utility handles this in one command (replace emma with your actual username and the IP address with your server's):
ssh-copy-id [email protected]
On Windows, the OpenSSH client includes ssh-copy-id in recent versions, but if it is not available, you can manually append the public key by displaying its contents locally and then, on the VPS, creating the necessary directory and file. On your local Windows machine, display the public key with type $env:USERPROFILE\.ssh\id_ed25519.pub in PowerShell. Copy the output. Then on the VPS (still logged in as root or your new user), run:
mkdir -p ~/.ssh
echo "paste-the-public-key-content-here" >> ~/.ssh/authorized_keys
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
The permission commands are critical: SSH will refuse to use an authorized_keys file that is readable by anyone other than its owner, because a world-readable key file means any other user on the system could add their own key and gain access to your account.
Once the public key is in place, test that key-based authentication works by opening a new terminal window on your local machine and connecting with ssh [email protected]. If everything is configured correctly, you will either be logged in immediately (if you did not set a passphrase) or prompted for your key's passphrase. Do not close your existing root session yet — if the key-based login fails, you need the password-based session to debug the issue. Once you confirm key-based login works, harden the SSH daemon by editing its configuration file:
sudo nano /etc/ssh/sshd_config
Find and modify (or add) the following directives:
PasswordAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
These three settings collectively disable password logins (eliminating the brute-force vector entirely), prevent anyone from logging in directly as root (forcing all administrative actions through sudo for audit trail purposes), and ensure public key authentication remains enabled. After saving the file, restart the SSH daemon to apply the changes:
sudo systemctl restart sshd
Before closing your existing session, open a third terminal window and verify that you can still connect with your key. If the connection is refused, the configuration change introduced an error — and since you never closed the original session, you can revert the change and fix it without being locked out. This "always test in a separate terminal before closing the working session" habit has saved more VPS deployments than any other single piece of advice we give at Hosting Captain.
A firewall is a gatekeeper that controls which network traffic reaches the services running on your server. The correct posture for any internet-facing server is default-deny: block all inbound connections except for the specific ports your applications require, and explicitly allow those ports one by one. UFW — Uncomplicated Firewall — is Ubuntu's user-friendly interface to the Linux kernel's netfilter subsystem, and it reduces what would otherwise be dozens of iptables commands to a handful of intuitive directives.
Begin by checking whether UFW is already installed and setting the default policies:
sudo ufw default deny incoming
sudo ufw default allow outgoing
The first command tells the firewall to reject all inbound connection attempts unless explicitly permitted. The second allows all outbound connections, which is the standard configuration because your server needs to reach out to package repositories, API endpoints, and update servers without restriction. Next, explicitly allow the services and ports you need. At minimum, you need SSH access and HTTP/HTTPS web traffic:
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
If you changed the SSH port from 22 to a non-standard port as an additional security measure — for example, port 2200 — adjust the first rule accordingly with sudo ufw allow 2200/tcp. Before enabling the firewall, review your rule set to confirm everything looks correct:
sudo ufw status verbose
The output should show Status: inactive followed by your configured rules. Once you are satisfied, activate the firewall:
sudo ufw enable
You will be prompted to confirm because enabling a firewall over an SSH connection carries the risk of locking yourself out if you forgot to allow the SSH port. Confirm with y. Run sudo ufw status again — it should now show Status: active with your allowed ports listed. At this point, the only ports reachable from the public internet are 22 (SSH), 80 (HTTP), and 443 (HTTPS). Every other service — including any database, development server, or internal tool you install later — is blocked by default and can only be accessed from within the server itself or by adding an explicit UFW rule.
Nginx (pronounced "Engine-X") is the most widely deployed web server on the modern internet, powering over 34% of all websites according to W3Techs' 2025 survey, and it has decisively overtaken Apache as the default recommendation for new VPS deployments. Nginx's event-driven, asynchronous architecture handles thousands of concurrent connections within a fraction of the memory that Apache's process-per-connection model requires, making it particularly well-suited to VPS environments where RAM is the binding resource constraint. If you have a specific reason to prefer Apache — compatibility with .htaccess files in a legacy application, for example — the package name and service commands differ, but the fundamental configuration logic is the same. For developers who want a pre-configured stack tailored to staging and testing workflows, our VPS staging environments guide covers how to build disposable development mirrors that replicate production exactly.
Install Nginx from Ubuntu's default repositories:
sudo apt install nginx -y
Once the installation completes, Nginx starts automatically as a system service. Verify it is running with:
sudo systemctl status nginx
The output should show active (running) in green. At this point, if you open a web browser and navigate to http://your-server-ip (replacing with your actual IP address), you should see the default Nginx welcome page — a white screen with "Welcome to nginx!" centered in the browser window. This page is served from /var/www/html/index.nginx-debian.html and confirms that the web server is installed, running, and reachable through the firewall you configured in the previous step. If the page does not load, check that UFW is allowing port 80 (sudo ufw status) and that Nginx is binding to the correct network interface (sudo ss -tlnp | grep nginx should show port 80 in a LISTEN state).
Enable Nginx to start automatically when the server reboots — this should already be configured, but it is worth confirming:
sudo systemctl enable nginx
At this stage, the web server is serving static files from the default document root. In the next section, we will layer on PHP processing and a MySQL database, turning this static file server into a full application platform capable of running WordPress, Laravel, or any custom PHP application.
The LEMP stack gets its dynamism from PHP — the server-side scripting language that processes requests, queries databases, and generates the HTML that Nginx delivers to browsers — and MySQL (or its drop-in replacement, MariaDB), the relational database that stores your content, user accounts, and application state. On Ubuntu 22.04 and 24.04, the package manager installs MariaDB when you request the mysql-server package, because Ubuntu transitioned its default MySQL package to MariaDB several releases ago. MariaDB is fully compatible with MySQL at the wire protocol and SQL syntax level, and it offers performance advantages in several workloads thanks to its alternative storage engines and optimizer improvements.
Install PHP-FPM — the FastCGI Process Manager that allows Nginx to pass PHP requests to a dedicated process pool — along with the MySQL extension and several other commonly needed modules:
sudo apt install php-fpm php-mysql php-curl php-gd php-mbstring php-xml php-zip -y
Each extension serves a specific purpose: php-mysql provides the database connectivity layer; php-curl enables HTTP requests from within PHP (used by countless plugins and API integrations); php-gd handles image processing (thumbnail generation, watermarking); php-mbstring provides multibyte string functions necessary for UTF-8 content in non-English languages; php-xml enables XML and RSS parsing; and php-zip allows PHP to create and extract ZIP archives, which is required by WordPress plugin and theme installers. Verify that PHP-FPM is running:
sudo systemctl status php8.3-fpm
The version number in the service name (8.3 on Ubuntu 24.04, 8.1 on Ubuntu 22.04) depends on which PHP version your distribution ships. If the service name does not match, list all PHP-related services with sudo systemctl list-units | grep php to find the correct name. PHP-FPM listens on a Unix socket by default — typically at /run/php/php8.3-fpm.sock — which Nginx will communicate with directly, avoiding the overhead of a TCP connection to localhost.
Install the database server:
sudo apt install mariadb-server -y
After installation, run the included security script, which walks through several critical hardening steps:
sudo mysql_secure_installation
The script will prompt you through several questions. Answer as follows: set a strong root password (if prompted — on newer Ubuntu versions, the root account uses Unix socket authentication by default, which is more secure); remove anonymous users (y); disallow root login remotely (y); remove the test database (y); and reload the privilege tables (y). These five steps close the most common attack vectors that automated scanners probe for on newly provisioned servers. Next, verify that MariaDB is binding only to the local loopback interface — this ensures the database port 3306 is not reachable from the public internet:
sudo ss -tlnp | grep mysql
The output should show the process listening on 127.0.0.1:3306 or localhost:3306, not 0.0.0.0:3306. If it shows 0.0.0.0, edit the MariaDB configuration file at /etc/mysql/mariadb.conf.d/50-server.cnf, set bind-address = 127.0.0.1, and restart the service with sudo systemctl restart mariadb. With PHP and MariaDB both installed, running, and secured, the full LEMP stack is operational. The final step is to configure Nginx to pass PHP requests to PHP-FPM — which we will do as part of deploying the test website in the next section.
With every layer of the stack installed, it is time to verify that they work together by deploying a simple PHP page that confirms Nginx can process PHP, connect to MariaDB, and return a dynamically generated response. This test page is deliberately minimal — it proves the plumbing works end to end, and it will be replaced by your actual application (WordPress, Laravel, a custom site) once the foundation is confirmed.
First, create a directory for your website. The conventional location under Nginx is /var/www/ followed by your domain name — but since we have not pointed a domain yet, we will use a placeholder directory name:
sudo mkdir -p /var/www/mysite
Set the ownership of this directory to your non-root user so you can edit files without sudo:
sudo chown -R emma:emma /var/www/mysite
Create a simple PHP info page that connects to MariaDB and displays server details:
nano /var/www/mysite/index.php
Paste the following content into the editor:
<?php
echo "<h1>Your VPS is working!</h1>";
echo "<p>PHP version: " . phpversion() . "</p>";
try {
$db = new PDO('mysql:host=localhost;charset=utf8mb4', 'root', '');
echo "<p style='color:green'>MariaDB connection: OK</p>";
} catch (PDOException $e) {
echo "<p style='color:red'>MariaDB connection failed: " . htmlspecialchars($e->getMessage()) . "</p>";
}
echo "<p>Server time: " . date('Y-m-d H:i:s') . " UTC</p>";
Save the file (Ctrl+O, Enter, Ctrl+X in nano). Now create an Nginx server block — the equivalent of an Apache virtual host — that tells Nginx where to find your site files and how to process PHP requests:
sudo nano /etc/nginx/sites-available/mysite
Add the following configuration:
server {
listen 80;
server_name _;
root /var/www/mysite;
index index.php index.html;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
}
The server_name _ directive is a catch-all that matches any hostname — useful before a domain is pointed. The fastcgi_pass line must reference the correct PHP-FPM socket path for your Ubuntu version: /run/php/php8.3-fpm.sock on Ubuntu 24.04, or /run/php/php8.1-fpm.sock on Ubuntu 22.04. Adjust the version number to match your installation.
Enable the server block by creating a symbolic link from sites-available to sites-enabled, then test and reload Nginx:
sudo ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
The nginx -t command performs a configuration syntax check — always run this before reloading, because a typo in a config file will prevent Nginx from starting and take your site offline. If the test passes, visit http://your-server-ip/ in a browser. You should see "Your VPS is working!" followed by the PHP version, a green "MariaDB connection: OK" message, and the current server time. This single page confirms that Nginx is receiving requests, passing PHP files to PHP-FPM for execution, and that PHP can successfully connect to MariaDB — the entire LEMP stack is operational.
Important security note: The test page above uses a passwordless root database connection, which works because MariaDB on Ubuntu uses Unix socket authentication for the root user by default. For any production application, you must create a dedicated database and user with a strong password. The test page should be deleted or made inaccessible before your site goes live, because exposing phpversion() and database status to the public internet is an information disclosure risk.
A website accessible only by IP address is a proof of concept, not a launch. Pointing a domain name to your VPS involves configuring DNS records at your domain registrar — the company where you purchased the domain — to translate the human-readable domain name into your server's IP address. The process is the same regardless of whether you bought your domain from Namecheap, GoDaddy, Google Domains, Cloudflare, or any other registrar, though the exact navigation path through their control panels differs.
Log into your domain registrar's control panel and locate the DNS management section — it may be labeled "DNS Settings," "Manage DNS," "DNS Zone," "Name Server Management," or something similar. You need to create two types of records. First, an A record (Address record) that points your root domain to the server's IPv4 address. The host field should be @ (representing the bare domain, e.g., example.com), the type should be A, the value should be your server's IPv4 address, and the TTL (Time to Live) can be left at the default or set to 300 seconds (5 minutes) for faster propagation during initial setup. Second, a CNAME record (Canonical Name record) that points the www subdomain to your root domain, so that visitors who type www.example.com are redirected to the same server. The host should be www, the type CNAME, and the value @ or your bare domain name.
If your VPS provider also assigned you an IPv6 address, create an AAAA record with the host @, type AAAA, and value set to the IPv6 address. This ensures IPv6-capable visitors can reach your server directly over the newer protocol. After saving the records, DNS propagation begins — the process by which your changes spread across the global network of DNS resolvers. Propagation typically takes between a few minutes and 48 hours, though most registrars' changes are visible within 30 minutes to 2 hours. You can check whether propagation has reached your location by running nslookup example.com or dig example.com from your local terminal and verifying that the returned IP address matches your server's.
Once DNS resolves correctly, update your Nginx server block to recognize the domain name. Edit /etc/nginx/sites-available/mysite and change the server_name directive from _ to your actual domain:
server_name example.com www.example.com;
Test and reload Nginx:
sudo nginx -t
sudo systemctl reload nginx
Now navigate to http://example.com (using your actual domain) in a browser. If you see the test page from Step 10, your domain is correctly pointing to your VPS and Nginx is serving the right content for the right hostname.
An SSL certificate encrypts the data flowing between your visitors' browsers and your server, preventing anyone on the network path — ISPs, public Wi-Fi operators, malicious actors — from reading or modifying the traffic. Beyond security, SSL is a practical necessity: browsers flag unencrypted HTTP sites with "Not Secure" warnings that erode visitor trust, and Google uses HTTPS as a positive ranking signal in search results. Let's Encrypt, a free, automated certificate authority operated by the Internet Security Research Group, issues domain-validated SSL certificates that are trusted by every major browser and operating system. Certbot, developed by the Electronic Frontier Foundation, automates the process of obtaining and renewing Let's Encrypt certificates.
Install Certbot and its Nginx plugin:
sudo apt install certbot python3-certbot-nginx -y
The Nginx plugin allows Certbot to automatically read your Nginx configuration, identify the domains being served, and modify the server block to include the SSL certificate paths and HTTPS redirection rules. Run Certbot with the Nginx plugin and follow the interactive prompts:
sudo certbot --nginx
Certbot will ask for an email address (used for renewal notices and urgent security notifications), prompt you to agree to the Let's Encrypt terms of service, and optionally ask whether you want to subscribe to the EFF's mailing list. It will then list the domain names found in your Nginx configuration and ask which ones to enable HTTPS for — typically all of them. For the final question, choose whether to redirect HTTP traffic to HTTPS: selecting option 2 ("Redirect") means every visitor who types http://example.com is automatically sent to https://example.com, which is the recommended configuration for production sites.
Certbot modifies your Nginx configuration automatically, adding the SSL certificate and private key paths, enabling modern TLS protocols, and inserting the redirect rules. After the process completes, visit https://example.com — you should see a padlock icon in the browser address bar, confirming the connection is encrypted and the certificate is valid. You can verify your SSL configuration's security grade by running your domain through the Qualys SSL Labs Server Test, which evaluates your TLS configuration against a comprehensive set of criteria and grades it from A+ to F. A properly configured Certbot Nginx installation typically scores an A.
The critical final step is understanding that Let's Encrypt certificates expire after 90 days. Certbot installs a systemd timer or cron job during installation that automatically checks for certificates nearing expiration twice daily and renews them as needed. Verify that the auto-renewal timer is active:
sudo systemctl status certbot.timer
If the timer is not active, enable and start it:
sudo systemctl enable certbot.timer
sudo systemctl start certbot.timer
Perform a dry run to confirm that renewal will work when the time comes:
sudo certbot renew --dry-run
If the dry run completes without errors, your certificate will renew automatically in the background without any manual intervention. The most common cause of renewal failure is a firewall blocking port 80, because Let's Encrypt's HTTP-01 challenge requires inbound access to port 80 to verify domain ownership. Your UFW configuration in Step 7 explicitly allows port 80, so this should not be an issue, but it is worth confirming if renewal ever fails.
At this point, your VPS is fully operational: a secure, updated operating system running behind a firewall, with SSH restricted to key-based authentication, a production-grade LEMP stack installed and confirmed working, a domain pointed and resolving, and a free SSL certificate encrypting all traffic with automatic renewal. From this foundation, you can install WordPress, Laravel, a static site generator, a custom application, or any other software that runs on Linux, Nginx, MySQL, and PHP. You have complete control over every layer of the stack, and you own the skills to maintain and extend it. If your project grows to the point where a single VPS can no longer handle the load — whether due to traffic volume, storage requirements, or the need for guaranteed hardware isolation — our dedicated server guide explains the upgrade path and the cost and performance trade-offs at each tier. For developers who want to use their VPS for testing and deployment pipelines, our VPS staging guide walks through building disposable environments that mirror production without risking the live site.
No prior command-line experience is required to follow this walkthrough. Every command is provided verbatim, and each step explains what the command does and why it matters. The initial learning curve for basic VPS administration — navigating directories, editing files with nano, managing services with systemctl — is measured in days, not weeks, and the skills you build are transferable across every Linux-based hosting environment you will encounter in the future. If you can copy and paste commands into a terminal and read error messages when something does not work as expected, you have the prerequisites to complete this guide. That said, patience is the unspoken requirement: server configuration involves precise syntax where a single missing semicolon can cause a service to fail, and the ability to methodically retrace your steps and identify where a configuration drifted from the instructions is more valuable than any specific technical background.
Entry-level VPS plans suitable for the walkthrough above — 2 GB RAM, 1 vCPU, 40–50 GB NVMe SSD — cost between $5 and $12 per month at the standard (non-promotional) rate across major providers in 2025–2026. Hostinger's KVM VPS plans start around $5–$7 per month, Vultr and DigitalOcean at approximately $12 per month, and Linode's dedicated-core plans at roughly $12 per month at this tier. European providers like Hetzner offer even lower base pricing (around €4–€6 per month) but with data centers concentrated in Europe. Be aware that most providers advertise introductory discounts that slash the first-term price by 40–60%, but the renewal rate is the number you should budget against, because that is the price you will pay for every subsequent billing cycle.
For a first-time user following this walkthrough, budget two to three hours from placing the order to seeing a working test website with SSL enabled at your domain. The time breaks down roughly as follows: 5–10 minutes for provider provisioning and credential delivery, 20–30 minutes for initial updates and user creation, 20–30 minutes for SSH key setup and firewall configuration (this step often takes longest for beginners because it involves switching between local and remote terminals), 30 minutes for installing and configuring Nginx, PHP, and MariaDB, 30 minutes for the test website deployment and Nginx configuration, 15 minutes for DNS changes (plus propagation waiting time, which happens in the background), and 15 minutes for SSL installation. Subsequent VPS deployments, once you have internalized the process, can be completed in under 30 minutes.
The most common mistake is locking themselves out of the server by misconfiguring SSH — disabling password authentication before confirming that key-based login works, changing the SSH port and forgetting to update the firewall, or restarting the SSH daemon with a syntax error in the configuration file. The mitigation is the rule we emphasize throughout this guide: always test the new configuration in a separate terminal window before closing the existing working session. A second, equally pervasive mistake is skipping the firewall configuration entirely because the server "works without it." An un-firewalled VPS is probed by automated attack scripts within minutes of coming online, and leaving database ports, Redis instances, or development servers exposed to the public internet is an invitation to be compromised. Run sudo ufw status right now — if it does not say active, stop everything else and configure your firewall before proceeding.
Yes, but with significant caveats. Control panels like cPanel, Plesk, CyberPanel, and aaPanel can be installed on a VPS and provide a graphical interface for managing websites, databases, email accounts, and SSL certificates. However, they consume substantial system resources — cPanel alone can use 500 MB to 1 GB of RAM before any websites are hosted — and they add a recurring license cost (cPanel licenses for VPS start around $15–$20 per month). For beginners who want a graphical management layer without the resource and cost overhead of a full control panel, Webmin and Virtualmin offer free, lightweight alternatives, and CloudPanel provides a modern, Docker-free interface specifically designed for Debian and Ubuntu. If you ultimately prefer the managed experience where someone else handles the command line entirely, a managed VPS plan — where the provider maintains the operating system, security patches, and control panel — bridges the gap between self-managed VPS and shared hosting.
Ubuntu Server LTS is the strongest recommendation for a first VPS because its documentation footprint, community support volume, and tutorial coverage exceed every other distribution combined. Nearly every VPS tutorial, Stack Overflow answer, and hosting blog post assumes Ubuntu as the target environment, which means you will spend less time translating apt commands to dnf or resolving package name differences. Debian 12 is an excellent alternative if you prefer a more conservative distribution that changes less between releases. CentOS Stream, AlmaLinux, and Rocky Linux are strong choices if your workplace or application requires RHEL compatibility, but their smaller community means more time spent troubleshooting on your own. Ubuntu 24.04 LTS, released in April 2024, will receive security updates through April 2029, giving you a five-year window before you need to consider a distribution upgrade — plenty of time to build confidence and evaluate alternatives at your own pace.
Emma Larsson is a lead systems developer and virtualization specialist with a decade of expertise in kernel configurations and hypervisor scaling.







