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:
| Region | Typical Audience | Starter Tier (KVM1) | Mid Tier (KVM2) | Monthly Cost | Best Fit |
|---|---|---|---|---|---|
| Atlanta, US | US East / Southeast | 1 vCPU / 1 GB / 20 GB NVMe | 2 vCPU / 2 GB / 25 GB NVMe | $10–$20 | US East audience, SaaS landing pages |
| Los Angeles, US | US West / Pacific | 1 vCPU / 1 GB / 20 GB NVMe | 2 vCPU / 2 GB / 25 GB NVMe | $10–$20 | West Coast audience, APAC-facing projects |
| Frankfurt, Germany | Central Europe | 1 vCPU / 1 GB / 20 GB NVMe | 2 vCPU / 2 GB / 25 GB NVMe | $10–$20 | EU-wide audience, GDPR-friendly hosting |
| Amsterdam, Netherlands | Western Europe | 1 vCPU / 1 GB / 20 GB NVMe | 2 vCPU / 2 GB / 25 GB NVMe | $10–$20 | UK, Benelux & Nordics traffic |
| Singapore | Southeast Asia | 1 vCPU / 1 GB / 20 GB NVMe | 2 vCPU / 2 GB / 25 GB NVMe | $10–$20 | APAC audience, SG/MY/ID/PH visitors |
| Tokyo, Japan | East Asia / Pacific | 1 vCPU / 1 GB / 20 GB NVMe | 2 vCPU / 2 GB / 25 GB NVMe | $10–$20 | JP/KR/TW audience, gaming, streaming |
| Mumbai, India | South Asia | 1 vCPU / 1 GB / 20 GB NVMe | 2 vCPU / 2 GB / 25 GB NVMe | $10–$20 | Indian 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:
| Type | Name / Host | Value / Points to | TTL |
|---|---|---|---|
| A | @ | `203.0.113.10` | 300 |
| AAAA | @ | `2001:db8:abcd:12::10` | 300 |
| A | www | `203.0.113.10` | 300 |
| AAAA | www | `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.