wineworlds/deployer-recipes

A collection of recipes for deployer

Maintainers

Package info

github.com/wineworlds/deployer-recipes

Type:deployer-recipes

pkg:composer/wineworlds/deployer-recipes

Transparency log

Statistics

Installs: 2 673

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.3.2 2026-07-14 19:37 UTC

This package is auto-updated.

Last update: 2026-08-14 19:48:07 UTC


README

A collection of recipes for Deployer — with a full, production-tested toolkit for Shopware 6: deploy, one-time provisioning, publishing a local instance, moving a shop between servers, and selective data migration (relaunch).

Install

composer require --dev deployer/deployer
composer require --dev wineworlds/deployer-recipes

Import a recipe in your deploy.yaml (see below). Then run tasks with vendor/bin/dep <task> <host>.

Recipes

Recipe Import path What you get
Shopware recipe/shopware.php deploy, sw:shared:init, sw:publish, sw:transfer, migrate:*, fetch
TYPO3 (rsync) recipe/typo3-rsync.php Legacy TYPO3 deploy + fetch/sync/transfer
Shopware (rsync, legacy) recipe/shopware-rsync.php Older git+build+rsync Shopware deploy
generic recipe/fetch.php, recipe/sync.php, recipe/transfer.php Bare DB/file primitives

Shopware

Mental model

There are three places, and it helps to keep them apart:

  LOCAL (control machine)              SERVER (per host)
  ─ runs `vendor/bin/dep`              ─ {{deploy_path}}/releases/…   (each deploy)
  ─ .env.local     → local dev DB      ─ {{deploy_path}}/current       (symlink → newest release)
  ─ .env.<alias>   → target templates  ─ {{deploy_path}}/shared        (persists across releases)
  ─ bin/migrate.tables (whitelist)         └─ shared/.env.local  = the REAL secrets
                                            └─ shared/files, public/media, …  = media

The env files (this is the part people trip over):

File Where Purpose
.env committed, shipped in every release base / dev defaults only — no real secrets
.env.local local only, git-ignored your local dev DB/secrets (used by sw_local_db)
.env.<alias> local only, git-ignored template for a target host → uploaded once as its shared/.env.local
shared/.env.local on the server, in shared/ the host's real secrets, symlinked into every release

The recipe reads real credentials from .env.local (server: the shared one; local: your dev one) — never from the committed .env.

Prerequisites: a shopware/production-style project with shopware/deployment-helper installed (composer require shopware/deployment-helper); the deploy runs vendor/bin/shopware-deployment-helper run on the target.

Configure deploy.yaml

Minimal, annotated — this is all you need for deploy, sw:shared:init, sw:publish and migrate:*:

import:
  - vendor/wineworlds/deployer-recipes/recipe/shopware.php

config:
  # chmod avoids needing ACL/sudo on shared hosting (recommended):
  writable_mode: chmod

  # ONLY needed for `sw:transfer` — the alias of the OLD/source server:
  # sync_from_host: old

hosts:
  prod:
    hostname:    server.example.de
    remote_user: deployer
    deploy_path: /var/www/prod        # releases/, current, shared/ live here
    bin/php:     /usr/bin/php83        # PHP binary on the server (for bin/console)
    keep_releases: 3                  # optional (Deployer default: 10)
    # optional — clears opcache after the symlink:
    # cachetool: /run/php/php83-fpm.sock

after:
  deploy:failed: deploy:unlock

Add more hosts as needed — each host <alias> maps to a local template .env.<alias> (see sw_env_template to change the naming).

Host keys that matter

Key Required Meaning
hostname / remote_user yes SSH target (also honors port: and your ~/.ssh/config)
deploy_path yes base dir on the server (holds releases/, current, shared/)
bin/php recommended PHP CLI on the server used for bin/console
keep_releases no how many releases to keep
cachetool no php-fpm socket/URL → opcache is cleared after each deploy

Local files you must keep (git-ignored)

# .gitignore
.env.local          # your local dev secrets
.env.*              # per-host templates (.env.prod, .env.old, …)  REAL secrets!

Create a host template by copying .env and filling in the real values for that server (DATABASE_URL, APP_URL, APP_SECRET, MAILER_DSN, APP_ENV=prod, …):

cp .env .env.prod   # then edit .env.prod

Commands

deploy — release a new version

vendor/bin/dep deploy prod

Pipeline: deploy:preparedeploy:clear_pathssw:deployment:helper (migrations, plugins, theme, cache via the deployment-helper) → sw:touch_install_locksw:health_checksdeploy:publish.

  • Needs: sw:shared:init must have run once before the first deploy (so shared/.env.local and the shared dirs exist).
  • Headless (no storefront): set sw_health_check: false in config: — the system:check --context=pre_rollout step only makes sense with a storefront.

sw:shared:init — one-time provisioning (run once per host)

vendor/bin/dep sw:shared:init prod

Creates shared/ + all shared dirs, uploads .env.prodshared/.env.local, uploads config files (auth.json, public/.htaccess, public/.user.ini) and your local media, and fixes group permissions. Idempotent — existing env/config on the host is never overwritten.

  • Needs: local .env.prod (the host template). Errors clearly if missing.
  • Sub-tasks if you want the pieces: sw:shared:skeleton (no media) and sw:shared:media:upload.

sw:publish — bring a locally developed instance online

vendor/bin/dep sw:publish prod            # aborts if the target is locked/exists
vendor/bin/dep sw:publish prod --force    # ignore lock + skip confirmations

Does it all in one go: sw:target:guardsw:shared:initsw:db:publish (your complete local DB → the target DB) → deploysw:target:lock.

  • Needs: local .env.prod, local .env.local (your dev DB), and shopware/deployment-helper.
  • Protection: a lock file ({{deploy_path}}/.sw-publish.lock) marks a published instance. A second sw:publish aborts unless --force. If the target already has a current/ without a lock, it asks for confirmation.
  • sw:db:publish prod is also callable on its own (overwrites the target DB).

sw:transfer — move a shop to another server

# in config: sync_from_host: old
cp .env .env.newserver                     # fill in the new server's values
vendor/bin/dep sw:transfer newserver --force

Migrates an existing shop source → target: shared media and the complete DB are copied from sync_from_host to the selected host, then a fresh release is deployed. Media + DB are routed through your local machine, so no direct source→target SSH is required (Deployer already has SSH to both).

  • Needs: config.sync_from_host (source alias), both hosts defined, and a local .env.newserver template for the target.
  • Call it on the TARGET host (dep sw:transfer newserver); the source comes from sync_from_host.
  • Same lock protection and --force as sw:publish.

migrate:* — selective data migration (relaunch)

Copies selected business data (customers, orders, newsletter, number ranges, promotions …) from your locally migrated DB into an existing target shop — without touching the target's catalog/config. This runs local → target host (no sync_from_host).

vendor/bin/dep migrate:backup prod             # 1. rollback point (dumps target DB)
vendor/bin/dep migrate:integrity-check prod    # 2. schema / orphan / row-count report
vendor/bin/dep migrate:tables prod             # 3. push whitelisted tables (atomic)
vendor/bin/dep migrate:postprocess prod        # 4. fix refs + cache:clear + dal:refresh:index

# if needed:
vendor/bin/dep migrate:rollback prod -o backup=var/migrate-backups/<file>.sql.gz
vendor/bin/dep migrate:switch:domain prod -o sc_from=old.de -o sc_to=new.de -o app_url=https://new.de
vendor/bin/dep migrate:maintenance:enable prod   # / :disable
  • Needs: a whitelist file bin/migrate.tables (one table per line, # = comment) and a local DB holding the migrated source data.
  • Configure the specifics in config: (all optional, sensible defaults):
config:
  migrate_tables_file: bin/migrate.tables          # whitelist location
  migrate_backup_dir:  var/migrate-backups         # where backups are stored (local)
  migrate_fallback_shipping_method: ''             # 32-char hex id, for orphaned deliveries
  migrate_shipping_method_map: {}                  # { oldHexId: newHexId } (applied first)

Example bin/migrate.tables:

# Customers
customer
customer_address
# Orders
order
order_line_item
order_delivery
# Number ranges (order/customer counters!)
number_range_state

fetch — pull a remote state to local

vendor/bin/dep fetch:db prod       # dump remote DB → import into local
vendor/bin/dep fetch:files prod    # download shared media → local
vendor/bin/dep fetch prod          # both

Reads the remote credentials from the host's .env.local.

Typical workflows

Goal Commands
First time online (local shop → new server) cp .env .env.prod (edit) → dep sw:publish prod
Routine deploy (code only) dep deploy prod
Server move (old → new) set sync_from_host: old, cp .env .env.new (edit) → dep sw:transfer new
Relaunch (migrate live data into a rebuilt shop) dep migrate:backupmigrate:integrity-checkmigrate:tablesmigrate:postprocess

Settings reference

Setting Default Purpose
sw_env_template .env.<alias> local env template uploaded as shared/.env.local
sw_shared_config_files auth.json, public/.htaccess, public/.user.ini config uploaded once by shared:init
sw_shared_media_dirs files, public/media, public/thumbnail, public/sitemap, public/export media moved by publish/transfer
sw_deploy_lock_file {{deploy_path}}/.sw-publish.lock publish/transfer protection lock
sw_mysqldump_options --single-transaction --quick --no-tablespaces --skip-comments --default-character-set=utf8mb4 dump options for full dumps
sw_health_check true run system:check during deploy (false for headless)
dotenv {{current_path}}/.env.local file Deployer sources before each run() (real secrets). Migrating from an old hoster that keeps creds in .env? override with {{current_path}}/.env
migrate_tables_file bin/migrate.tables whitelist for migrate:tables

TYPO3 / generic

import:
  - vendor/wineworlds/deployer-recipes/recipe/typo3-rsync.php

config:
  sync_from_host: live
  sync_to_host: preview
vendor/bin/dep sync preview        # sync:db + sync:files (host → host)
vendor/bin/dep fetch preview       # fetch:db + fetch:files (host → local)
vendor/bin/dep transfer preview    # sync:db + full deploy_path rsync