<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nainish Rai</title>
    <description>The latest articles on DEV Community by Nainish Rai (@nainish_rai).</description>
    <link>https://dev.to/nainish_rai</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3226628%2Feacc32cc-ac50-4209-85f2-754c7d640186.jpg</url>
      <title>DEV Community: Nainish Rai</title>
      <link>https://dev.to/nainish_rai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nainish_rai"/>
    <language>en</language>
    <item>
      <title>How I Deployed a NestJS App on a VPS (and AWS) Without Losing My Mind</title>
      <dc:creator>Nainish Rai</dc:creator>
      <pubDate>Fri, 30 May 2025 17:10:33 +0000</pubDate>
      <link>https://dev.to/nainish_rai/how-i-deployed-a-nestjs-app-on-a-vps-and-aws-without-losing-my-mind-3eih</link>
      <guid>https://dev.to/nainish_rai/how-i-deployed-a-nestjs-app-on-a-vps-and-aws-without-losing-my-mind-3eih</guid>
      <description>&lt;p&gt;Hey, devs!&lt;/p&gt;

&lt;p&gt;Sharing my experience at a startup (let’s call it “VidStack”), I got tasked with deploying a &lt;strong&gt;NestJS microservices app&lt;/strong&gt; on a &lt;strong&gt;Ubuntu VPS&lt;/strong&gt; and &lt;strong&gt;AWS&lt;/strong&gt;. Sounds intimidating? Yeah, it was a bit. But I got through it without setting any servers on fire (mostly). Here’s how I pulled it off—step-by-step, with honest explanations and zero fluff. If you’re a dev figuring out deployment for the first time, this one’s for you. 🍜&lt;/p&gt;




&lt;h2&gt;
  
  
  🧱 The Setup: What We Were Dealing With
&lt;/h2&gt;

&lt;p&gt;Our app had multiple services (aka microservices). Picture this: 6 microservices yelling at each other over a walkie-talkie (NATS), with an API Gateway playing babysitter. Here’s the crew:&lt;/p&gt;

&lt;h3&gt;
  
  
  Services:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;API Gateway&lt;/strong&gt;: The babysitter keeping things in order.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User Management&lt;/strong&gt;: Handles signup/login stuff.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Video Management&lt;/strong&gt;: Manages video uploads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clips Management&lt;/strong&gt;: Chops videos into shareable clips.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clip Actions&lt;/strong&gt;: Tracks likes/comments on clips.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action Management&lt;/strong&gt;: Logs all interactions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All built with &lt;strong&gt;NestJS&lt;/strong&gt;, a slick Node.js framework for backend development.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧪 Local Dev Setup
&lt;/h2&gt;

&lt;p&gt;Before we go live, we need to test locally. Here’s how I got it running.&lt;/p&gt;

&lt;h3&gt;
  
  
  🛠 Step 1: Clone the Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &amp;lt;repo-url&amp;gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;project-spaghetti
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What’s this?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
We’re grabbing the project code from GitHub and moving into its folder. Think of it as downloading a recipe before cooking. I think I am overexplaining but nvm :).&lt;/p&gt;


&lt;h3&gt;
  
  
  📦 Step 2: Install Dependencies
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This pulls in all the packages (like &lt;code&gt;express&lt;/code&gt;, &lt;code&gt;dotenv&lt;/code&gt;, etc.) listed in &lt;code&gt;package.json&lt;/code&gt;. &lt;/p&gt;


&lt;h3&gt;
  
  
  🧪 Step 3: Set Up &lt;code&gt;.env&lt;/code&gt; Files
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; .env.example .env
&lt;span class="nb"&gt;cp &lt;/span&gt;api-gateway/.env.example api-gateway/.env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;What are &lt;code&gt;.env&lt;/code&gt; files?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
They store sensitive stuff like database passwords. Never commit them to GitHub unless you want hackers sending you thank-you notes.&lt;/p&gt;


&lt;h3&gt;
  
  
  🐘 Step 4: Start PostgreSQL with Docker
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt; postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Docker&lt;/strong&gt;: A tool that runs apps in lightweight containers (like tiny virtual machines).&lt;br&gt;&lt;br&gt;
&lt;strong&gt;PostgreSQL&lt;/strong&gt;: Our database for storing data.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Why Docker?&lt;/strong&gt; Installing Postgres manually is a hassle. Docker makes it as easy as reheating leftovers.&lt;/p&gt;


&lt;h3&gt;
  
  
  🗃 Step 5: Run Database Migrations
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx prisma migrate deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Prisma&lt;/strong&gt;: A tool that makes talking to databases feel like chatting with a friend.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Migrations&lt;/strong&gt;: These create database tables based on your schema (like setting up shelves for your data).&lt;/p&gt;


&lt;h3&gt;
  
  
  🏃 Step 6: Start the Services
&lt;/h3&gt;

&lt;p&gt;Open a terminal for each service and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;api-gateway &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run start:dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repeat for each microservice. Your laptop will sound like a jet engine, but it works.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Deploying to a VPS
&lt;/h2&gt;

&lt;p&gt;Now we move from local to real-world. I used a VPS on DigitalOcean (you could use AWS EC2 too).&lt;/p&gt;




&lt;h3&gt;
  
  
  🌐 Step 1: VPS Initial Setup
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; curl git docker.io docker-compose nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What’s happening?&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;apt update/upgrade&lt;/code&gt;: Updates the server’s software.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;curl/git&lt;/code&gt;: Tools for downloading and version control.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker/docker-compose&lt;/code&gt;: For running our database in containers.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nginx&lt;/code&gt;: A web server to handle incoming traffic (we’ll use it soon).&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Install Node.js &amp;amp; PM2
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://deb.nodesource.com/setup_18.x | &lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; bash -
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; nodejs
&lt;span class="nb"&gt;sudo &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; pm2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Node.js&lt;/strong&gt;: Runs our NestJS app.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PM2&lt;/strong&gt;: A process manager that keeps our services running, even if the server restarts.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🏗 Step 2: Clone Project on VPS
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /opt/project-spaghetti
&lt;span class="nb"&gt;cd&lt;/span&gt; /opt/project-spaghetti
git clone &amp;lt;repo-url&amp;gt; &lt;span class="nb"&gt;.&lt;/span&gt;
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run &lt;span class="nb"&gt;install&lt;/span&gt;:all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sets up the app folder and installs all dependencies.&lt;/p&gt;




&lt;h3&gt;
  
  
  ⚙️ Step 3: Configure &lt;code&gt;.env&lt;/code&gt; Files
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"DATABASE_URL='postgresql://user:pass@localhost:5432/db'"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set up &lt;code&gt;.env&lt;/code&gt; files again, but with production values (e.g., real database credentials).&lt;/p&gt;




&lt;h3&gt;
  
  
  🐘 Step 4: Run Database and Migrations
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
npx prisma migrate deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This starts Postgres in Docker and builds the database tables.&lt;/p&gt;




&lt;h3&gt;
  
  
  🧱 Step 5: Build the Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build:all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This converts TypeScript code to JavaScript, which Node.js can run.&lt;/p&gt;




&lt;h3&gt;
  
  
  🧙‍♂️ Step 6: Keep Services Alive with PM2
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pm2 start ecosystem.config.json
pm2 save
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ecosystem.config.json&lt;/strong&gt;: A file listing all microservices and how to run them.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pm2 start&lt;/code&gt;: Launches all services.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pm2 save&lt;/code&gt;: Ensures they restart if the server reboots.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🌍 Step 7: Set Up Nginx (The Traffic Cop)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/nginx/sites-available/project-spaghetti
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;your-domain.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_http_version&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Upgrade&lt;/span&gt; &lt;span class="nv"&gt;$http_upgrade&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Connection&lt;/span&gt; &lt;span class="s"&gt;'upgrade'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_cache_bypass&lt;/span&gt; &lt;span class="nv"&gt;$http_upgrade&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Nginx&lt;/strong&gt;: A web server that directs internet traffic to your app.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;proxy_pass&lt;/strong&gt;: Sends traffic from port 80 (standard web port) to port 3000 (where our app lives).&lt;/p&gt;

&lt;p&gt;Enable the site:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /etc/nginx/sites-available/project-spaghetti /etc/nginx/sites-enabled/
&lt;span class="nb"&gt;sudo &lt;/span&gt;nginx &lt;span class="nt"&gt;-t&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🔒 Step 8: Add Free SSL with Let’s Encrypt
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; certbot python3-certbot-nginx
&lt;span class="nb"&gt;sudo &lt;/span&gt;certbot &lt;span class="nt"&gt;--nginx&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; your-domain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives your site HTTPS (the browser lock icon). It’s free, and Google loves it.&lt;/p&gt;




&lt;h2&gt;
  
  
  🤖 Automating with GitHub Actions (CI/CD)
&lt;/h2&gt;

&lt;p&gt;Manually SSH-ing into the server for updates? Nah, let’s automate it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set Up SSH for GitHub
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; ed25519 &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"github-deploy"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the public key to your VPS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;your-public-key&amp;gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.ssh/authorized_keys
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the private key and server details to &lt;strong&gt;GitHub Secrets&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SSH_PRIVATE_KEY&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SERVER_HOST&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SERVER_USER&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, every push to the &lt;code&gt;main&lt;/code&gt; branch will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;SSH into the server.&lt;/li&gt;
&lt;li&gt;Pull the latest code.&lt;/li&gt;
&lt;li&gt;Rebuild and restart services.&lt;/li&gt;
&lt;li&gt;Let you sip coffee. ☕&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🩺 Monitoring &amp;amp; Debugging
&lt;/h2&gt;

&lt;h3&gt;
  
  
  PM2 Commands:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pm2 status
pm2 logs
pm2 restart all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Database Backups:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pg_dump &lt;span class="nt"&gt;-U&lt;/span&gt; user db &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; backup.sql
psql &lt;span class="nt"&gt;-U&lt;/span&gt; user db &amp;lt; backup.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Renew SSL:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;certbot renew
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ⚠️ Bonus Tips (Lessons from My Screw-Ups)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Don’t run migrations before the database is up. You’ll cry.
&lt;/li&gt;
&lt;li&gt;Check disk space. My server died once because it was stuffed with logs 😵‍💫.
&lt;/li&gt;
&lt;li&gt;Use a firewall (UFW) to allow only ports 22 (SSH), 80, and 443.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧠 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Deploying a NestJS microservices app isn’t trivial, but it’s doable if you break it down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Docker&lt;/strong&gt; runs Postgres.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prisma&lt;/strong&gt; sets up the database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PM2&lt;/strong&gt; keeps services running.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nginx&lt;/strong&gt; handles traffic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Actions&lt;/strong&gt; automates updates.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Take it one step at a time, and you’ll be fine. If you’re staring at a blank terminal wondering where to start, I hope this helps. Share it with a dev friend who’s in the same boat! 😅&lt;/p&gt;




&lt;h2&gt;
  
  
  💭 My Personal Experience &amp;amp; Takeaways
&lt;/h2&gt;

&lt;p&gt;When I first saw the task—"Deploy NestJS microservices to a VPS"—I legit opened 20 tabs, panicked, and drank way too much diet coke.&lt;/p&gt;

&lt;h3&gt;
  
  
  Challenges I Faced:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Configuring &lt;strong&gt;PM2&lt;/strong&gt; to handle multiple services wasn’t easy. Each service needed its own setup, and I kept mixing up ports.
&lt;/li&gt;
&lt;li&gt;Forgot to set up a &lt;code&gt;.env&lt;/code&gt; file once. Debugged for 2 hours. Rookie mistake.
&lt;/li&gt;
&lt;li&gt;Nginx gave me a &lt;strong&gt;502 Bad Gateway&lt;/strong&gt; error. Turns out, I forgot to restart it after tweaking the config 🤦‍♂️.
&lt;/li&gt;
&lt;li&gt;Debugging &lt;strong&gt;Docker/Postgres&lt;/strong&gt; issues was brutal without logs. Lesson: always check &lt;code&gt;docker logs&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What I Learned:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Break problems down. One service at a time. One port at a time.
&lt;/li&gt;
&lt;li&gt;Deployment is more about configuration than code.
&lt;/li&gt;
&lt;li&gt;Tools like &lt;strong&gt;Docker&lt;/strong&gt;, &lt;strong&gt;PM2&lt;/strong&gt;, and &lt;strong&gt;Nginx&lt;/strong&gt; sound scary—but they’re not once you use them.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD&lt;/strong&gt; is a blessing. Automate everything you can.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This task forced me out of my comfort zone, but I came out way more confident with DevOps, deployment, and infrastructure. If you’re reading this and thinking “I can’t do it”—you totally can. Just Google, break it down, and keep pushing.&lt;/p&gt;

&lt;h3&gt;
  
  
  👋 Final Words
&lt;/h3&gt;

&lt;p&gt;Thanks for sticking around! Hope this helped demystify the world of NestJS deployment for you. If you want more dev logs like this or want to see the &lt;strong&gt;GitHub Actions CI/CD&lt;/strong&gt; setup I used, feel free to reach out or drop a DM!&lt;/p&gt;

&lt;p&gt;Happy deploying! ⚙️🚀&lt;/p&gt;

&lt;p&gt;— &lt;strong&gt;Nainish Rai&lt;/strong&gt;  &lt;/p&gt;

</description>
      <category>nestjs</category>
      <category>devops</category>
      <category>docker</category>
      <category>aws</category>
    </item>
  </channel>
</rss>
