DEV Community

Cover image for Building a Production Server from Scratch: The Ultimate Guide
Arham Rumi
Arham Rumi

Posted on

Building a Production Server from Scratch: The Ultimate Guide

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.

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.

Connect to VPS

You will see the integrated terminal of your VPS like this after connecting successfully.

Connected to VPS

Check System Codename

Run this command to see the codename of your VPS OS.

lsb_release -a
Enter fullscreen mode Exit fullscreen mode

You will see something like this.

VPS codename

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
sudo apt autoremove -y
Enter fullscreen mode Exit fullscreen mode

Install Essentials

These tools are vital for fetching remote files and deploying your app.

sudo apt install curl git -y
Enter fullscreen mode Exit fullscreen mode

Install Core Runtime — Node.js (LTS Version)

Go to https://deb.nodesource.com/ to get the latest LTS (Long Term Support) version.

Nodesource homepage

Run the following commands one by one.

curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
Enter fullscreen mode Exit fullscreen mode
sudo apt install -y nodejs
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

verify node js installation

⚙️ 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Reload the Package Database

Run the following command to reload the package database.

sudo apt update
Enter fullscreen mode Exit fullscreen mode

Install MongoDB Community Server

Install the latest stable version of MongoDB using the command:

sudo apt install -y mongodb-org
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Then run the start command above again.

Check MongoDB Status

Run this command to verify MongoDB is actually running.

sudo systemctl status mongod
Enter fullscreen mode Exit fullscreen mode

Mongodb status check

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
Enter fullscreen mode Exit fullscreen mode

Restart MongoDB

You can restart the mongod process by issuing the following command:

sudo systemctl restart mongod
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Move inside the repository using:

cd social-app
Enter fullscreen mode Exit fullscreen mode

Inside the repo

🔒 Pro Tip: Never ever public your code unless you actually want to make it OpenSource.

Setup Environment

Install packages using:

npm install
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

You’ll enter the editor mode. Simply copy all the variables that you’ve defined in your local .env file, like this:

Edit Env

Now, press CTRL + O to write out changes. It will ask you to confirm. Press ENTER.

Saving Env

It will then show you the number of written lines as confirmation that your file has been saved.

Saved Env

Then move out of the editor using CTRL + X.

Production Process Management

Install PM2 globally using:

sudo npm install -g pm2
Enter fullscreen mode Exit fullscreen mode

🚀 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
Enter fullscreen mode Exit fullscreen mode

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.

Run app’s process

Monitor your application using:

pm2 logs social-app-prod
Enter fullscreen mode Exit fullscreen mode

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:

App logs

You can exit the logs using CTRL + C. Check the status of your processes using:

pm2 list
Enter fullscreen mode Exit fullscreen mode

Or by using:

pm2 status
Enter fullscreen mode Exit fullscreen mode

It will show your processes.

pm2 list - processes list

Ensure your application survives server restarts using these commands:

pm2 save
Enter fullscreen mode Exit fullscreen mode
pm2 startup systemd
Enter fullscreen mode Exit fullscreen mode

Validation & Testing

Health Check Verification

Test your application internally:

curl http://127.0.0.1:7000/api/v1/healthcheck
Enter fullscreen mode Exit fullscreen mode

Local test

External Access Testing

Access your application via the server’s public IP. I am using postman.

API verification with 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:

Allow TCP on port 80

Allow TCP on port 7000

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)