I’m Henry, the author of this blog, and I want to show you how I’d actually set up a private VPS server for a website.
Not the “click three buttons and everything magically works” version.
I mean the real setup: SSH, users, Nginx, DNS, SSL, firewall rules, updates, backups, and a few things that are easy to forget until something breaks at 2 AM.
If you’re comfortable with the command line, this is a useful project to build. And honestly, managing your own server is one of those things where you learn a lot very quickly.
Sometimes the server teaches you.
Sometimes it teaches you with an error message that makes absolutely no sense.
What We’re Building
By the end, the setup will look roughly like this:
Domain
|
v
DNS
|
v
VPS Public IP
|
v
Nginx
|
+---- HTTPS
|
+---- Website
|
+---- Application
I’ll use Ubuntu Server in the examples, but the same ideas apply to most Linux VPS environments.
You’ll need:
- A VPS with root access
- Ubuntu Server
- A domain name
- SSH access
- A website or web application
- A little patience
That last one is optional, but highly recommended.
1. Connect to the VPS
After creating the VPS, you’ll normally receive its public IP address.
Connect through SSH:
ssh root@YOUR_SERVER_IP
The first thing I’d do is create a normal user instead of doing everything as root.
adduser henry
usermod -aG sudo henry
Then test the new account:
su - henry
sudo whoami
If the output is:
root
you’re good.
Running everything as root because it’s “faster” is one of those shortcuts that feels clever right up until you accidentally delete something important.
2. Update the Server
Before installing anything, update the package lists and existing packages:
sudo apt update
sudo apt upgrade -y
I also like checking whether the server needs a reboot:
[ -f /var/run/reboot-required ] && echo "Reboot required"
If necessary:
sudo reboot
Reconnect after the server comes back.
3. Set Up SSH Properly
SSH is going to be one of your main doors into the server, so don’t leave it wide open.
Ideally, use SSH keys instead of password authentication.
From your local machine:
ssh-keygen -t ed25519
Copy the public key to the VPS:
ssh-copy-id henry@YOUR_SERVER_IP
Then test:
ssh henry@YOUR_SERVER_IP
Once key authentication is working, you can disable password authentication in the SSH configuration.
Open:
sudo nano /etc/ssh/sshd_config
Look for:
PasswordAuthentication yes
Change it to:
PasswordAuthentication no
Then validate and restart SSH:
sudo sshd -t
sudo systemctl restart ssh
Always test another SSH session before closing your current one.
That little habit can save you from locking yourself out of your own server.
4. Configure the Firewall
Ubuntu commonly uses UFW for basic firewall management.
First:
sudo ufw default deny incoming
sudo ufw default allow outgoing
Allow SSH:
sudo ufw allow OpenSSH
Then allow web traffic:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
Enable it:
sudo ufw enable
Check the rules:
sudo ufw status verbose
You generally don't want random application ports exposed to the internet.
For example, if your application listens internally on port 3000, there’s usually no reason to expose 3000 publicly when Nginx can proxy requests to it.
5. Install Nginx
Now we need something to actually serve the website.
Install Nginx:
sudo apt install nginx -y
Check whether it is running:
sudo systemctl status nginx
You can also enable it at boot:
sudo systemctl enable nginx
Open the VPS IP in a browser.
If you see the Nginx welcome page, congratulations.
Your server is officially doing something useful.
6. Point Your Domain to the VPS
Now go to your DNS provider and create an A record.
For example:
Type: A
Name: @
Value: YOUR_SERVER_IP
TTL: 300
For www:
Type: A
Name: www
Value: YOUR_SERVER_IP
TTL: 300
DNS changes aren't always instant, so give it some time.
You can check the record with:
dig example.com
Or:
nslookup example.com
You want the domain to resolve to the VPS IP.
7. Create an Nginx Server Block
Let's assume the domain is:
example.com
Create a directory for the site:
sudo mkdir -p /var/www/example.com
Give your user access:
sudo chown -R henry:henry /var/www/example.com
Create a simple page:
nano /var/www/example.com/index.html
Add:
<!DOCTYPE html>
<html>
<head>
<title>My VPS Website</title>
</head>
<body>
<h1>Hello from my VPS!</h1>
<p>The server is alive. Nobody panic.</p>
</body>
</html>
Now create an Nginx configuration:
sudo nano /etc/nginx/sites-available/example.com
Use:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example.com;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
Enable it:
sudo ln -s /etc/nginx/sites-available/example.com \
/etc/nginx/sites-enabled/example.com
Test the configuration:
sudo nginx -t
If everything looks good:
sudo systemctl reload nginx
Now visit your domain.
8. Add HTTPS
Running a website over plain HTTP isn't something I’d recommend.
Install Certbot:
sudo apt install certbot python3-certbot-nginx -y
Then request a certificate:
sudo certbot --nginx -d example.com -d www.example.com
Certbot can configure the Nginx HTTPS settings for you.
After that, check:
sudo nginx -t
And:
sudo systemctl reload nginx
You should now be able to access:
https://example.com
The browser lock icon isn't decoration. It means the connection is encrypted.
9. If You’re Hosting an Application
Static HTML is easy.
Real applications are where things get interesting.
Suppose your Node.js application listens on:
127.0.0.1:3000
You don't necessarily need to expose port 3000 publicly.
Instead, Nginx can sit in front of it:
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Now the public traffic goes:
Internet
|
HTTPS
|
Nginx
|
localhost:3000
|
Node.js
This is a much cleaner setup than exposing every service directly to the internet.
10. Keep the Application Running
If your application crashes, you probably don't want your website disappearing until you manually restart it.
For Node.js applications, a process manager such as systemd or another appropriate service manager can handle this.
A simple systemd service might look like:
[Unit]
Description=My Website
After=network.target
[Service]
User=henry
WorkingDirectory=/var/www/myapp
ExecStart=/usr/bin/node /var/www/myapp/server.js
Restart=always
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.target
Save it as:
/etc/systemd/system/myapp.service
Then:
sudo systemctl daemon-reload
sudo systemctl enable myapp
sudo systemctl start myapp
Check it:
sudo systemctl status myapp
This gives you something much closer to a proper production service instead of keeping a terminal window open and praying nobody closes it.
11. Don't Forget Backups
A VPS is not a backup.
This is worth repeating.
If the server disappears and your only copy of the database was sitting on that server, the backup plan was basically:
“Hopefully nothing happens.”
That isn't a backup strategy.
At minimum, think about:
- Website files
- Databases
- Environment/configuration files
- SSL configuration
- Application data
- Server configuration
For MySQL, for example:
mysqldump -u root -p database_name > database_backup.sql
But don't just create backups.
Test restoring them.
A backup you've never successfully restored is an assumption, not proof.
12. Watch the Server
Once the website is online, the job isn't finished.
I usually keep an eye on:
free -h
for memory,
df -h
for disk usage,
and:
uptime
for basic system load information.
For services:
sudo systemctl status nginx
And for logs:
sudo journalctl -u nginx
You can also use more advanced monitoring stacks when the server grows, such as metrics collection, centralized logging, alerting, and external uptime checks.
That's where VPS management starts becoming real infrastructure work rather than simply “I installed a website.”
13. Choose the Right VPS
You don't always need a huge server.
A small website might work perfectly well with a modest VPS. A busy application, database-heavy platform, or API service may need more CPU, memory, storage performance, or network capacity.
When comparing VPS hosting, I’d pay attention to:
- Dedicated or guaranteed resources
- NVMe storage
- Network capacity
- Backup options
- Snapshot support
- DDoS protection
- Data-center location
- IPv4/IPv6 availability
- Root access
- Upgrade options
- Monitoring and support
If you're comparing VPS hosting providers, HelloServer is one option worth checking, especially if you want control over the server environment rather than being locked into a shared hosting setup.
The important part isn't choosing the biggest plan.
It's choosing a setup that gives your website enough headroom without paying for resources you'll never use.
14. A Few Production Checks
Before calling the server “finished,” I'd check a few things.
Test Nginx:
sudo nginx -t
Check listening ports:
sudo ss -tulpn
Check firewall rules:
sudo ufw status
Check disk space:
df -h
Check memory:
free -h
Check failed services:
systemctl --failed
And make sure your website actually works over HTTPS.
Not just the homepage.
Test forms, login, uploads, APIs, database connections, redirects, and anything else your application depends on.
Final Thoughts
Setting up a private VPS for a website isn't particularly difficult once you understand what each layer is doing.
The important thing is not memorizing commands.
It's understanding the architecture:
Domain
↓
DNS
↓
Firewall
↓
Nginx
↓
Application
↓
Database
Then add the things that keep it reliable:
Backups
Monitoring
Updates
Logging
Security
That's the difference between simply getting a website online and actually running your own server properly.
And yes, you'll probably break something while learning.
That's normal.
Just make sure you have a backup before you break it.
Top comments (0)