Skip to main content

Self-Hosting Guide: Deploy Medusa for E-Commerce

·OSSAlt Team
medusae-commerceself-hostingdockerguide

Self-Hosting Guide: Deploy Medusa for E-Commerce

Medusa is the open source Shopify alternative — a headless commerce platform with no transaction fees, full API access, and a modular architecture. Self-hosting means you own your store completely.

Requirements

  • VPS with 2 GB RAM minimum (4 GB recommended)
  • Node.js 20+ or Docker
  • Domain name (e.g., store.yourdomain.com)
  • PostgreSQL database
  • Redis
  • 20+ GB disk

Step 1: Create Medusa Project

# Create new Medusa project
npx create-medusa-app@latest my-store
cd my-store

# Or clone for Docker setup
git clone https://github.com/medusajs/medusa.git
cd medusa

Step 2: Docker Compose Setup

# docker-compose.yml
services:
  medusa:
    build: .
    container_name: medusa
    restart: unless-stopped
    ports:
      - "9000:9000"
    environment:
      - DATABASE_URL=postgresql://medusa:your-strong-password@db:5432/medusa
      - REDIS_URL=redis://redis:6379
      - JWT_SECRET=your-jwt-secret
      - COOKIE_SECRET=your-cookie-secret
      - STORE_CORS=https://store.yourdomain.com
      - ADMIN_CORS=https://admin.yourdomain.com
    depends_on:
      - db
      - redis

  db:
    image: postgres:16-alpine
    container_name: medusa-db
    restart: unless-stopped
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=medusa
      - POSTGRES_USER=medusa
      - POSTGRES_PASSWORD=your-strong-password

  redis:
    image: redis:7-alpine
    container_name: medusa-redis
    restart: unless-stopped
    volumes:
      - redis_data:/data

volumes:
  postgres_data:
  redis_data:

Generate secrets:

openssl rand -hex 32  # JWT_SECRET
openssl rand -hex 32  # COOKIE_SECRET

Step 3: Start Medusa

docker compose up -d

# Run migrations and seed
docker exec medusa npx medusa db:migrate
docker exec medusa npx medusa seed --seed-file=data/seed.json

Admin dashboard at http://localhost:9000/app API at http://localhost:9000

Step 4: Reverse Proxy (Caddy)

# /etc/caddy/Caddyfile

# API and Admin
admin.yourdomain.com {
    reverse_proxy localhost:9000
}

# Storefront (Step 6)
store.yourdomain.com {
    reverse_proxy localhost:3000
}
sudo systemctl restart caddy

Step 5: Set Up Payments

Stripe (recommended):

npm install medusa-payment-stripe

Configure in medusa-config.js:

module.exports = {
  plugins: [{
    resolve: 'medusa-payment-stripe',
    options: {
      api_key: process.env.STRIPE_API_KEY,
      webhook_secret: process.env.STRIPE_WEBHOOK_SECRET,
    },
  }],
}

Set environment variables:

STRIPE_API_KEY=sk_live_your_key
STRIPE_WEBHOOK_SECRET=whsec_your_secret

No transaction fees from Medusa — only Stripe's standard 2.9% + $0.30.

Step 6: Deploy Storefront

Next.js Starter (recommended):

npx create-medusa-app@latest --with-nextjs-starter
cd my-store-storefront

# Configure
echo "NEXT_PUBLIC_MEDUSA_BACKEND_URL=https://admin.yourdomain.com" > .env.local

# Build and start
npm run build
npm start

Or build a custom storefront with any framework using the Medusa JS SDK:

import Medusa from '@medusajs/js-sdk'

const medusa = new Medusa({ baseUrl: 'https://admin.yourdomain.com' })

// List products
const { products } = await medusa.store.products.list()

// Get product details
const { product } = await medusa.store.products.retrieve('prod_123')

// Create cart
const { cart } = await medusa.store.carts.create({})

// Add item to cart
await medusa.store.carts.lineItems.create(cart.id, {
  variant_id: 'variant_123',
  quantity: 1,
})

// Complete checkout
const { order } = await medusa.store.carts.complete(cart.id)

Step 7: Configure Products

In the admin dashboard (admin.yourdomain.com/app):

  1. ProductsAdd Product

    • Title, description, images
    • Variants (size, color)
    • Pricing (multiple currencies)
    • Inventory tracking
  2. Collections → organize products into groups

  3. Gift Cards → create gift card products

  4. Discounts → percentage or fixed amount codes

Step 8: Configure Shipping and Tax

Shipping:

  1. SettingsRegions → add your regions
  2. SettingsShipping → add shipping options per region
  3. Configure flat rate, free shipping, or calculated rates

Tax:

  1. SettingsTax → configure tax rates per region
  2. Or integrate TaxJar for automatic calculation

Email notifications:

npm install medusa-plugin-sendgrid
# or
npm install medusa-plugin-resend

Step 9: Set Up Admin Users

# Create admin user via CLI
docker exec medusa npx medusa user --email admin@yourdomain.com --password your-password

Or invite via Admin Dashboard → SettingsTeam.

Production Hardening

File storage (S3 for product images):

npm install medusa-file-s3
// medusa-config.js
plugins: [{
  resolve: 'medusa-file-s3',
  options: {
    s3_url: 'https://s3.yourdomain.com',
    bucket: 'medusa-uploads',
    region: 'us-east-1',
    access_key_id: process.env.S3_ACCESS_KEY,
    secret_access_key: process.env.S3_SECRET_KEY,
  },
}],

Backups:

# Database backup (daily cron)
docker exec medusa-db pg_dump -U medusa medusa > /backups/medusa-$(date +%Y%m%d).sql

# File storage backup (if using local)
tar czf /backups/medusa-uploads-$(date +%Y%m%d).tar.gz ./uploads

Updates:

npm install @medusajs/medusa@latest
npx medusa db:migrate
docker compose restart medusa

Monitoring:

  • Monitor API endpoint (port 9000)
  • Monitor storefront (port 3000)
  • Track order completion rates
  • Set up alerts for failed payments

Resource Usage

ProductsRAMCPUDisk
1-1002 GB2 cores10 GB
100-1K4 GB4 cores30 GB
1K-10K8 GB8 cores50 GB

VPS Recommendations

ProviderSpec (500 products)Price
Hetzner4 vCPU, 8 GB RAM€8/month
DigitalOcean2 vCPU, 4 GB RAM$24/month
Linode2 vCPU, 4 GB RAM$24/month

vs Shopify Basic ($39/month + 2.9% fees): At $10K/month revenue, Shopify costs $639/month. Medusa on Hetzner costs $8/month + Stripe's 2.9%.


Compare e-commerce platforms on OSSAlt — features, transaction fees, and flexibility side by side.