Manual install (advanced)
Manual install (advanced)
Section titled “Manual install (advanced)”Prerequisites
Section titled “Prerequisites”- VPS or cloud VM with Ubuntu 22.04+ (2 vCPU / 4 GB RAM minimum for a single-tenant install)
- Node.js 22 LTS installed (CLAUDE.md §2.1 — older majors are not tested)
- PostgreSQL 16+ running (local or managed)
- Redis 7+ running (in-memory fallback exists in dev only — production needs a real Redis)
- Domain name with DNS pointed to your server
- Valid license JWT (
ECOMMUS_LICENSE) issued by Media Design SRL
1. Source delivery
Section titled “1. Source delivery”You must already have the source on disk. Two paths (per ADR-015):
| Mode | What you receive | How to refresh |
|---|---|---|
| Private Git collaborator | Read access to MDLABS-cmd/ecommus | git pull origin <release-tag> |
| Per-release tarball | Signed .tar.gz for each tagged release | New tarball on every release; verify the GPG signature |
Premium plugins / themes always pull from the private npm registry, gated by your license JWT.
2. Environment configuration
Section titled “2. Environment configuration”Set these on the server (via .env, your hosting provider’s secrets manager, or systemd EnvironmentFile=):
NODE_ENV=productionDATABASE_MODE=postgresDATABASE_URL=postgres://ecommus:CHANGE_ME@localhost:5432/ecommus_prod
# Auth — separate access + refresh secrets are mandatory in production.# The API refuses to boot if either is missing or starts with "dev-".JWT_ACCESS_SECRET=<min-32-char-random>JWT_REFRESH_SECRET=<different-min-32-char-random>
# Cache + queuesREDIS_URL=redis://localhost:6379
# License — your customer license JWT (Ed25519 signed by license-server)ECOMMUS_LICENSE=eyJhbGciOiJFZERTQSI...
# Public URLsFRONTEND_URL=https://mystore.roADMIN_URL=https://admin.mystore.roSUPER_ADMIN_URL=https://superadmin.mystore.ro
# Private npm registry (premium plugin downloads)NPM_REGISTRY_URL=https://npm.ecommus.cloudNPM_REGISTRY_TOKEN=<your license-bound npm token>Generate strong secrets:
node -e "console.log(require('crypto').randomBytes(48).toString('hex'))"The complete environment reference (every key, default, required-in-prod flag) lives at Environment Variables.
3. Database setup
Section titled “3. Database setup”# Create database and userpsql -U postgres <<SQLCREATE DATABASE ecommus_prod;CREATE USER ecommus WITH PASSWORD 'CHANGE_ME';GRANT ALL PRIVILEGES ON DATABASE ecommus_prod TO ecommus;SQL
# Run migrationsDATABASE_MODE=postgres \DATABASE_URL=postgres://ecommus:CHANGE_ME@localhost:5432/ecommus_prod \ node --experimental-strip-types packages/db/src/migrate.ts4. Build the apps
Section titled “4. Build the apps”# Install workspace dependencies (uses your license-bound npm token for premium scopes)npm ci
# Build storefrontnpm --workspace @ecommus/storefront-astro run build
# Build admin (Next.js standalone output)npm --workspace @ecommus/admin run build
# Build super-adminnpm --workspace @ecommus/super-admin run build
# Build APInpm --workspace @ecommus/api run build5. Run the services
Section titled “5. Run the services”Use a process manager like pm2 (or systemd / Docker). Production must run four processes — API, Admin, Super-admin, Storefront:
npm install -g pm2
pm2 start dist/apps/api/server.js --name ecommus-api --env productionpm2 start "next start -p 3001" --name ecommus-admin --cwd apps/adminpm2 start "next start -p 3002" --name ecommus-super-admin --cwd apps/super-adminpm2 start "node ./dist/server/entry.mjs" --name ecommus-storefront --cwd apps/storefront-astro
pm2 startuppm2 saveIf you also self-host the license server, add a fifth process for it on a separate VM (recommended: don’t co-locate with customer tenants).
6. Reverse proxy (Caddy or Nginx)
Section titled “6. Reverse proxy (Caddy or Nginx)”The framework’s deploy guide ships a Caddyfile — Caddy is the recommended path because it auto-provisions Let’s Encrypt certs and the template already routes the four upstreams. Nginx works too:
server { listen 443 ssl http2; server_name api.mystore.ro; location / { proxy_pass http://127.0.0.1:4000; proxy_http_version 1.1; }}server { listen 443 ssl http2; server_name admin.mystore.ro; location / { proxy_pass http://127.0.0.1:3001; proxy_http_version 1.1; }}server { listen 443 ssl http2; server_name superadmin.mystore.ro; location / { proxy_pass http://127.0.0.1:3002; proxy_http_version 1.1; }}server { listen 443 ssl http2; server_name mystore.ro www.mystore.ro; location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; }}Provision certs:
certbot --nginx -d mystore.ro -d www.mystore.ro -d admin.mystore.ro -d superadmin.mystore.ro -d api.mystore.ro7. Health checks
Section titled “7. Health checks”curl https://api.mystore.ro/health # {ok:true, db:true, redis:true}curl https://admin.mystore.ro/api/health # {ok:true, app:"admin"}curl https://superadmin.mystore.ro/api/health # {ok:true, app:"super-admin"}If any returns non-200, the corresponding service is down — re-check pm2 logs <name> first.
8. Updating
Section titled “8. Updating”The supported upgrade flow is documented in Upgrade procedure (semver policy, pre-upgrade checklist, migrations, rollback). The short manual version:
# Snapshot the DB FIRST (see deployment/backup-restore for the full drill)pg_dump -Fc ecommus_prod > /backup/ecommus_prod-$(date +%F-%H%M).dump
# Pull the new releasegit fetch --tagsgit checkout v<new-release>npm ci
# Re-build the apps (same commands as step 4)npm --workspace @ecommus/storefront-astro run buildnpm --workspace @ecommus/admin run buildnpm --workspace @ecommus/super-admin run buildnpm --workspace @ecommus/api run build
# Run any new migrationsnode --experimental-strip-types packages/db/src/migrate.ts
# Reload all four processespm2 reload allIf the release notes mention breaking changes in plugin contracts, run plugin smoke tests before promoting.
See also
Section titled “See also”- Customer Onboarding — recommended provisioning playbook
- Environment Variables — full reference
- License — JWT shape, tier matrix, grace period
- Backup & Restore — RPO/RTO, off-site target, restore drill
- Upgrade procedure — semver policy, rollback