🚀

EcomCentral — Deployment Guide

Requirements, setup, server configuration, and security checklist

← Back to App

Contents

  1. Requirements
  2. Database Setup (PostgreSQL)
  3. Local Development
  4. Apache Production Setup
  5. Nginx Production Setup
  6. Environment Variables
  7. Using config.local.php (Single-Server)
  8. Security Checklist
  9. Supabase (Managed PostgreSQL)

Requirements

ComponentMinimumRecommended
PHP8.18.3+
PostgreSQL1416+ (or Supabase)
Web serverApache 2.4 / Nginx 1.18Either
PHP extensionspdo_pgsql, curl, json, opensslSame
HTTPSRequired (Let's Encrypt is free)—
BrowserAny modern browser with ES modules support—

Database Setup (PostgreSQL)

EcomCentral stores connections, encrypted credentials, settings, and audit logs in PostgreSQL.

1. Create the database and user

-- Run as postgres superuser
CREATE DATABASE ecomcentral;
CREATE USER ecomcentral_user WITH PASSWORD 'your-strong-password';
GRANT ALL PRIVILEGES ON DATABASE ecomcentral TO ecomcentral_user;

2. Run the schema

Apply the schema SQL file from the files/ directory:

psql -U ecomcentral_user -d ecomcentral -f files/shop_api_credentials_schema.sql

3. Seed channel types (optional but recommended)

psql -U ecomcentral_user -d ecomcentral -f files/shop_channel_types_seed_extended.sql
psql -U ecomcentral_user -d ecomcentral -f files/shop_channel_types_seed_extended_2.sql
â„šī¸ The seed files populate shop_channel_types with all 45+ supported marketplaces and their API credential schemas, logos, and OAuth flags.

Local Development

Option A — PHP built-in server

# From the project root
php -S localhost:8080

Then open http://localhost:8080 in your browser.

Option B — DDEV / Lando / Herd

Place the project in your tool's webroot and point the document root to the project folder.

Config for local dev

Create api/config.local.php (it is already gitignored):

<?php
return [
    'db' => [
        'host'   => 'localhost',
        'port'   => '5432',
        'dbname' => 'ecomcentral',
        'user'   => 'ecomcentral_user',
        'pass'   => 'your-strong-password',
    ],
    'encryption_key'     => 'your-32-byte-key-here-exactly!!',
    'default_id_mandant' => 1,
];

Generate a 32-character encryption key:

openssl rand -hex 16
# or
php -r "echo bin2hex(random_bytes(16));"
âš ī¸ The encryption key must be exactly 32 characters. It encrypts all stored API credentials. Never change it after credentials have been saved — they will become unreadable.

Apache Production Setup

Virtual host configuration

<VirtualHost *:443>
    ServerName ecomcentral.example.com
    DocumentRoot /var/www/ecomcentral

    SSLEngine on
    SSLCertificateFile    /etc/letsencrypt/live/ecomcentral.example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/ecomcentral.example.com/privkey.pem

    <Directory /var/www/ecomcentral>
        Options -Indexes
        AllowOverride All
        Require all granted
    </Directory>

    # Deny direct access to internal PHP helpers
    <FilesMatch "^_">
        Require all denied
    </FilesMatch>

    # Deny access to config.local.php
    <Files "config.local.php">
        Require all denied
    </Files>
</VirtualHost>

# Redirect HTTP → HTTPS
<VirtualHost *:80>
    ServerName ecomcentral.example.com
    Redirect permanent / https://ecomcentral.example.com/
</VirtualHost>

Required Apache modules

a2enmod ssl rewrite headers
systemctl restart apache2

.htaccess (place in project root if needed)

Options -Indexes
<FilesMatch "^_.*\.php$">
    Require all denied
</FilesMatch>

Nginx Production Setup

server {
    listen 443 ssl http2;
    server_name ecomcentral.example.com;
    root /var/www/ecomcentral;
    index index.html index.php;

    ssl_certificate     /etc/letsencrypt/live/ecomcentral.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ecomcentral.example.com/privkey.pem;

    # Block directory listings
    autoindex off;

    # Block internal PHP helpers and config.local
    location ~ /api/(_.*\.php|config\.local\.php) {
        deny all;
        return 404;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    location / {
        try_files $uri $uri/ =404;
    }
}

server {
    listen 80;
    server_name ecomcentral.example.com;
    return 301 https://$host$request_uri;
}

Environment Variables

For container/cloud deployments (Docker, Kubernetes, Heroku, Railway, Render, etc.), set secrets as environment variables instead of using config.local.php.

VariableRequiredDescription
DB_PASS ✓ Yes PostgreSQL password
ECOM_ENCRYPT_KEY ✓ Yes 32-character AES encryption key for credentials
DB_HOST No DB host (default: aws-1-eu-central-1.pooler.supabase.com)
DB_PORT No DB port (default: 5432)
DB_NAME No Database name (default: postgres)
DB_USER No Database user (default: configured Supabase user)
DEFAULT_ID_MANDANT No Default tenant ID (default: 1)

Docker example

docker run -d \
  -e DB_HOST=your-db-host \
  -e DB_PASS=your-db-password \
  -e ECOM_ENCRYPT_KEY=your32charencryptionkeyhere!! \
  -p 80:80 \
  your-ecomcentral-image

docker-compose.yml example

services:
  app:
    build: .
    ports: ["80:80"]
    environment:
      DB_HOST: db
      DB_PASS: ${DB_PASS}
      ECOM_ENCRYPT_KEY: ${ECOM_ENCRYPT_KEY}
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: ${DB_PASS}
      POSTGRES_DB: ecomcentral

Using config.local.php (Single-Server)

For single-server deployments where you don't use environment variables, create api/config.local.php. This file is in .gitignore and takes priority over env vars.

<?php
// api/config.local.php — NEVER commit this file
return [
    'db' => [
        'host'   => 'your-db-host',
        'port'   => '5432',
        'dbname' => 'ecomcentral',
        'user'   => 'ecomcentral_user',
        'pass'   => 'your-db-password',
    ],
    'encryption_key'     => 'your32charencryptionkeyhere!!',
    'default_id_mandant' => 1,
];
🔐 Never commit config.local.php. It is gitignored by default. Verify with git status before any push.

Security Checklist

Supabase (Managed PostgreSQL)

EcomCentral is pre-configured to work with Supabase, a managed PostgreSQL service with a generous free tier.

  1. Create a free account at supabase.com
  2. Create a new project and note the database password
  3. Go to Project Settings → Database → Connection string
  4. Copy the Connection pooling (Transaction) URI — it looks like:
    postgresql://postgres.abcdefgh:[YOUR-PASSWORD]@aws-1-eu-central-1.pooler.supabase.com:5432/postgres
  5. Go to SQL Editor and paste the contents of files/shop_api_credentials_schema.sql to create the schema
  6. Run the seed files to add channel types
  7. Set your DB_PASS to the Supabase project password and update DB_HOST, DB_USER accordingly
✓ Supabase provides automatic backups, connection pooling, and a web-based SQL editor — ideal for getting started quickly without managing your own PostgreSQL server.