🇯🇵 Tokyo is live! 🚀 Launch your VPS and enjoy 2 months off — use code KONNICHIWA50 🎉 Get Started Today →

How to Self Host a Website in 2026: A Complete VPS Setup Guide

Laptop connected to a server stack and cloud, illustrating data storage and cloud computing on a dark blue background.

Your first decision is to choose a server that meets your traffic needs without paying for idle resources. For most indie sites and small projects, a small VPS works well: 1 vCPU, 1 GB RAM, and 20 GB NVMe storage will comfortably run a static site, brochure site, or a lightweight CMS such as Ghost or a Hugo export. If you expect higher resource usage with WooCommerce, many WordPress plugins, or occasional traffic spikes from newsletters, start at 2 vCPUs and 2 GB RAM so that PHP workers, database queries, and background tasks have dedicated resources. With a self-hosting approach on VPS.US, you can precisely match resources with your needs without paying for idle capacity.

Latency matters. If your readers are in the US and your server is in Frankfurt, every request must traverse an ocean before the page renders. Choose the node closest to your main audience—a reduction of round-trip time by 30–60 ms can be more noticeable than adding another CPU core. For many sites, placing the VPS on a low-latency node is key to achieving sub-100 ms server response times.

Here’s a simple scoring framework:

  • Latency: 50%
  • Price: 30%
  • Resources: 20%

In plain language, a cheaper server is not a bargain if it introduces visible delays to your pages.

Step 1: Picking Your Region

VPS.US operates 17 locations worldwide. The table below shows how to select a region based on your audience location:

RegionTypical AudienceStarter Tier (KVM1)Mid Tier (KVM2)Monthly CostBest Fit
Atlanta, USUS East / Southeast1 vCPU / 1 GB / 20 GB NVMe2 vCPU / 2 GB / 25 GB NVMe$10–$20US East audience, SaaS landing pages
Los Angeles, USUS West / Pacific1 vCPU / 1 GB / 20 GB NVMe2 vCPU / 2 GB / 25 GB NVMe$10–$20West Coast audience, APAC-facing projects
Frankfurt, GermanyCentral Europe1 vCPU / 1 GB / 20 GB NVMe2 vCPU / 2 GB / 25 GB NVMe$10–$20EU-wide audience, GDPR-friendly hosting
Amsterdam, NetherlandsWestern Europe1 vCPU / 1 GB / 20 GB NVMe2 vCPU / 2 GB / 25 GB NVMe$10–$20UK, Benelux & Nordics traffic
SingaporeSoutheast Asia1 vCPU / 1 GB / 20 GB NVMe2 vCPU / 2 GB / 25 GB NVMe$10–$20APAC audience, SG/MY/ID/PH visitors
Tokyo, JapanEast Asia / Pacific1 vCPU / 1 GB / 20 GB NVMe2 vCPU / 2 GB / 25 GB NVMe$10–$20JP/KR/TW audience, gaming, streaming
Mumbai, IndiaSouth Asia1 vCPU / 1 GB / 20 GB NVMe2 vCPU / 2 GB / 25 GB NVMe$10–$20Indian subcontinent traffic

The full location list includes Paris, Stockholm, Riga, Warsaw, Vilnius, Madrid, Sofia, Palermo, Moscow, Fujairah (UAE), and Lagos (Nigeria)—so wherever your users are, there is likely a nearby node.

In the control panel, create a new VPS and make only four choices: OS, region, plan, and SSH key. Choose Ubuntu 24.04 LTS unless you already standardize on another Linux distribution. LTS means long-term support with security updates for years without major version changes. Pick the region from the table, select the smallest plan that suits your site type, and upload your SSH public key to enable secure, password-free login.

If the panel asks for a hostname, use a simple name like `web-01`. Once your server is provisioned and you have its public IP, connect the server to a domain so visitors can find it.

Step 2: Register Your Domain and Configure DNS

Once your VPS is online, purchase a domain from any trusted registrar. In your registrar’s DNS panel, add records for both the root domain and `www`. A typical configuration is as follows:

TypeName / HostValue / Points toTTL
A@`203.0.113.10`300
AAAA@`2001:db8:abcd:12::10`300
Awww`203.0.113.10`300
AAAAwww`2001:db8:abcd:12::10`300

Enter your VPS’s public IPv4 address in the A records and IPv6 in the AAAA records for both `@` and `www` to ensure visitors reach the same server regardless of the method they use to enter your domain.

For more guidance on backups during a self-hosting setup, read our article on Self Hosted Backup Software: Tools, Setup, and Best Practices.

If your registrar’s DNS panel shows additional fields such as Proxy, Priority, or Alias, keep them at their default settings. A low TTL of 300 seconds instructs DNS resolvers to update changes quickly.

A quick Bash example for automated DNS record creation via an API:

curl -X POST "https://api.example.com/v1/dns/records" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '[
{"type":"A","name":"@","content":"203.0.113.10","ttl":300},
{"type":"AAAA","name":"@","content":"2001:db8:abcd:12::10","ttl":300},
{"type":"A","name":"www","content":"203.0.113.10","ttl":300},
{"type":"AAAA","name":"www","content":"2001:db8:abcd:12::10","ttl":300}
]'

Test the records with:

dig +short A example.com
dig +short AAAA example.com

You should see your VPS IPs, one per line.

Step 3: Perform Initial Server Setup and Hardening

Before installing a web server, secure your VPS. Start by updating the OS, avoid using the root account daily, and open only the essential ports. Failing to do so results in a functional but vulnerable default Linux installation.

Update and Install Utilities

Connect to the server via SSH as the default user or root, then update Ubuntu 24.04 and install essential tools:

apt update && apt full-upgrade -y
apt install -y curl git ufw
reboot

This sequence ensures that your server is up-to-date. Verify the installations with:

curl --version
git --version
ufw version

User and SSH Hardening

Create a non-root admin account with sudo privileges for elevated tasks without logging in as root:

adduser deploy
usermod -aG sudo deploy
rsync --archive --chown=deploy:deploy ~/.ssh /home/deploy

Test the new account in a separate terminal session:

ssh deploy@your_server_ip
sudo whoami
rsync --archive --chown=deploy:deploy ~/.ssh /home/deploy

If the output is `root` (after entering your password), the login is successful. Then, disable direct root SSH login by editing the SSH configuration:

sudo nano /etc/ssh/sshd_config

Change or add the following line:

PermitRootLogin no

Reload SSH:

sudo systemctl reload ssh

Verify with:

sudo sshd -t
grep -E '^PermitRootLogin' /etc/ssh/sshd_config

Firewall Configuration

Enable the firewall and allow only SSH and web traffic (ports 22, 80, and 443):

sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status

The status should show that the firewall is active with the correct rules listed.

Step 4: Install and Configure NGINX Web Server

After securing your server, install NGINX. NGINX listens on port 80 and serves files or proxies requests to another application:

sudo apt update
sudo apt install -y nginx
sudo systemctl enable --now nginx

Verify the service with:

systemctl status nginx --no-pager
curl -I http://your_server_ip

Create a document root and add a test page:

sudo mkdir -p /var/www/html
echo '<h1>It works</h1>' | sudo tee /var/www/html/index.html

Configure a server block for your site. This block instructs NGINX which domain to serve, where your files are stored, and the default index file:

server {
    listen 80;
    listen [::]:80;
    server_name yourdomain.com www.yourdomain.com;

    root /var/www/html;
    index index.html index.htm;

    location / {
        try_files $uri $uri/ =404;
    }
}

Save this configuration as `/etc/nginx/sites-available/yourdomain.com`, enable it, and remove the default configuration:

sudo nano /etc/nginx/sites-available/yourdomain.com
sudo ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default

Test the configuration and reload NGINX:

sudo nginx -t
sudo systemctl reload nginx

Verify with:

curl -I http://yourdomain.com
curl http://yourdomain.com

You should receive an HTTP 200 response along with the test page content.

Step 5: Deploy Your Website Content

The test page confirms that NGINX is working. Replace it with your actual website files so that visiting `yourdomain.com` displays your homepage.

For a static site (HTML, CSS, JavaScript, or exported files from Hugo, Astro, or Next.js), transfer the files into `/var/www/html`. It is recommended to upload them to a temporary directory first and then copy only the final built files.

Use these commands to deploy your content and set proper permissions:

# Upload your built static site folder from your local machine
scp -r ./dist/* deploy@your_server_ip:/tmp/site/

# Or clone your site repository directly on the server
ssh deploy@your_server_ip
git clone https://github.com/yourname/your-site.git /tmp/site

# Replace the test page with your actual site files
sudo rm -f /var/www/html/index.html
sudo cp -r /tmp/site/* /var/www/html/

# Set ownership so NGINX can properly serve the files
sudo chown -R www-data:www-data /var/www/html

# Set directory (755) and file (644) permissions
sudo find /var/www/html -type d -exec chmod 755 {} \;
sudo find /var/www/html -type f -exec chmod 644 {} \;

Verify the deployment:

ls -la /var/www/html
curl http://yourdomain.com

If your homepage HTML is displayed correctly, then NGINX is serving your site as expected.

Step 6: Secure Your Site with Let’s Encrypt SSL

Although your site currently works over HTTP, browsers will mark it as untrusted until HTTPS is enabled. Secure your site by using Certbot with the NGINX plugin to obtain a free TLS certificate from Let’s Encrypt.

Install Certbot and its NGINX plugin:

sudo apt update
sudo apt install -y certbot python3-certbot-nginx

sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

# Verify the renewal timer is active
sudo systemctl status certbot.timer --no-pager
sudo systemctl enable --now certbot.timer

# Optional: create a cron fallback to reload NGINX after renewal
echo '0 3 * * * root certbot renew --quiet --deploy-hook "systemctl reload nginx"' | \
  sudo tee /etc/cron.d/certbot-custom

# Test the renewal process
sudo certbot renew --dry-run

During the Certbot process, you’ll be prompted for your email, agreement to the terms, and whether to redirect HTTP traffic to HTTPS. Choosing the redirect option modifies your NGINX configuration automatically.

After completion, verify HTTPS:

sudo nginx -t
curl -I http://yourdomain.com
curl -I https://yourdomain.com

A 301 or 308 redirect on HTTP and a 200 OK response on HTTPS indicates a secure site.

Step 7: Automate Backups of Your Website and Config

Regular backups protect against accidental deletions, configuration errors, or hardware failures. For a self-hosted site, a backup should include your web root (`/var/www/html`) and the NGINX configuration (`/etc/nginx`).

You can send backups to any S3-compatible object storage using a tool like rclone.

Install rclone and configure your remote:

# Install rclone
curl https://rclone.org/install.sh | sudo bash
rclone version

# Configure your S3-compatible remote (interactive wizard)
rclone config
# Name it "backup", choose "s3", enter your endpoint, keys, and bucket

Create a backup script to archive your site and upload it:

sudo nano /usr/local/bin/site-backup.sh
sudo chmod 700 /usr/local/bin/site-backup.sh

Insert the following script:

#!/usr/bin/env bash
set -euo pipefail

BACKUP_DIR="/var/backups/site"
DATE="$(date +%F-%H%M%S)"
HOSTNAME="$(hostname -s)"
ARCHIVE="${BACKUP_DIR}/${HOSTNAME}-${DATE}.tar.gz"
REMOTE="backup:your-backup-bucket/website/"

mkdir -p "$BACKUP_DIR"

tar -czf "$ARCHIVE" /var/www/html /etc/nginx

rclone copy "$ARCHIVE" "$REMOTE"

find "$BACKUP_DIR" -type f -name "*.tar.gz" -mtime +7 -delete
sudo /usr/local/bin/site-backup.sh
rclone ls backup:your-backup-bucket/website/

Finally, schedule the script via cron to run daily at 2:15 AM (crontab -e) :

15 2 * * * /usr/local/bin/site-backup.sh >> /var/log/site-backup.log 2>&1

Step 8: Test, Monitor, and Maintain Your Website

Backups protect your data, and monitoring ensures your site remains live, secure, and performs as expected. Begin by checking HTTP redirection, HTTPS response, and certificate validity:

curl -I http://yourdomain.com
curl -I https://yourdomain.com
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com </dev/null 2>/dev/null | openssl x509 -noout -issuer -subject -dates

For local monitoring, create a health check script:

sudo nano /usr/local/bin/site-healthcheck.sh
sudo chmod 700 /usr/local/bin/site-healthcheck.sh

Insert the following script:

#!/usr/bin/env bash
URL="https://yourdomain.com"
if ! curl -fsS --max-time 10 "$URL" > /dev/null; then
  echo "$(date -Is) health check failed for $URL" >> /var/log/site-healthcheck.log
fi

Test the script:

sudo /usr/local/bin/site-healthcheck.sh
tail -n 5 /var/log/site-healthcheck.log

Then, schedule it every 5 minutes with cron:

*/5 * * * * /usr/local/bin/site-healthcheck.sh

Maintenance Checklist

  • [ ] Confirm that `curl -I http://yourdomain.com` returns a redirect to HTTPS.
  • [ ] Confirm that `curl -I https://yourdomain.com` returns 200 OK.
  • [ ] Validate the SSL certificate using `openssl x509 -noout -dates`.
  • [ ] Set up an external uptime monitor for `https://yourdomain.com`.
  • [ ] Weekly: Review NGINX logs and disk usage using `df -h`.
  • [ ] Monthly: Apply security updates with `sudo apt update && sudo apt upgrade -y` and test SSL renewal with `sudo certbot renew –dry-run`.
  • [ ] Monthly: Verify backup uploads and perform a restore test.
  • [ ] Quarterly: Remove unused packages using `sudo apt autoremove -y`.

With these steps, your self-hosted VPS on VPS.US will be live, secure, and ready to grow.

Facebook
Twitter
LinkedIn

Table of Contents

Get started today

With VPS.US VPS Hosting you get all the features, tools

Image