A production-ready template for running Shopware 6 on Upsun (powered by Platform.sh), with a fully Dockerized local development environment and a suite of DevOps automation via make.
| Layer | Technology |
|---|---|
| PHP runtime | Dockware shopware:6.7.3.0 (PHP 8.3) |
| Database | MariaDB 10.11 |
| Search | OpenSearch 2 |
| Cache / Sessions | Redis 7 |
| PaaS | Upsun / Platform.sh |
| Automation | GNU Make |
.
├── .platform/ # Upsun service & route definitions
│ ├── routes.yaml
│ └── services.yaml
├── .platform.app.yaml # Upsun application definition (hooks, mounts, crons, worker)
├── devops/
│ └── platformsh/
│ ├── build-hook.sh # Runs during Upsun build phase
│ ├── deploy-hook.sh # Runs during Upsun deploy phase
│ ├── platformsh-setenv.sh # Branch-specific env var helper
│ └── AuthHandler.php # HTTP Basic Auth guard (optional staging protection)
├── docker/
│ └── shop/
│ ├── boot_start_dev.sh / boot_start_prod.sh # Pre-entrypoint container scripts
│ ├── boot_end_dev.sh / boot_end_prod.sh # Post-entrypoint container scripts
│ ├── php_dev.ini # PHP settings for development
│ └── php_prod.ini # PHP settings for production
├── docker-compose-dev.yml # Local dev environment
├── docker-compose-prod.yml # Local prod-like environment (Redis + OpenSearch included)
├── Makefile # Developer automation
├── src/ # Shopware project root (place your SW installation here)
│ └── files/
│ └── theme-config/ # Theme config tracked in git; deployed to Upsun mount
└── vendor-patch/ # Files here are rsync'd over vendor on boot/build
- Docker & Docker Compose
- GNU Make
- (For Upsun operations) Platform.sh CLI (
platform) - (For Upsun operations)
jq
Place your Shopware installation inside src/. The directory is volume-mounted into the container at /var/www/html.
If you're starting fresh, create the Shopware project with Composer:
composer create-project shopware/production srcOpen docker-compose-dev.yml and update at minimum:
- APP_URL=http://procoders.local # or whatever local hostname you use
- DOMAIN_URL=http://procoders.local
- APP_SECRET=REPLACE_WITH_GENERATED_SECRET # generate with: bin/console system:generate-app-secret
- APP_NAME=procoders
- SHOPWARE_CACHE_ID=procodersAdd 127.0.0.1 procoders.local to your /etc/hosts (or use localhost).
make docker-start-devOn first boot the container installs Composer and npm dependencies automatically (only if vendor/ is absent). Subsequent starts are much faster.
- Storefront: http://procoders.local
- Admin: http://procoders.local/admin
- Adminer (DB UI): http://localhost:8989
make docker-start-prodThis profile enables OPcache, HTTP cache, Redis, and OpenSearch — useful for testing production behaviour locally. Note that PHP code changes require an OPcache reset.
Run make help to see all available targets with descriptions.
| Target | Description |
|---|---|
make docker-start-dev |
Start dev containers |
make docker-start-prod |
Start prod-like containers |
make stop |
Stop all containers |
make docker-purge |
Remove all Docker images and volumes |
| Target | Description |
|---|---|
make build-js |
Run bin/build-js.sh inside the container |
make build-storefront |
Run bin/build-storefront.sh |
make build-administration |
Run bin/build-administration.sh |
make local-sw-resources-rebuild |
Clear cache and fully rebuild assets locally |
make remote-sw-resources-rebuild BRANCH=<env> |
Rebuild assets on a remote Upsun environment |
| Target | Description |
|---|---|
make backup-db-from-remote BRANCH=main |
Download a DB dump from Upsun |
make backup-db-from-local |
Dump local DB |
make import-to-local-db LOCAL_SQL_BACKUP_FILE=<path> |
Import a dump to local DB |
make import-to-remote-db BRANCH=<env> REMOTE_SQL_BACKUP_FILE=<path> |
Import a dump to remote |
| Target | Description |
|---|---|
make backup-media-from-remote BRANCH=<env> |
Download media from Upsun |
make backup-media-from-local |
Copy local media to backup dir |
make apply-media-from-local-to-remote BRANCH=<env> |
Push local media to Upsun (destructive) |
| Target | Description |
|---|---|
make main-to-stage-sync |
Copy production DB + media to stage, preserving stage-only data |
| Target | Description |
|---|---|
make replace-in-local-db TABLE_NAME=… COLUMN_NAME=… SEARCH_FOR=… REPLACE_WITH=… |
String replace in a DB column (dry-run by default) |
make activate-category-with-assigned-products CATEGORY_ID=<uuid> |
Activate a category + its products (dry-run by default) |
make remove-client-team-email-recipients DRY_RUN=false |
Replace client emails with blackhole address |
Branch-specific environment variables are stored as a JSON Platform variable named ENV_VARS_<UPPERCASE_BRANCH>.
Example: create a Platform.sh variable named ENV_VARS_MAIN with value:
{
"SHOPWARE_URL": "https://shop.example.com",
"APP_ENV": "prod",
"APP_NAME": "procoders",
"APP_SECRET": "<your-secret>",
"APP_DEBUG": "0",
"LOCK_DSN": "flock",
"BASIC_AUTH": "0"
}Do the same for ENV_VARS_STAGE (staging) and any other branches. DATABASE_URL is generated automatically from PLATFORM_RELATIONSHIPS — do not include it manually.
Runs in a read-only filesystem (no database access):
- Creates
symlinks_source_dirfor runtime-editable files - Sets up symlinked
.bash_profileand.env - Reads branch-specific env vars from
PLATFORM_VARIABLES - Installs NVM + Node.js
- Runs
composer install --no-dev - Symlinks
package-lock.jsonfiles so they persist across builds - Optionally injects HTTP Basic Auth into
public/index.php - Backs up theme config from git for use in the deploy hook
- Installs npm dependencies (storefront + admin)
- Copies mount-bound directories to a temp location for restoration during deploy
- Applies
vendor-patch/overrides via rsync
Runs with a live database and writable mounts:
- Restores build artifacts to their mounts
- Loads NVM, exports env vars from
.env.local.php - Runs
bundle:dump,theme:dump,build-js.sh,assets:install,theme:compile - Initialises Shopware on first deploy (
system:install) - Runs database migrations
- Installs/updates all plugins
- Clears caches and reloads php-fpm OPcache
The template ships with two MariaDB instances:
| Service | Branch | Disk |
|---|---|---|
maindb |
main (production) |
1536 MB |
stagedb |
stage |
512 MB |
The relationship name follows the branch: maindatabase on main, stagedatabase on stage. The Makefile uses -r "$${BRANCH}database" automatically.
Set BASIC_AUTH=1 (and BASIC_AUTH_USER / BASIC_AUTH_PASSWORD) in your branch's ENV_VARS_* variable to protect the entire storefront with HTTP Basic Auth. The /api/ and /.well-known/ paths are automatically whitelisted.
Place any files that need to override content inside vendor/ into the vendor-patch/ directory, mirroring the path structure relative to the Shopware root. They are applied via rsync at the end of both the local boot script and the Upsun build hook.
Example: to override vendor/shopware/administration/Resources/views/administration/index.html.twig, place your version at:
vendor-patch/vendor/shopware/administration/Resources/views/administration/index.html.twig
Remove this mechanism once the upstream limitation is resolved.
- Replace
procoderswith your project name throughoutdocker-compose-*.ymlandMakefile - Set
APP_URL/DOMAIN_URLto your actual local hostname - Generate
APP_SECRETwithbin/console system:generate-app-secret - Change
OPENSEARCH_INITIAL_ADMIN_PASSWORDindocker-compose-prod.yml - Change
BASIC_AUTH_PASSWORDindocker-compose-*.yml - Set
CLIENT_TEAM_EMAILS,DEV_TEAM_EMAILS,BLACKHOLE_EMAILinMakefile - Update
dump-env-unique-config-from-local-db--whereclause with your plugin config key prefixes - Add project-specific cron jobs in
.platform.app.yaml - After first Upsun deploy, set
THEME_IDin the docker-compose files
To upgrade Shopware, update the image tag in both docker-compose files:
image: dockware/shopware:6.x.x.xAnd update the composer.json in src/ accordingly.