<?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: Israel</title>
    <description>The latest articles on DEV Community by Israel (@israeldotcom).</description>
    <link>https://dev.to/israeldotcom</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%2F757985%2F1c7b950a-f761-4d95-a70c-613261c87fe0.png</url>
      <title>DEV Community: Israel</title>
      <link>https://dev.to/israeldotcom</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/israeldotcom"/>
    <language>en</language>
    <item>
      <title>Deploying a MedusaJS 2.0 Store on AN AWS EC2 Instance.</title>
      <dc:creator>Israel</dc:creator>
      <pubDate>Fri, 26 Sep 2025 20:36:27 +0000</pubDate>
      <link>https://dev.to/israeldotcom/deploying-a-medusajs-20-store-on-an-aws-ec2-instance-5ba5</link>
      <guid>https://dev.to/israeldotcom/deploying-a-medusajs-20-store-on-an-aws-ec2-instance-5ba5</guid>
      <description>&lt;h2&gt;
  
  
  So you have decided to set up an online store and you would rather set it up your self, you're in the right place.
&lt;/h2&gt;

&lt;p&gt;We'll Deploy a MedusaJS Backend and Storefront on an Ubuntu Server. In a later article we'll look at using other AWS services to build a more resilient version. I'll link it here when it's ready [link]&lt;/p&gt;

&lt;h1&gt;
  
  
  Table of Contents
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Pre-requisites&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Step-by-Step Deployment&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;STEP 1) Server Provisioning&lt;/li&gt;
&lt;li&gt;STEP 2) Installing Prerequisites&lt;/li&gt;
&lt;li&gt;STEP 3) Running the Medusa Backend&lt;/li&gt;
&lt;li&gt;STEP 4) Reverse Proxy with Nginx&lt;/li&gt;
&lt;li&gt;STEP 5) Setting up the Frontend&lt;/li&gt;
&lt;li&gt;STEP 6) Debugging and Fixes&lt;/li&gt;
&lt;li&gt;STEP 7) Next Steps (Future Work)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Why Deploy MedusaJS on a Scalable Server?&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;There are many modern, headless commerce platforms, and MedusaJS is one of the most versatile for building full-featured online stores. Medusa makes store development seamless but  deploying a production-ready application can be challenging without the right setup and automation practices.&lt;/p&gt;

&lt;p&gt;That’s what this article will focus on, configuring an Ubuntu server to handle it and serving it through Nginx so safe to say that by the end we'll have&lt;/p&gt;

&lt;p&gt;A live MedusaJS application running on your server&lt;/p&gt;

&lt;p&gt;Clearly separated and functional routes for admin, API, authentication, and storefront&lt;/p&gt;

&lt;p&gt;A persistent frontend using PM2 for reliability&lt;/p&gt;

&lt;p&gt;Nginx properly configured to handle the admin panel, country-specific routes and SSL&lt;/p&gt;

&lt;p&gt;So whether you’re a developer looking to build more features for a specific use-case or just exploring headless commerce, this step-by-step guide will give you everything you need to host Medusa yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Server Provisioning
&lt;/h2&gt;

&lt;p&gt;Start by provisioning an ubuntu server, we'll create a new security group with inbound rules; 22 from your IP, 80 and 443 from anywhere. &lt;br&gt;
You should have something like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ow69iimgpnms5fddsqn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ow69iimgpnms5fddsqn.png" alt=" " width="800" height="204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A t3 medium server with about 30GB of storage space should do just fine.&lt;/p&gt;
&lt;h2&gt;
  
  
  Installing the Prerequisites
&lt;/h2&gt;

&lt;p&gt;All we need is a Server, a domain and a stripe account.&lt;/p&gt;

&lt;p&gt;We'll need to install quite a few things to get our Medusa Store up and running.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Node&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Docker &amp;amp; Docker Compose&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Curl &amp;amp; Git&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;PM2&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Nginx&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Certbot&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can use this script to install everything we need. &lt;br&gt;
We'll install the Certbot later since it requires interaction&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash

# Update system
sudo apt update &amp;amp;&amp;amp; sudo apt upgrade -y

# Install prerequisites
sudo apt install -y ca-certificates curl gnupg lsb-release

# Add Docker’s official GPG key
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
  sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# Add Docker’s APT repository
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list &amp;gt; /dev/null

# Install Docker Engine, CLI, containerd, and Docker Compose plugin
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

# Enable and start Docker
sudo systemctl enable docker
sudo systemctl start docker

# Allow current user to run Docker without sudo
sudo usermod -aG docker $USER
newgrp docker

# Verify Docker
docker --version
docker compose version

# Install Git
sudo apt install -y git

# Install Nginx
sudo apt install -y nginx
sudo systemctl enable nginx
sudo systemctl start nginx

# Install Node.js (LTS) and npm
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install -y nodejs

# Install PM2 globally
sudo npm install -g pm2

# Setup PM2 startup (so it restarts apps on reboot)
pm2 startup systemd -u $USER --hp $HOME

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running the Backend Server
&lt;/h2&gt;

&lt;p&gt;We'll set up the Medusa Backend using Docker.&lt;/p&gt;

&lt;p&gt;Let's begin by cloning the Repo&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git clone https://github.com/medusajs/medusa-starter-default.git --depth=1 medusa-server&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
Next, create a Docker compose file, &lt;code&gt;docker-compose.yml&lt;/code&gt; in the new repo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services:
  # PostgreSQL Database
  postgres:
    image: postgres:15-alpine
    container_name: medusa_postgres
    restart: unless-stopped
    environment:
      POSTGRES_DB: medusa-store
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - medusa_network

  # Redis
  redis:
    image: redis:7-alpine
    container_name: medusa_redis
    restart: unless-stopped
    ports:
      - "6379:6379"
    networks:
      - medusa_network

  # Medusa Server
  # This service runs the Medusa backend application
  # and the admin dashboard.
  medusa:
    build: .
    container_name: medusa_backend
    restart: unless-stopped
    depends_on:
      - postgres
      - redis
    ports:
      - "9000:9000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgres://postgres:postgres@postgres:5432/medusa-store
      - REDIS_URL=redis://redis:6379
    env_file:
      - .env
    volumes:
      - .:/app
      - /app/node_modules
    networks:
      - medusa_network

volumes:
  postgres_data:

networks:
  medusa_network:
    driver: bridge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates three new services we'll need, Redis, Postgres and Medusa&lt;/p&gt;

&lt;p&gt;Create a Dockerfile, &lt;code&gt;Dockerfile&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Development Dockerfile for Medusa
FROM node:20-alpine

# Set working directory
WORKDIR /server

# Copy package files and npm config
COPY package.json package-lock.json ./

# Install all dependencies using npm
RUN npm install

# Copy source code
COPY . .

# Expose the port Medusa runs on
EXPOSE 9000

# Start with migrations and then the development server
CMD ["./start.sh"]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now create the start script &lt;code&gt;start.sh&lt;/code&gt; and give it permission to run with &lt;code&gt;chmod u+x start.sh&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/sh

# Run migrations and start server
echo "Running database migrations..."
npx medusa db:migrate

echo "Seeding database..."
npm run seed || echo "Seeding failed, continuing..."

echo "Starting Medusa development server..."
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;npm install&lt;/code&gt; to install the dependencies we'll be working with.&lt;/p&gt;

&lt;p&gt;Replace the &lt;code&gt;medusa-config.ts&lt;/code&gt; file with this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { loadEnv, defineConfig } from '@medusajs/framework/utils'

loadEnv(process.env.NODE_ENV || 'production', process.cwd())

module.exports = defineConfig({
  projectConfig: {
    databaseUrl: process.env.DATABASE_URL,
    databaseDriverOptions: {
      ssl: false,
      sslmode: "disable",
    },

    http: {
      storeCors: process.env.STORE_CORS!,
      adminCors: process.env.ADMIN_CORS!,
      authCors: process.env.AUTH_CORS!,
      jwtSecret: process.env.JWT_SECRET || "supersecret",
      cookieSecret: process.env.COOKIE_SECRET || "supersecret",
    },
  },

  admin: {
    vite: () =&amp;gt; {
      return {
        server: {
          allowedHosts: [".domainhere.com"], // add your domain here
        },
      }
    },
  },
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't forget to replace with your domain name where i indicated&lt;/p&gt;

&lt;p&gt;In the package.json script section add this&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{&lt;br&gt;
  "scripts": {&lt;br&gt;
    // Other scripts...&lt;br&gt;
    "docker:up": "docker compose up --build -d",&lt;br&gt;
    "docker:down": "docker compose down"&lt;br&gt;
  }&lt;br&gt;
}&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;.dockerignore&lt;/code&gt; file and add these to it&lt;/p&gt;

&lt;p&gt;&lt;code&gt;node_modules&lt;br&gt;
npm-debug.log*&lt;br&gt;
yarn-debug.log*&lt;br&gt;
yarn-error.log*&lt;br&gt;
.git&lt;br&gt;
.gitignore&lt;br&gt;
README.md&lt;br&gt;
.env.test&lt;br&gt;
.nyc_output&lt;br&gt;
coverage&lt;br&gt;
.DS_Store&lt;br&gt;
*.log&lt;br&gt;
dist&lt;br&gt;
build&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next create a .env file and add these, replacing with your domain where necessary&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;STORE_CORS=http://localhost:8000,https://docs.medusajs.com,https://domainhere.com,https://www.domainhere.com
ADMIN_CORS=http://localhost:5173,http://localhost:9000,https://docs.medusajs.com,https://domainhere.com,https://domainhere.com/app
AUTH_CORS=http://localhost:5173,http://localhost:9000,https://docs.medusajs.com,https://domainhere.com,https://domainhere.com/app
REDIS_URL=redis://redis:6379
JWT_SECRET=supersecret
COOKIE_SECRET=supersecret
DATABASE_URL=postgres://postgres:postgres@postgres:5432/medusa-store
DB_NAME=medusa-v2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Never expose your secrets but it should look like this &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjyde6oh1lbnszblin5c4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjyde6oh1lbnszblin5c4.png" alt=" " width="800" height="163"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To start your application use &lt;code&gt;npm run docker:up&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To create a new admin user run&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker compose run --rm medusa npx medusa user -e admin@example.com -p supersecret&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Replace with your email and password&lt;/p&gt;

&lt;p&gt;To check your logs if everything runs smoothly&lt;br&gt;
&lt;code&gt;docker compose logs -f&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Reverse Proxy with Nginx
&lt;/h2&gt;

&lt;p&gt;Now let's setup Nginx&lt;/p&gt;

&lt;p&gt;We've installed Nginx previously so we should be seeing the "Welcome to Nginx page" on the server's url&lt;/p&gt;

&lt;p&gt;Create a Config file in /etc/nginx/sites-available and name it anything you want. I used the name of my domain, workrate.online&lt;/p&gt;

&lt;p&gt;This config file sets up redirects to your Admin dashboard, frontend and API&lt;br&gt;
Just replace my domain name, workrate.online with yours&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server {
    listen 80;
    server_name workrate.online www.workrate.online;

    # --- Frontend (Next.js Storefront) ---
    location ~ ^/(dk|us|ng)(/.*)?$ {
        proxy_pass http://localhost:8000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }

    # Root frontend fallback
    location / {
        proxy_pass http://localhost:8000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }

    # --- Medusa Backend Routes ---
    location /store/ {
        proxy_pass http://localhost:9000/store/;
    }

    location /admin/ {
        proxy_pass http://localhost:9000/admin/;
    }

    location /auth/ {
        proxy_pass http://localhost:9000/auth/;
    }

    location /app/ {
        proxy_pass http://localhost:9000/app/;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enable the newly created config with &lt;br&gt;
&lt;code&gt;sudo ln -s /etc/nginx/sites-available/yourfilenamehere/etc/nginx/sites-enabled/&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Remove the default config, it sometimes interfere&lt;br&gt;
&lt;code&gt;sudo rm /etc/nginx/sites-enabled/default&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Test and reload your config &lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo nginx -t&lt;br&gt;
sudo systemctl reload nginx&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Don't forget to point your domain to your server with your DNS provider.&lt;/p&gt;

&lt;p&gt;Also you should set up Certbot to provide HTTPS by running &lt;/p&gt;

&lt;p&gt;sudo apt install -y certbot python3-certbot-nginx&lt;br&gt;
sudo certbot --nginx -d yourdomainname.com -d &lt;a href="http://www.yourdomainname.com" rel="noopener noreferrer"&gt;www.yourdomainname.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should now be able to access your Admin panel from your domain &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyrjdpwswiojjyz1lbrsd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyrjdpwswiojjyz1lbrsd.png" alt=" " width="800" height="475"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting up the frontend
&lt;/h2&gt;

&lt;p&gt;We'll be setting up a GitHub Actions pipeline with the frontend because it seems more practical, the backend almost never changes but the frontend will require a lot of UI work and therefore constant pushing. &lt;/p&gt;

&lt;p&gt;Anyways, let's start by cloning the storefront&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git clone https://github.com/medusajs/nextjs-starter-medusa medusa-storefront&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;npm install&lt;/code&gt; to install all dependencies&lt;/p&gt;

&lt;p&gt;Create a .env file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#Your Medusa backend, should be updated to where you are hosting your server. Remember to update CORS settings for your server. See – https://docs.medusajs.com/learn/configurations/medusa-config#httpstorecors
MEDUSA_BACKEND_URL=http://localhost:9000

# Your publishable key that can be attached to sales channels. See - https://docs.medusajs.com/resources/storefront-development/publishable-api-keys
NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY=

# Your store URL, should be updated to where you are hosting your storefront.
NEXT_PUBLIC_BASE_URL=http://localhost:8000

# Your preferred default region. When middleware cannot determine the user region from the "x-vercel-country" header, the default region will be used. ISO-2 lowercase format. 
NEXT_PUBLIC_DEFAULT_REGION=dk

# Your Stripe public key. See – https://docs.medusajs.com/resources/commerce-modules/payment/payment-provider/stripe
NEXT_PUBLIC_STRIPE_KEY=pk_test_dQZtCPCXzFgnPf7YRp1ETSs7

# Your Next.js revalidation secret. See – https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#on-demand-revalidation
REVALIDATE_SECRET=supersecret

NEXT_PUBLIC_MEDUSA_BACKEND_URL=http://localhost:9000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll need your Publishable key and Stripe Key {You can use the test one i attached for development purpose only}&lt;/p&gt;

&lt;p&gt;You can use SSH tunnelling to access your port 9000 through your browser, login and get your Publishable Key. Run this on your local machine not the server&lt;/p&gt;

&lt;p&gt;Or just go through your domain/app&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ssh -i /path/to/your-key.pem -L 9000:localhost:9000 ubuntu@&amp;lt;your-ec2-public-ip&amp;gt;&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You should then be able to go to &lt;code&gt;http://localhost:9000/app/settings/publishable-api-keys&lt;/code&gt; to retrieve your own keys&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;npm run dev&lt;/code&gt; to make sure everything is running smoothly&lt;/p&gt;
&lt;h2&gt;
  
  
  GitHub Action
&lt;/h2&gt;

&lt;p&gt;Generate new secret keys on your local machine with &lt;br&gt;
&lt;code&gt;ssh-keygen -t rsa -b 4096 -C "example@email.com"&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
Follow the prompt and manually append your generated .pub keys to &lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Create a GitHub repo, &lt;code&gt;Medusa-storefront&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Copy the private keys and go over to your Github Repo &lt;/p&gt;

&lt;p&gt;Navigate to Settings -&amp;gt; Secrets &amp;amp; Variables -&amp;gt; Actions&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8b6x8dmhby462adxdp8p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8b6x8dmhby462adxdp8p.png" alt=" " width="800" height="493"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a new repository secret named SSH_PRIVATE_KEY and enter the keys you copied earlier.&lt;/p&gt;

&lt;p&gt;Remember the values from the .env files, we'll create some secrets and variables so we can SSH into over server, build the frontend and deploy it every time it detects a push.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SSH_PRIVATE_KEY  Secret &lt;br&gt;
SERVER_HOST Secret Your Public IPv4 Address&lt;br&gt;
SERVER_USER Secret  ubuntu&lt;br&gt;
APP_DIR Secret  /var/www/storefront&lt;br&gt;
NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY  Secret&lt;br&gt;
NEXT_PUBLIC_STRIPE_KEY  Secret &lt;br&gt;
REVALIDATE_SECRET   Secret&lt;br&gt;
MEDUSA_BACKEND_URL  Variable https://domainname&lt;br&gt;
NEXT_PUBLIC_MEDUSA_BACKEND_URL  Variable https://domainname&lt;br&gt;
NEXT_PUBLIC_BASE_URL    Variable https://domainname&lt;br&gt;
NEXT_PUBLIC_DEFAULT_REGION  Variable dk&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Next in your server create a file in the store-front directory in &lt;code&gt;.github/workflows/deploy.yml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Add this to the file save and push to your own local repo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Deploy Frontend

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    env:
      MEDUSA_BACKEND_URL: ${{ vars.MEDUSA_BACKEND_URL }}
      NEXT_PUBLIC_MEDUSA_BACKEND_URL: ${{ vars.NEXT_PUBLIC_MEDUSA_BACKEND_URL }}
      NEXT_PUBLIC_BASE_URL: ${{ vars.NEXT_PUBLIC_BASE_URL }}
      NEXT_PUBLIC_DEFAULT_REGION: ${{ vars.NEXT_PUBLIC_DEFAULT_REGION }}
      NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY }}
      NEXT_PUBLIC_STRIPE_KEY: ${{ secrets.NEXT_PUBLIC_STRIPE_KEY }}
      REVALIDATE_SECRET: ${{ secrets.REVALIDATE_SECRET }}

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 20

      - name: Create .env file
        run: |
          cat &amp;gt; .env &amp;lt;&amp;lt; EOF
          MEDUSA_BACKEND_URL=${{ vars.MEDUSA_BACKEND_URL }}
          NEXT_PUBLIC_MEDUSA_BACKEND_URL=${{ vars.NEXT_PUBLIC_MEDUSA_BACKEND_URL }}
          NEXT_PUBLIC_BASE_URL=${{ vars.NEXT_PUBLIC_BASE_URL }}
          NEXT_PUBLIC_DEFAULT_REGION=${{ vars.NEXT_PUBLIC_DEFAULT_REGION }}
          NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY=${{ secrets.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY }}
          NEXT_PUBLIC_STRIPE_KEY=${{ secrets.NEXT_PUBLIC_STRIPE_KEY }}
          REVALIDATE_SECRET=${{ secrets.REVALIDATE_SECRET }}
          EOF
      - name: Install dependencies and build
        run: |
          npm install
          npm run build
      - name: Copy build files and .env to server
        uses: appleboy/scp-action@v0.1.7
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          source: ".,!.git"
          target: "${{ secrets.APP_DIR }}"

      - name: Restart app
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd ${{ secrets.APP_DIR }}
            # Install production dependencies
            sudo npm install
            # Restart PM2 process
            sudo pm2 delete medusa-storefront || true
            sudo pm2 start npm --name medusa-"storefront" -- run start
            sudo pm2 save

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use these commands to make sure the APP_DIR exists and has the correct permission to run&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;br&gt;
sudo mkdir -p /var/www/storefront&lt;br&gt;
sudo chown -R ubuntu:ubuntu /var/www/storefront&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging, Fixes and Additional Configs
&lt;/h2&gt;

&lt;p&gt;All you have left to do is make a change to the frontend, i overhauled the Storefront landing page. Make a push, let it build and test to make sure everything works fine.&lt;br&gt;
Check it out here.&lt;br&gt;
&lt;a href="https://github.com/aregbesolaisrael/medusa-storefront" rel="noopener noreferrer"&gt;https://github.com/aregbesolaisrael/medusa-storefront&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;While this setup works for small and medium businesses, in my next article i'll cover scaling Medusa with AWS services (ECS, RDS, CloudFront) and setting up monitoring and alerts.&lt;/p&gt;

</description>
      <category>ecommerce</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>devops</category>
    </item>
    <item>
      <title>Configuring Nginx on an EC2 Instance.</title>
      <dc:creator>Israel</dc:creator>
      <pubDate>Thu, 30 Jan 2025 17:48:18 +0000</pubDate>
      <link>https://dev.to/israeldotcom/configuring-nginx-on-an-ec2-instance-1ihb</link>
      <guid>https://dev.to/israeldotcom/configuring-nginx-on-an-ec2-instance-1ihb</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Hey there, today we'll be doing a quick DevOps task, setting up Nginx (A web server) on an Ubuntu server. Nothing too fancy.&lt;br&gt;
If you're new welcome to my Blog, I'm Israel, a developer and DevOps Engineer looking for excitement and challenges.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Task
&lt;/h2&gt;

&lt;p&gt;The task is to set up an Ubuntu server, configure Nginx on it and have it serve a custom page as it's default page. .&lt;/p&gt;

&lt;h2&gt;
  
  
  The Plan
&lt;/h2&gt;

&lt;p&gt;We are going to use an AWS account to provision the Ubuntu server, login to the instance via SSH, install Nginx on it then create the custom page to be displayed then finally test it to see if it works. Simple enough, let's get to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Musing
&lt;/h2&gt;

&lt;p&gt;A big part about being a DevOps engineer is optimization. That's almost the entire thing, optimization and efficiency and continuously improving and reevaluating said process. I wrote an article about what DevOps engineers do, you can check it out at &lt;a href="https://medium.com/@israeltheory/devops-the-big-picture-c925da59d08f" rel="noopener noreferrer"&gt;The Big Picture&lt;/a&gt; and if you're looking for engineers you can check out &lt;a href="https://hng.tech/hire/devops-engineers" rel="noopener noreferrer"&gt;DevOps Engineers&lt;/a&gt; &amp;amp; &lt;a href="https://hng.tech/hire/cloud-engineers" rel="noopener noreferrer"&gt;Cloud Engineers&lt;/a&gt; for rockstar professionals.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Setting up the Ubuntu server with AWS
&lt;/h2&gt;

&lt;p&gt;To do this we'll head over to &lt;a href="https://aws.amazon.com/" rel="noopener noreferrer"&gt;AWS's Website&lt;/a&gt; then find your way to the console at the top right hand corner. It should look like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ew6yzddy7nvqf7oqi1c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ew6yzddy7nvqf7oqi1c.png" alt="AWS Console" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we're going to search for EC2 and launch an Ubuntu instance with settings that'll serve our purpose and cost the least, cost optimization, remember ;).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Name the instance and select Ubuntu on the quick start tab&lt;/li&gt;
&lt;li&gt;Select t2.micro and create a keypair, I like to use .pem ones.&lt;/li&gt;
&lt;li&gt;Next i created a security group and allowed HTTP/HTTPS traffic from the internet and ssh traffic from my IP. &lt;/li&gt;
&lt;li&gt;create and access the server with
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; ssh -i &amp;lt;yourkeypair.pem&amp;gt; ubuntu@&amp;lt;serveripaddress&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but don't forget to give execution permissions with chmod u+x keypair.pem&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Installing and configuring Nginx
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Now we are in the server we can install Nginx with these commands. &lt;br&gt;
you can just run them in a script but it's advisable to first put them in one by one to get a feel of how it's done&lt;br&gt;
&lt;code&gt;sudo apt update &amp;amp;&amp;amp; sudo apt install -y nginx&lt;br&gt;
sudo systemctl start nginx&lt;br&gt;
sudo systemctl enable nginx&lt;/code&gt;&lt;br&gt;
These will install Nginx, confirm it's running and make sure it automatically runs when you restart.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Navigate to the Nginx web directory with&lt;br&gt;
&lt;code&gt;cd /var/www/html&lt;/code&gt;&lt;br&gt;
open a new index.html file with &lt;br&gt;
&lt;code&gt;vi index.html&lt;/code&gt;&lt;br&gt;
and paste a basic html file &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;save and exit vim with :wq and the earlier command ensures Nginx automatically restarts and you can see changes to your site at once.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ws7i0bap6zpnlfrpwch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ws7i0bap6zpnlfrpwch.png" alt="Updated page" width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges &amp;amp; Contribution to learning
&lt;/h2&gt;

&lt;p&gt;This was a joy to work on, taking me back to my early days when tasks like these took me more than 5 mins to work on. I had trouble deciding whether to use a domain name or not, i went with no because it just was easier.&lt;br&gt;
Now i had fun writing this article and it reignited the fire i once had for writing, so now i plan to write more articles and fully commit to a writing style. Thanks HNG&lt;/p&gt;

</description>
      <category>devops</category>
      <category>nginx</category>
    </item>
  </channel>
</rss>
