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:
- A team SSH keypair and a private network are created if this is the team's first environment.
- Each server is created: application, MySQL, Valkey, OpenSearch.
- Each is polled until its installation finishes. This is the slow part; allow up to twenty minutes.
- The media volume is created and mounted.
- 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 installcan make the live site feel slower for a minute, and why sizing the application server matters.
Release
- Link shared paths —
app/etc/env.php,pub/mediaandvarare symlinked out of the release into shared storage, so media and logs survive the switch. - Install or upgrade. On a brand-new store,
setup:installruns with your database, cache and OpenSearch details. On every deploy after that,setup:upgrade --keep-generated. setup:di:compile.setup:static-content:deploy -f en_US.- Your deploy commands, in order. A failure here aborts the deploy before the switch — see Deploy hooks and commands.
- The switch.
ln -sfnthe new release tocurrent-new, thenmv -Tit overcurrent. A rename on the same filesystem is atomic: a request either sees the old release or the new one, never a half-updated tree. - Reload PHP-FPM, then
bin/magento cache:flush. - Rewrite the crontab so
bin/magento cron:runruns every minute against the new release. - Prune old releases, keeping the newest three.
- 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.