selfhostedworld.com logoselfhostedworld.com

Try describing what you need:

s-cart logo

s-cart

★ 12

A self-hosted alternative to Shopify

MIT LicenseOpen Source — No Paywall6 Containers — 6 containers — moderate hosting footprintPackage · Source · DockerNeeds MySQL2 active committers (12mo)

About

S-Cart is a free, open-source e-commerce platform built on the GP247 ecosystem and Laravel. It is aimed at businesses, individual sellers, developers, and students who want to run an online shop with...

Community Ratings

No ratings yet

Features

  • products
  • cart
  • orders
  • customers
  • multi-language
  • multi-currency
  • categories
  • news
  • content pages
  • payment plugins

Details

Last Updated
Oct 10, 2026
Created
Aug 21, 2025
Install Methods
package-managersourcedocker
Requirements
PHP 8.3 or newerComposer 2.xMySQL or MariaDBWritable folders: storage, bootstrap/cache, app/GP247, public/GP247, public/vendor, resources/views/vendor, vendor
Authentication
local
API
REST
Backup & Export
database-dumpfile-backup
Runtime / Stack
PHP
Privacy & Independence
No Cloud Required
User Model
Multi-UserMulti-Tenant
Deployment

Deployment: Docker Compose ✓6 Containers — moderate hosting footprintRuns as 6 containers

Run s-cart with Docker Compose

Compose file from the s-cart project repository.

6 services · database: mysql · infra: nginx, mysql · 1 unclassified (node)

no resource limits declared

needs persistent storage (12 volumes)

docker-compose.prod.yml · @ 2560446 · scanned Sep 30, 2026

# =============================================================================
# PRODUCTION environment.
#
# Remote/managed database (default):
#   docker compose -f docker-compose.prod.yml up -d --build
#   -> set DB_HOST/DB_PORT/DB_USERNAME/DB_PASSWORD in .env to your remote DB.
#
# Dockerized MySQL instead:
#   docker compose -f docker-compose.prod.yml --profile db-local up -d --build
#   -> set DB_HOST=mysql-local in .env (the mysql-local service name).
#   (or set COMPOSE_PROFILES=db-local in .env so plain `up -d` also starts it)
#
# Same bind-mount design as dev (see docker-compose.yml for the full
# rationale): the project directory is mounted into the containers so
# `git pull` + `docker compose up -d` picks up new code with no rebuild;
# only vendor/ and node_modules/ live in named volumes for I/O performance.
#
# Project name, image tag and container names below are all suffixed/scoped
# distinctly from docker-compose.yml (dev) on purpose (RISK-OPS-006,
# NFR-SEC-005, ADR installer-deploy_docker-dev-prod-safeguards): running the
# dev compose file by mistake on a host that's already running this prod
# stack can, at worst, start an unrelated dev stack alongside it (or fail on
# a port conflict) - it can no longer silently stop/replace a running prod
# container or overwrite the prod image, which is what happened before this
# was scoped per-environment (see DOCKER.md).
# =============================================================================

# Project name derives from SC_DOCKER_INSTANCE (default "scart" -> "scart-prod", unchanged
# from before). Set SC_DOCKER_INSTANCE=<slug> in .env to run several independent S-Cart
# projects on the same host: it scopes the project name (<slug>-prod), every
# container_name (<slug>-<svc>-prod), the image tag and the named volumes below,
# so two production instances never collide or share a MySQL data volume. This
# composes with the dev/prod suffix (ADR-017): identity is <instance>-<env>, and
# the default SC_DOCKER_INSTANCE=scart reproduces exactly the previous scart-prod names.
# See ADR installer-deploy_docker-multi-instance / DOCKER.md "Run several projects on one host".
name: ${SC_DOCKER_INSTANCE:-scart}-prod

services:
  app:
    build:
      context: ./docker/php
      args:
        PHP_VERSION: ${SC_DOCKER_PHP_VERSION:-8.3}
        WWWUSER: ${SC_DOCKER_WWWUSER:-1000}
        WWWGROUP: ${SC_DOCKER_WWWGROUP:-1000}
        INSTALL_XDEBUG: "false"
    image: scart-app:${SC_DOCKER_PHP_VERSION:-8.3}${SC_DOCKER_INSTANCE:+-}${SC_DOCKER_INSTANCE:-}-prod
    container_name: ${SC_DOCKER_INSTANCE:-scart}-app-prod
    working_dir: /var/www/html
    volumes:
      - ./:/var/www/html
      - scart-vendor:/var/www/html/vendor
    # Only variables entrypoint.sh's shell logic needs (DB wait-loop) plus
    # Docker-specific overrides go here. Deliberately NOT `env_file: .env` -
    # that would inject the whole .env (including APP_KEY etc.) as frozen
    # container env vars, which phpdotenv then refuses to ever overwrite from
    # the .env file again (even after `artisan key:generate` updates it).
    # Laravel reads the rest of .env itself on every request, no forwarding
    # needed.
    environment:
      APP_ENV: production
      APP_DEBUG: "false"
      # Default REMOTE_ADDR trusts exactly one hop: the "webserver" (nginx)
      # container this compose file itself ships ("app" has no published
      # port, nginx is always its only direct peer) - it's a literal
      # sentinel Illuminate\Http\Middleware\TrustProxies substitutes with
      # the request's actual immediate peer at runtime, and it makes
      # X-Forwarded-Proto work (HTTPS URL generation). Deployments that
      # additionally sit behind an external CDN/LB (Cloudflare, GCP/AWS
      # LB...) must ALSO trust that edge's IP ranges or request()->ip()
      # stops at the edge's own hop in X-Forwarded-For and returns the
      # edge's IP instead of the visitor's: set TRUSTED_PROXIES in .env
      # (compose interpolates it here - keep REMOTE_ADDR in the list, see
      # .env.example for ready-made values) and re-run `docker compose up
      # -d`. Consumed via config/trustedproxy.php (full rationale there) -
      # Docker-only setting, bare host installs need nothing.
      TRUSTED_PROXIES: "${TRUSTED_PROXIES:-REMOTE_ADDR}"
      DB_CONNECTION: ${DB_CONNECTION:-mysql}
      DB_HOST: ${DB_HOST}
      DB_PORT: ${DB_PORT:-3306}
      DB_USERNAME: ${DB_USERNAME}
      DB_PASSWORD: ${DB_PASSWORD}
    restart: unless-stopped
    networks:
      - scart

  webserver:
    image: nginx:1.27-alpine
    container_name: ${SC_DOCKER_INSTANCE:-scart}-nginx-prod
    depends_on:
      - app
    ports:
      - "${SC_DOCKER_APP_PORT:-80}:80"
    volumes:
      - ./:/var/www/html:ro
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
    restart: unless-stopped
    networks:
      - scart

  queue:
    build:
      context: ./docker/php
      args:
        PHP_VERSION: ${SC_DOCKER_PHP_VERSION:-8.3}
        WWWUSER: ${SC_DOCKER_WWWUSER:-1000}
        WWWGROUP: ${SC_DOCKER_WWWGROUP:-1000}
        INSTALL_XDEBUG: "false"
    image: scart-app:${SC_DOCKER_PHP_VERSION:-8.3}${SC_DOCKER_INSTANCE:+-}${SC_DOCKER_INSTANCE:-}-prod
    container_name: ${SC_DOCKER_INSTANCE:-scart}-queue-prod
    working_dir: /var/www/html
    command: ["php", "artisan", "queue:work", "--sleep=3", "--tries=3", "--max-time=3600"]
    volumes:
      - ./:/var/www/html
      - scart-vendor:/var/www/html/vendor
    environment:
      # Mirror of the "app" service pins above (kept in sync by
      # DockerComposeEnvConsistencyTest). Laravel loads .env through an
      # immutable repository - a real process env var always wins - so a
      # pin on "app" alone leaves this container reading APP_ENV/APP_DEBUG
      # from the host's .env; with the .env.example default (APP_ENV=local)
      # background jobs would run in local/debug while the web tier runs in
      # production, on the same site.
      APP_ENV: production
      APP_DEBUG: "false"
      DB_CONNECTION: ${DB_CONNECTION:-mysql}
      DB_HOST: ${DB_HOST}
      DB_PORT: ${DB_PORT:-3306}
      DB_USERNAME: ${DB_USERNAME}
      DB_PASSWORD: ${DB_PASSWORD}
    depends_on:
      - app
    restart: unless-stopped
    networks:
      - scart

  scheduler:
    build:
      context: ./docker/php
      args:
        PHP_VERSION: ${SC_DOCKER_PHP_VERSION:-8.3}
        WWWUSER: ${SC_DOCKER_WWWUSER:-1000}
        WWWGROUP: ${SC_DOCKER_WWWGROUP:-1000}
        INSTALL_XDEBUG: "false"
    image: scart-app:${SC_DOCKER_PHP_VERSION:-8.3}${SC_DOCKER_INSTANCE:+-}${SC_DOCKER_INSTANCE:-}-prod
    container_name: ${SC_DOCKER_INSTANCE:-scart}-scheduler-prod
    working_dir: /var/www/html
    command: ["sh", "-c", "while true; do php artisan schedule:run --no-interaction; sleep 60; done"]
    volumes:
      - ./:/var/www/html
      - scart-vendor:/var/www/html/vendor
    environment:
      # Mirror of the "app" service pins above (kept in sync by
      # DockerComposeEnvConsistencyTest). Laravel loads .env through an
      # immutable repository - a real process env var always wins - so a
      # pin on "app" alone leaves this container reading APP_ENV/APP_DEBUG
      # from the host's .env; with the .env.example default (APP_ENV=local)
      # background jobs would run in local/debug while the web tier runs in
      # production, on the same site.
      APP_ENV: production
      APP_DEBUG: "false"
      DB_CONNECTION: ${DB_CONNECTION:-mysql}
      DB_HOST: ${DB_HOST}
      DB_PORT: ${DB_PORT:-3306}
      DB_USERNAME: ${DB_USERNAME}
      DB_PASSWORD: ${DB_PASSWORD}
    depends_on:
      - app
    restart: unless-stopped
    networks:
      - scart

  # Optional dockerized MySQL for prod. Only starts with --profile db-local
  # (or COMPOSE_PROFILES=db-local). Skip entirely to use a remote/managed
  # database - just point DB_HOST at it in .env.
  mysql-local:
    image: mysql:8.4
    container_name: ${SC_DOCKER_INSTANCE:-scart}-mysql-local-prod
    profiles: ["db-local"]
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: ${SC_DOCKER_DB_ROOT_PASSWORD}
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_USER: ${DB_USERNAME}
      MYSQL_PASSWORD: ${DB_PASSWORD}
    volumes:
      - scart-mysql-local-data-prod:/var/lib/mysql
      - ./docker/mysql/my.cnf:/etc/mysql/conf.d/my.cnf:ro
    networks:
      - scart

  # One-off container for building front-end assets. Not started by `up`
  # (profile "tools"); run manually when you need to rebuild assets:
  #   docker compose -f docker-compose.prod.yml run --rm node
  node:
    image: node:22-alpine
    container_name: ${SC_DOCKER_INSTANCE:-scart}-node-prod
    working_dir: /var/www/html
    profiles: ["tools"]
    # npm ci requires an existing package-lock.json; fall back to npm install
    # (which also generates one) when it's missing, e.g. on a fresh checkout.
    command: ["sh", "-c", "if [ -f package-lock.json ]; then npm ci; else npm install; fi && npm run build"]
    volumes:
      - ./:/var/www/html
      - scart-node-modules:/var/www/html/node_modules
    networks:
      - scart

networks:
  scart:
    driver: bridge

volumes:
  # Explicit `name:` pins below decouple volume identity from the compose
  # `name:` project setting above - changing the project name (scart ->
  # scart-prod) does not rename or orphan these, so any already-running prod
  # deployment keeps its existing MySQL data / vendor / node_modules volumes
  # untouched.
  #
  # The ${SC_DOCKER_INSTANCE:-scart} prefix keeps the DEFAULT names byte-for-byte
  # identical to before (SC_DOCKER_INSTANCE unset -> "scart-vendor" etc.), so existing
  # single-instance prod deployments are unaffected; only when you set
  # SC_DOCKER_INSTANCE=<slug> for a second project do the volumes become
  # "<slug>-vendor" / "<slug>-mysql-local-data-prod", giving each instance its
  # OWN MySQL data volume (no cross-instance data mixing - see RISK-OPS-009).
  scart-vendor:
    name: ${SC_DOCKER_INSTANCE:-scart}-vendor
  scart-node-modules:
    name: ${SC_DOCKER_INSTANCE:-scart}-node-modules
  scart-mysql-local-data-prod:
    name: ${SC_DOCKER_INSTANCE:-scart}-mysql-local-data-prod

This file may be out of date. Check the s-cart documentation for current setup steps.

Track your self-hosted stack

Bookmark software to try, rate tools you've used, and keep your collection in one place.

Metadata extracted from README on Oct 10, 2026

Related Software

Saleor logo

Saleor

23.4k
GraphQL-native, API-only commerce platform for scalable composable commerce.
E-Commerce SolutionsPermissive LicenseInventory Management+1
5 Containers
Details
PrestaShop logo

PrestaShop

9.2k
An open source e-commerce web application for building online stores.
E-Commerce SolutionsCopyleft LicenseCMS Platforms+3
3 Containers
Details
EverShop logo

EverShop

10.5k
A modern TypeScript-first eCommerce platform built with GraphQL and React.
E-Commerce SolutionsInventory ManagementSelf Hosting Solutions+1
2 Containers
Details
OpenCart logo

OpenCart

8.2k
An open source ecommerce platform for building and running online stores.
E-Commerce SolutionsInventory ManagementSelf Hosting Solutions+1
Details
Odoo logo

Odoo

55.0k
Odoo is a suite of web-based open source business apps that can be used individually or combined into an ERP.
Resource PlanningCopyleft LicenseCRM Systems+5
Details
Magento Open Source logo

Magento Open Source

12.2k
Magento Open Source is an eCommerce platform for building and managing online stores.
E-Commerce SolutionsCMS PlatformsInventory Management+3
Details
WooCommerce logo

WooCommerce

10.5k
A GitHub monorepo for the plugins, packages, and tools used to develop WooCommerce Core and related extensions.
E-Commerce SolutionsCopyleft LicenseCMS Platforms+2
Details
Open Source POS logo

Open Source POS

4.4k
A web-based point of sale system for managing sales, inventory, customers, and related retail operations.
E-Commerce SolutionsInventory ManagementSelf Hosting Solutions+1
Details
Open Food Network logo

Open Food Network

1.3k
An online marketplace platform for local food that connects farmers, food hubs, and buyers.
Agriculture ManagementCopyleft LicenseE-Commerce Solutions+2
Details
OFBiz logo

OFBiz

1.1k
Apache OFBiz is an enterprise resource planning (ERP) system written in Java with libraries, entities, services, and features for running business operations.
Resource PlanningE-Commerce SolutionsInventory Management+4
Details
Litecart logo

Litecart

363
litecart is an open source shopping cart packaged as a single-file application with an embedded SQLite database, admin dashboard, and site front end.
E-Commerce SolutionsSelf Hosting SolutionsInventory Management+2
Details
myCart logo

myCart

363
myCart is an open source shopping cart with an embedded SQLite database, an admin dashboard, and a storefront site.
E-Commerce SolutionsInventory ManagementSelf Hosting Solutions+1
Details