Deploy like a pro — set up, secure, and scale your own production-ready VPS with zero DevOps experience.
This article is originally published at my Medium account.

Building a Production Server from Scratch: The Ultimate Guide | by ARHAM RUMI | Oct, 2025 | Medium
ARHAM RUMI ・ ・
Medium
In a world obsessed with managed services and serverless stacks, understanding how to manage your own Virtual Private Server (VPS) is a timeless skill.
Running your own server gives you:
✅ Full control over your infrastructure
✅ Lower long-term costs compared to managed platforms
✅ Real DevOps insight that translates across all cloud providers
Whether you’re launching a startup MVP, a SaaS app, or your personal project, this guide will take you from a blank VPS to a fully deployed, production-grade environment.
💡 Note: This guide doesn’t focus on any specific cloud provider — the steps are exactly the same no matter where you host your VPS. You can go with AWS EC2, DigitalOcean, Vultr, Linode, or any other provider that fits your budget, region, or performance needs.
I’ll dive deeper into comparing different VPS providers in a future article, but for now, let’s stay focused on setting up your server the right way.
Initial Server Access
First, connect to your VPS using SSH or the built-in web terminal provided by your hosting service. In this guide, I’ll be using the provider’s integrated web terminal to connect to my VPS.
You will see the integrated terminal of your VPS like this after connecting successfully.
Check System Codename
Run this command to see the codename of your VPS OS.
lsb_release -a
You will see something like this.
My VPS codename is noble
.
Identifying System’s Init System
Before managing services like MongoDB or Node.js applications, it’s important to know which init system your Linux distribution uses. The init system is responsible for starting and managing processes after the system boots.
Run the following command to identify your init system:
ps --no-headers -o comm 1
It will display your init system. Mine is systemd
.
💡 Why It Matters:
Service management commands (like starting, stopping, and enabling MongoDB or PM2) depend on the init system. Most VPS providers today use systemd, so if your output shows systemd, you can safely follow all systemctl commands in this guide.
Update System Packages
Always update a fresh VPS — this closes known vulnerabilities in the base image. Run these commands:
sudo apt update && sudo apt upgrade -y
sudo apt autoremove -y
Install Essentials
These tools are vital for fetching remote files and deploying your app.
sudo apt install curl git -y
Install Core Runtime — Node.js (LTS Version)
Go to https://deb.nodesource.com/ to get the latest LTS (Long Term Support) version.
Run the following commands one by one.
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
You might have noticed that our command includes an extra -E
flag compared to the official NodeSource installation command.
Normally, when you use sudo
, your environment variables — like proxy settings (HTTP_PROXY
, HTTPS_PROXY
, etc.) or custom configuration paths — are not passed to the root environment. This is a security measure to prevent unexpected privilege escalation through environment manipulation.
By using sudo -E
, we ensure that your existing environment (especially proxy-related settings) stays intact during the installation.
✅ If you’re behind a proxy, using -E
prevents download failures caused by missing proxy configurations.
✅ If you’re on a direct internet connection, it doesn’t hurt — the command works the same as sudo
.
🧠 In short:
sudo -E
is just a safety net. You can omit it if your VPS has direct internet access, but it’s good practice to include it to avoid proxy-related issues during installations.
Verify Installation
Run these commands to verify your runtime installations.
node -v
npm -v
⚙️ Why LTS? LTS releases are battle-tested and receive security updates for years — perfect for production stability.
Install MongoDB
Modern applications need modern databases. Here’s how to install MongoDB Community Edition. This includes several steps, which we’ll go through one by one with short descriptions for better understanding.
First, make sure you have GnuPG
installed.
sudo apt install gnupg -y
Now, the actual installation will start. I’ll follow the official instructions mentioned at this link. You can follow the link directly if you prefer, or stay here — I’ll walk you through each necessary step.
Liquid error: internal
Import the Public Key
Run this command to import the official keys.
curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc | sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg --dearmor
Create the List File
You need to run only one of these commands according to your VPS codename. My VPS codename is noble
.
For noble
run this:
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.2 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.2.list
For jammy
run this:
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/8.2 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.2.list
For focal
run this:
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/8.2 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.2.list
Reload the Package Database
Run the following command to reload the package database.
sudo apt update
Install MongoDB Community Server
Install the latest stable version of MongoDB using the command:
sudo apt install -y mongodb-org
Start MongoDB
You can start the mongod
process by issuing the following command according to your init system. if you have an older init system, follow this link:
Liquid error: internal
My init system is systemd
, so I will use the following commands:
sudo systemctl start mongod
If you receive an error similar to the following when starting mongod
:
Failed to start mongod.service: Unit mongod.service not found.
Run the following command first:
sudo systemctl daemon-reload
Then run the start command above again.
Check MongoDB Status
Run this command to verify MongoDB is actually running.
sudo systemctl status mongod
Then press CTRL + C
to exit MongoDB status view and return to the normal terminal.
🔒 Pro Tip: Enabling MongoDB ensures it restarts automatically after reboots.
sudo systemctl enable mongod
Restart MongoDB
You can restart the mongod
process by issuing the following command:
sudo systemctl restart mongod
Application Deployment
Pull Your Code
I have a public repository for learning purposes. You can also check it out, star it, or fork it if you’d like to start from there. Since it’s public, I don’t need to set up SSH to clone it.
git clone https://github.com/arham-rumi/social-app.git
Move inside the repository using:
cd social-app
🔒 Pro Tip: Never ever public your code unless you actually want to make it OpenSource.
Setup Environment
Install packages using:
npm install
Create .env
file using nano
utility. Please make sure you use the same filename for environment variables as the one imported in your code. For now, my code imports the environment variables from .env
, so I’ll create the file with the same name like this:
nano .env
You’ll enter the editor mode. Simply copy all the variables that you’ve defined in your local .env
file, like this:
Now, press CTRL + O
to write out changes. It will ask you to confirm. Press ENTER
.
It will then show you the number of written lines as confirmation that your file has been saved.
Then move out of the editor using CTRL + X
.
Production Process Management
Install PM2
globally using:
sudo npm install -g pm2
🚀 Why PM2? It ensures zero-downtime restarts, load balancing, and monitoring — ideal for production-grade stability.
Run our app’s process:
pm2 start npm --name "social-app-prod" -- run start
Here, the word start
after run
refers to the script name defined in your package.json
file. You can replace the name with yours. Now it will look like this.
Monitor your application using:
pm2 logs social-app-prod
Here, social-app-prod
is the name of the process — change it if you’re using a different name. It will show the logs like this:
You can exit the logs using CTRL + C
. Check the status of your processes using:
pm2 list
Or by using:
pm2 status
It will show your processes.
Ensure your application survives server restarts using these commands:
pm2 save
pm2 startup systemd
Validation & Testing
Health Check Verification
Test your application internally:
curl http://127.0.0.1:7000/api/v1/healthcheck
External Access Testing
Access your application via the server’s public IP. I am using postman.
That’s great — your server is working properly!
🌐 Network Configuration: If inaccessible, configure your cloud provider’s firewall rules to allow TCP traffic on your application port. For example:
There may be other ports or rules you’ll need to configure. However, for this article, I’ve kept it as simple as possible for demonstration purposes.
Outro: From Command Line to Confidence
You’ve just built more than a server — you’ve built independence. By setting up and securing your own VPS from scratch, you’ve gained control over your infrastructure and the confidence to deploy applications like a pro.
You now know how to:
✅ Secure your server with updates and best practices
✅ Install Node.js and MongoDB the professional way
✅ Deploy and manage production apps with PM2
✅ Keep everything running through reboots and scaling demands
Your VPS is now your personal cloud — custom, optimized, and truly yours. Every configuration command you’ve run is a building block toward mastering modern DevOps and backend scalability.
Next Steps
In the next guides, we’ll take this setup even further — configuring Nginx as a reverse proxy, enabling free SSL certificates with Let’s Encrypt, and automating secure backups to ensure your application is not just live, but resilient.
🚀 Own your stack. Master your craft. Deploy with confidence.
From here, explore containerization with Docker, implement CI/CD pipelines, or add monitoring — but remember: every enterprise-scale application starts with the solid foundation you just built.
💪 You didn’t just deploy an app — you built the foundation for scalable, self-managed infrastructure.
Top comments (0)