Deployments

The deploy pipeline

Every step of a Nautvia deploy in order, what runs where, and why the store stays up while it happens.

A deploy builds a new release beside the running one and switches to it with a single symlink move. Magento never enters maintenance mode, and a failure at any step leaves the live store exactly as it was.

Before anything starts

A deploy is refused if:

  • another deploy is already running for this environment;
  • a database, a cache or a search cluster is missing;
  • the team has no active subscription.

Provisioning

On the first deploy — and after a teardown — the infrastructure is built before any code is touched:

  1. A team SSH keypair and a private network are created if this is the team's first environment.
  2. Each server is created: application, MySQL, Valkey, OpenSearch.
  3. Each is polled until its installation finishes. This is the slow part; allow up to twenty minutes.
  4. The media volume is created and mounted.
  5. The logical database and its user are created.

On later deploys all of this is already done and skipped.

Build

Runs on the application server, as the deploy user, in a fresh release directory:

curl -L "$TARBALL_URL" | tar -xz --strip-components=1

COMPOSER_MEMORY_LIMIT=-1 composer install \
    --no-dev --no-interaction --no-progress --optimize-autoloader

COMPOSER_AUTH comes from your MAGENTO_COMPOSER_AUTH variable, if you set one.

There is no separate build machine. Build and release both run on the server that serves your store — which is why a heavy composer install can make the live site feel slower for a minute, and why sizing the application server matters.

Release

  1. Link shared pathsapp/etc/env.php, pub/media and var are symlinked out of the release into shared storage, so media and logs survive the switch.
  2. Install or upgrade. On a brand-new store, setup:install runs with your database, cache and OpenSearch details. On every deploy after that, setup:upgrade --keep-generated.
  3. setup:di:compile.
  4. setup:static-content:deploy -f en_US.
  5. Your deploy commands, in order. A failure here aborts the deploy before the switch — see Deploy hooks and commands.
  6. The switch. ln -sfn the new release to current-new, then mv -T it over current. A rename on the same filesystem is atomic: a request either sees the old release or the new one, never a half-updated tree.
  7. Reload PHP-FPM, then bin/magento cache:flush.
  8. Rewrite the crontab so bin/magento cron:run runs every minute against the new release.
  9. Prune old releases, keeping the newest three.
  10. Warm up with a request to the store.

Magento commands run with a 2 GB PHP memory limit.

Only three releases are kept

The prune in step 9 is what bounds disk use, and it also bounds how far back you can roll: a release older than the last three is gone from the server. See Rollbacks.

First install: what is set for you

The very first deploy of a store runs setup:install, which drops every table in the database and flushes the cache first. On an empty database that is housekeeping. It is also why importing your data comes after the first successful deploy, never before — see Migrating a store.

Some values are fixed at install and are not configurable through the dashboard:

Setting Value
Language en_US
Currency EUR
Timezone Europe/Kyiv
URL rewrites on
Search engine OpenSearch
Admin path randomised, not /admin

Change any of these afterwards in the Magento admin or with bin/magento config:set. Static content is only ever compiled for en_US; if your store needs another locale, add setup:static-content:deploy -f en_US de_DE as a deploy command.

Magento_TwoFactorAuth is disabled during the install, because stock Magento 2.4 cannot complete a login without working outbound mail. Configure mail and re-enable it.

If a deploy fails

The store keeps serving the previous release. The failure reason appears at the top of the deployment page and the log is kept. Everyone on the team gets an email and an in-app notification — see Notifications.

Cancelling

Cancel stops the pipeline advancing and marks the deploy cancelled. The script already running on the server is not killed — it finishes harmlessly against a release directory that never becomes current.