Customer Onboarding
Customer onboarding
Section titled “Customer onboarding”You’ve completed checkout, your inbox has a “Licența ta Ecommus … este activă” email, and now you need to install ecommus on your server. This page walks you from that email to a working install in under 60 minutes.
If you’re evaluating ecommus and haven’t bought yet, start with Introduction instead.
What you got in the email
Section titled “What you got in the email”The license-delivery email contains:
- JWT (license token) — single line of base64. Don’t share it; don’t paste it in screenshots; it’s how the framework knows your install is paid.
- Niche package(s) you bought —
services,real-estate,travel, orecommerce(or a combination). - Tier —
community,pro, orenterprise. Drives which plugins/themes you can install. - Subscription period —
3mo/9mo/12mo. The expiry timer starts now. - An npm token — used to download premium plugins from the private registry. Often delivered in a separate email after domain confirmation.
Keep all of these somewhere safe (1Password / Vault / pass). If you lose them, your operator can resend, but it’s friction.
What you need on your side
Section titled “What you need on your side”Minimum, all required:
- A VPS running Ubuntu 22.04 or 24.04 LTS — recommended specs 4 vCPU / 8 GB RAM / 80 GB SSD for a single tenant. Bigger if you plan to host multiple shops.
- A domain you control (e.g.
myshop.com). Three subdomains will be auto-created: storefront (myshop.com), admin (admin.myshop.com), api (api.myshop.com). - DNS access — Cloudflare, Route 53, or your registrar’s panel.
- Stripe account — for accepting customer payments. Test mode is fine to start; live mode requires KYC.
- An email sending account — Resend (recommended free tier, 3000 emails/mo) or any SMTP provider.
You don’t need to know docker or systemd to get started — the install script handles it.
Step 1 — provision the VPS (3 min)
Section titled “Step 1 — provision the VPS (3 min)”If you ordered the recommended VPS (Hetzner CCX23 or equivalent), you’ll receive an IP + root password. From your laptop:
# Replace with values from your purchase emailexport VPS_IP=1.2.3.4export ECOMMUS_DOMAIN=myshop.comexport ECOMMUS_ADMIN_EMAIL=ops@myshop.com
# Run the bootstrap script (system update + docker + caddy + firewall + ssh hardening)ssh root@$VPS_IP \ ECOMMUS_DEPLOY_USER=ecommus \ ECOMMUS_DEPLOY_PUBKEY="$(cat ~/.ssh/id_ed25519.pub)" \ ECOMMUS_DOMAIN=$ECOMMUS_DOMAIN \ ECOMMUS_ADMIN_EMAIL=$ECOMMUS_ADMIN_EMAIL \ bash -s < <(curl -fsSL https://raw.githubusercontent.com/MDLABS-cmd/ecommus/master/infra/provision.sh)The script prints “ecommus provision: run mode complete” when done. About 3 minutes on a fresh server.
Don’t have an SSH key yet? Run
ssh-keygen -t ed25519 -C "you@laptop"on your laptop first. Press Enter through the prompts (default location, no passphrase for first install — add one later).
Step 2 — DNS records (5 min + propagation)
Section titled “Step 2 — DNS records (5 min + propagation)”Add these records at your DNS provider:
| Type | Name | Value | TTL |
|---|---|---|---|
| A | @ (apex) | your VPS IP | 300 |
| A | * (wildcard) | your VPS IP | 300 |
| CAA | @ | 0 issue "letsencrypt.org" | 3600 |
| CAA | @ | 0 issuewild "letsencrypt.org" | 3600 |
If you use Cloudflare: set the orange cloud to DNS only (grey) for now. Caddy needs direct port-80 access to issue Let’s Encrypt certs. You can flip the proxy back on after the first cert is issued.
Verify propagation (~5 min):
dig +short api.$ECOMMUS_DOMAIN# Should print your VPS IPStep 3 — install ecommus + paste your license (10 min)
Section titled “Step 3 — install ecommus + paste your license (10 min)”SSH in as the deploy user:
ssh ecommus@$VPS_IPPull the source + install dependencies:
cd /opt/ecommusgit clone https://github.com/MDLABS-cmd/ecommus.git repocd repogit checkout v1.0.0 # or the latest tag from the release notes
# Authenticate npm to the private registry using YOUR token from the second emailnpm config set "@ecommus:registry" "https://npm.ecommus.ro" --location=usernpm config set "//npm.ecommus.ro/:_authToken" "YOUR_NPM_TOKEN_HERE" --location=user
# Install (this pulls premium plugins your tier is licensed for)npm installNow create your .env:
cp infra/.env.production.template /opt/ecommus/.envchmod 600 /opt/ecommus/.envln -sf /opt/ecommus/.env .envnano /opt/ecommus/.envReplace every TODO_GENERATE with a strong secret:
# Quick generators (paste output into the matching .env line)echo "POSTGRES_PASSWORD=$(openssl rand -base64 32 | tr -d '/+=' | head -c 32)"echo "JWT_ACCESS_SECRET=$(openssl rand -base64 64 | tr -d '/+=' | head -c 64)"echo "JWT_REFRESH_SECRET=$(openssl rand -base64 64 | tr -d '/+=' | head -c 64)"echo "LICENSE_SERVER_ADMIN_TOKEN=$(openssl rand -hex 32)"Paste your license JWT into:
ECOMMUS_LICENSE_JWT=eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9....Save + close.
Step 4 — first boot (5 min)
Section titled “Step 4 — first boot (5 min)”Bring up the stack:
cd /opt/ecommus/repodocker compose pull postgres redis verdaccio license-serverdocker compose up -d postgres redis # data plane firstsleep 15docker compose ps # postgres should show "healthy"docker compose build license-serverdocker compose up -d # everything elseVerify all containers are running:
docker compose ps# All services should show "Up" and "(healthy)" where applicableHealth check the API:
curl -fsS http://127.0.0.1:4000/health# {"ok":true,"service":"api","version":"1.0.0",...}Step 5 — Caddy reverse proxy + HTTPS (5 min)
Section titled “Step 5 — Caddy reverse proxy + HTTPS (5 min)”Render the Caddyfile from the template:
sudo cp /opt/ecommus/repo/infra/Caddyfile.template /etc/caddy/Caddyfilesudo sed -i "s/{{DOMAIN}}/$ECOMMUS_DOMAIN/g; s/{{ADMIN_EMAIL}}/$ECOMMUS_ADMIN_EMAIL/g" \ /etc/caddy/Caddyfile
sudo caddy validate --config /etc/caddy/Caddyfilesudo systemctl reload caddy
# Watch certificates being issuedsudo journalctl -u caddy -f# Wait until you see "certificate obtained successfully" for each subdomainExternal verification:
# From your laptopcurl -I https://api.$ECOMMUS_DOMAIN/health# HTTP/2 200 + valid TLSStep 6 — first admin login (2 min)
Section titled “Step 6 — first admin login (2 min)”Open in your browser:
https://admin.myshop.com/loginDefault operator account is in your email (or generated by the install script — check docker compose logs api | grep "default admin"). Log in.
You should land on the admin dashboard. The page header shows your tier + niche package(s).
Step 7 — wire Stripe (10 min)
Section titled “Step 7 — wire Stripe (10 min)”In the Stripe dashboard:
- Webhooks → Add endpoint → URL:
https://api.myshop.com/api/webhooks/stripe - Select events:
checkout.session.completed,payment_intent.succeeded,payment_intent.payment_failed - Copy the Signing secret — paste into
STRIPE_WEBHOOK_SECRETin.env - Copy your Secret key + Publishable key from API keys page — paste into
STRIPE_SECRET_KEY+STRIPE_PUBLISHABLE_KEY(the Stripe-canonical name; older docs may referenceSTRIPE_PUBLIC_KEY— that’s a typo, code readsSTRIPE_PUBLISHABLE_KEY) - Restart the api container so it picks up the new env:
docker compose restart apiTest from Stripe dashboard’s “Send test webhook” → expect 200 OK.
Step 8 — wire Resend (or your SMTP) (5 min)
Section titled “Step 8 — wire Resend (or your SMTP) (5 min)”Resend (recommended):
- Sign up at resend.com, free tier
- Domains → Add Domain →
myshop.com - Add the 3 DNS records (DKIM × 2 + SPF) at your DNS provider
- Wait ~10 min, click “Verify” — should turn green
- API Keys → Create API Key →
ecommus-prod - Paste into
RESEND_API_KEYin.env, restart api:
docker compose restart apiTest by triggering a password reset on your admin account — email should arrive in seconds.
If you prefer SMTP (your existing email host), replace RESEND_API_KEY with SMTP_HOST + SMTP_PORT + SMTP_USER + SMTP_PASS in .env. See Environment Variables for the full list.
Step 9 — verify everything is green
Section titled “Step 9 — verify everything is green”# On the VPScd /opt/ecommus/reponode --env-file=/opt/ecommus/.env scripts/full-buying-flow-e2e.mjsExpected output:
✅ FULL BUYING FLOW E2E: GREEN - Install: t1-buyflow-1234567890 - Subscription: sub_test_1234567890 - Events: payment_failed, cancelled, email_resent, renewed, issued - Mails: 3 (delivery + renewal + resend)If it fails, the failing step name tells you exactly what to fix. Most common: Stripe webhook secret typo, or Resend domain not yet verified.
Step 10 — set up backups
Section titled “Step 10 — set up backups”Daily Postgres dump (7-day retention):
# As ecommus usersudo -u ecommus mkdir -p /opt/ecommus/backups
crontab -e -u ecommus# Add this line:0 3 * * * cd /opt/ecommus/repo && docker compose exec -T postgres pg_dumpall -U ecommus | gzip > /opt/ecommus/backups/pg_$(date +\%F).sql.gz && find /opt/ecommus/backups -name 'pg_*.sql.gz' -mtime +7 -deleteFor off-server backup (recommended once you have real customers), pipe the dump to S3 / Backblaze B2 / Google Drive via rclone. The server-local dump is your “oh no I deleted a tenant” lifeline; the off-server copy is your “the datacenter is on fire” lifeline.
You’re done
Section titled “You’re done”If full-buying-flow-e2e.mjs is green and admin login works:
- Your install is production-ready for a single tenant
- Your license is active until the date shown in the admin header
- The buying-flow + anti-piracy + ops + renewal loops are all live
Next steps:
- Read Choose your niche package below
- For ongoing operations, bookmark the super-admin panel at
https://superadmin.myshop.com - Subscribe to the release notes so you don’t miss security updates
Choosing your niche package
Section titled “Choosing your niche package”The four canonical niche packages, what each ships with by default, and what’s included on each tier:
| Package | Default theme | Default plugins (community+) | Optional add-ons (pro+) |
|---|---|---|---|
services | theme-services | niche-booking, efactura-ro, notifications-sms | niche-healthcare, niche-fitness |
real-estate | theme-realestate | niche-real-estate, efactura-ro | maps-integration, lead-management |
travel | theme-travel | niche-hotel, niche-booking, efactura-ro | payment-stripe-deposits |
ecommerce | theme-fashion | niche-ecommerce, efactura-ro, shipping-sameday | marketplace-emag, marketplace-amazon, payment-netopia |
Switching package after install requires a license re-issue from your operator — talk to them before doing it; it’s not free.
Common issues
Section titled “Common issues”| Symptom | Most likely cause | Fix |
|---|---|---|
caddy reload fails with “tls handshake error” | DNS hasn’t propagated, or Cloudflare proxy is still on (orange cloud) | dig to verify; set Cloudflare records to DNS-only |
docker compose up fails on postgres healthcheck | wrong POSTGRES_PASSWORD between .env and existing data volume | rotate the env value (preferred) OR docker volume rm ecommus_postgres_data (DESTRUCTIVE — only on a fresh install) |
| Stripe webhook returns 400 invalid_signature | wrong STRIPE_WEBHOOK_SECRET for that endpoint | each Stripe endpoint has its own secret; copy the one for THIS endpoint |
| Resend emails go to spam | domain not verified / no DKIM | finish the DKIM step, wait an hour for inbox-provider reputation to update |
npm install fails with 401 Unauthorized on @ecommus/... | wrong / expired NPM token | check the email; tokens are tier-bound — pro-tier token can’t pull enterprise plugins |
| Browser shows “self-signed cert” warning | Caddy fell back to staging because real ACME failed | sudo journalctl -u caddy -n 100 — look for the actual ACME error |
Where to get help
Section titled “Where to get help”- Operator support email (in your purchase confirmation) — for license / billing / account issues
- GitHub Discussions at
github.com/MDLABS-cmd/ecommus/discussions— for install + plugin questions - Status page at
status.ecommus.ro— when license-server / npm.ecommus.ro is having a bad day
When asking for help, always include:
- Your install_id (from
cat /opt/ecommus/.env | grep INSTALL_ID) - The output of the failing command (full, no edits)
docker compose ps(which containers are up)- Last 50 lines of relevant logs (
docker compose logs --tail 50 api)