s-cart
★ 12A 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 yetNew this week
Read recap →Weekly Recap — Oct 2, 2026 – Oct 9, 2026Oct 9, 2026
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.
Tags
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
23.4k
GraphQL-native, API-only commerce platform for scalable composable commerce.
E-Commerce SolutionsPermissive LicenseInventory Management+1
5 Containers
PrestaShop
9.2k
An open source e-commerce web application for building online stores.
E-Commerce SolutionsCopyleft LicenseCMS Platforms+3
3 Containers
EverShop
10.5k
A modern TypeScript-first eCommerce platform built with GraphQL and React.
E-Commerce SolutionsInventory ManagementSelf Hosting Solutions+1
2 Containers
OpenCart
8.2k
An open source ecommerce platform for building and running online stores.
E-Commerce SolutionsInventory ManagementSelf Hosting Solutions+1
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
Magento Open Source
12.2k
Magento Open Source is an eCommerce platform for building and managing online stores.
E-Commerce SolutionsCMS PlatformsInventory Management+3
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
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
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
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
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
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
