GuideVPSAdvanced

MedusaJS Production Deployment Guide using Docker on any Linux server

This comprehensive guide walks you through deploying a production-ready MedusaJS e-commerce platform using Docker on any Linux server.

Prerequisites

Before starting, ensure you have:

  • A Linux server with root/sudo access (Ubuntu, Debian, CentOS, RHEL, etc.)
  • Docker and Docker Compose installed
  • Git installed
  • At least 2GB RAM and 20GB disk space

1. Clone Your Project

Clone your MedusaJS project to your server. This guide assumes your repository has a backend directory and a storefront directory at the root level:

git clone <your-medusa-repository-url>
cd your-medusa-project

2. Set Up Backend Configuration

2.1 Navigate to Backend Directory

cd backend

2.2 Download Starter Configuration Files

Find the file contents here: https://github.com/u11d-com/medusa-starter/tree/main/backend

curl -O https://raw.githubusercontent.com/u11d-com/medusa-starter/main/backend/start.sh
curl -O https://raw.githubusercontent.com/u11d-com/medusa-starter/main/backend/Dockerfile
curl -O https://raw.githubusercontent.com/u11d-com/medusa-starter/main/backend/.dockerignore

chmod +x start.sh

2.3 Download and Configure medusa-config.ts

curl -O https://raw.githubusercontent.com/u11d-com/medusa-starter/main/backend/medusa-config.ts

Important: Review the downloaded medusa-config.ts file and adjust settings according to your project. If you want to use Meilisearch with the provided stack and medusa-config.ts, please install the following additional package to your project:

npm install @rokmohar/medusa-plugin-meilisearch
# or
yarn add @rokmohar/medusa-plugin-meilisearch

2.4 Update package.json

Add or modify the start script in your package.json:

{
  "scripts": {
    "start": "./start.sh"
  }
}

3. Set Up Storefront Configuration

3.1 Navigate to Storefront Directory

cd ../storefront

3.2 Download Storefront Files

curl -O https://raw.githubusercontent.com/u11d-com/medusa-starter/main/storefront/Dockerfile
curl -O https://raw.githubusercontent.com/u11d-com/medusa-starter/main/storefront/.dockerignore

3.3 Download Next.js Configuration

curl -O https://raw.githubusercontent.com/u11d-com/medusa-starter/main/storefront/next.config.js

Note: Verify that the configuration matches your project structure and requirements before proceeding.

4. Configure Docker Compose

4.1 Navigate to Project Root

cd ..

4.2 Download Docker Compose Files

curl -O https://raw.githubusercontent.com/u11d-com/medusa-starter/main/compose.yaml
curl -O https://raw.githubusercontent.com/u11d-com/medusa-starter/main/compose.storefront.yaml

4.3 Edit Backend Compose File

Edit compose.yaml to:

  • Set your backend environment variables
  • Update your backend directory in context:
  • Change admin and database credentials for security

5. Launch Backend Services

5.1 Start Services

Launch PostgreSQL, Redis, and the Medusa backend:

docker compose up -d

5.2 Wait for Initialization

Wait 30-60 seconds for services to fully initialize.

5.3 Verify Services

Check that all services are running:

docker compose ps

You should see six healthy services:

  • postgres (Database)
  • redis (Cache & Event Bus)
  • meilisearch (Search Engine)
  • minio (S3 Compatible Object Storage)
  • zipkin (Distributed Tracing)
  • backend-server (Medusa backend)

6. Set Up Nginx Reverse Proxy

6.1 Install Nginx

sudo apt update
sudo apt install nginx

6.2 Create Nginx Configuration

sudo nano /etc/nginx/sites-available/app.conf

Paste this configuration:

server {
    listen 80;
    server_name _;

    location / {
        proxy_pass http://127.0.0.1:8000;
        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;
    }

    location /auth {
        proxy_pass http://127.0.0.1:9000;
        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;
    }

    location /app {
        proxy_pass http://localhost:9000;
        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;
    }

    location /admin {
        proxy_pass http://localhost:9000;
        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;
    }

    location /store {
        proxy_pass http://localhost:9000;
        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;
    }
}

6.3 Remove Default Configuration

sudo rm /etc/nginx/sites-enabled/default

6.4 Enable New Configuration

sudo ln -s /etc/nginx/sites-available/app.conf /etc/nginx/sites-enabled/

6.5 Reload Nginx

sudo systemctl reload nginx

6. Access Admin Panel

Open your browser and navigate to:

http://your-public-ip/app

Important: If you cannot reach Nginx on port 80 (HTTP), be aware that some cloud providers' machine images (for example, Oracle) block the port by default at the OS firewall level. In that case, follow Step 10: Configure Firewall with UFW to ensure HTTP traffic is allowed.

Log in using the credentials you set in compose.yaml:

  • MEDUSA_ADMIN_EMAIL
  • MEDUSA_ADMIN_PASSWORD

6.1 Generate API Key

In the admin panel:

  1. Go to Settings → Publishable API Keys
  2. Click "Create"
  3. Give it a descriptive name (e.g., "Storefront Production")
  4. Click Save
  5. Copy the generated key

6.2 Create a Region

In the admin panel:

  1. Go to Settings → Regions
  2. Click "Create"
  3. Fill in the region details.
  4. Add countries to the region:
    • Click "Add Country"
    • Select one or more countries from the dropdown
    • You can add multiple countries to a single region
  5. Click "Save"

Important: At least one region with at least one country must be created for the storefront to function properly. Products must be associated with regions to be visible in the storefront.

7. Update Storefront Configuration

7.1 Edit Storefront Compose File

Edit your compose.storefront.yaml:

  • Set your storefront environment variables
  • Update your storefront directory in context:

7.2 Add Publishable Key

Paste the publishable key you copied into the environment section:

environment:
  - NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY=<your-publishable-key>

8. Deploy Storefront

8.1 Build and Start

docker compose -f compose.storefront.yaml up --build -d

Note: The initial build may take 5-10 minutes depending on your server specifications.

8.2 Access Your Storefront

Navigate to:

http://your-server-ip/

You should see your live MedusaJS storefront running on port 8000.

This comprehensive guide walks you through deploying a production-ready MedusaJS e-commerce platform using Docker on any Linux server.

9. Configure SSL with Let's Encrypt

Secure your site with a free SSL certificate from Let's Encrypt using Certbot.

9.1 Install Certbot

sudo apt update
sudo apt install certbot python3-certbot-nginx -y

9.2 Configure DNS

In your DNS panel (Cloudflare, OVH, Google Domains, etc.), create an A record:

Type: A
Name: yourdomain.com
Value: <your-server-public-IP>
TTL: Auto

Wait a few minutes for DNS propagation.

9.4 Configure your server name in Nginx

Replace:

listen 80;
    server_name _;

with:

listen 80;
    server_name <your-domain>;

9.3 Obtain SSL Certificate

sudo certbot --nginx -d yourdomain.com

Replace yourdomain.com with your real domain.

Certbot will automatically:

  • Detect your existing HTTP server block
  • Create an HTTPS server block with proper SSL paths
  • Optionally configure HTTP → HTTPS redirection

9.4 Reload Nginx

sudo systemctl reload nginx

9.5 Verify your domain

Storefront:

https://yourdomain.com/

API Endpoints:

https://yourdomain.com/admin
https://yourdomain.com/app
https://yourdomain.com/store

Important: If you cannot reach Nginx on port 443 (HTTPS), be aware that some cloud providers' machine images (for example, Oracle) block the port by default at the OS firewall level. In that case, follow Step 10: Configure Firewall with UFW to ensure HTTPS traffic is allowed.

10. Configure Firewall with UFW (Optional but Recommended)

If you're using Ubuntu or another distribution with UFW (Uncomplicated Firewall), you can secure your server by only allowing necessary traffic.

10.1 Install UFW (if not installed)

sudo apt update
sudo apt install ufw -y

10.2 Set Default Policies

First, set sane defaults (deny all incoming, allow all outgoing):

sudo ufw default deny incoming
sudo ufw default allow outgoing

10.3 Allow SSH, HTTP and HTTPS

sudo ufw allow OpenSSH
sudo ufw allow http
sudo ufw allow https

If you are running SSH on a non-standard port (e.g. 2222), also allow it:

sudo ufw allow 2222/tcp

10.4 Enable UFW

Then enable UFW and verify the status:

VERY IMPORTANT: Before enabling UFW, make sure you have allowed SSH (and your custom SSH port, if you use one). Otherwise, you may lock yourself out of the server when the firewall is enabled.

sudo ufw enable
sudo ufw status verbose

After enabling, UFW will:

  • Allow incoming SSH, HTTP (80) and HTTPS (443) traffic (based on the rules you added)
  • Deny all other incoming connections by default
  • Allow all outgoing traffic by default

You usually do not need to open Docker's internal ports (8000, 9000, database, etc.) directly in UFW, because they are not exposed publicly and Nginx acts as the secure external entry point.

Need Help with Your Deployment?

Whether you're looking for expert consultation or want to explore our open-source resources, we're here to help you succeed with your Medusa deployment.

Fast response times • Flexible engagement • Production-ready solutions