Neue Skill: typo3-staging-to-live-cutover
Das Go-live ist eine eigene Aufgabe, nicht der letzte Schritt des Staging-Deployments: oeffentlich, schwer umkehrbar, anderes Risiko. Phasen: Cutover-Modell waehlen; aufraeumen, was nicht mit auf live darf (DB-Dumps, Einmal-Skripte, .bak-Configs, Fehlerlogs); umgebungsabhaengige Konfiguration (trustedHostsPattern, displayErrors, site base, DB-Zugang, Mail); Staging-Sperren entfernen (Basic-Auth, noindex, Testkonten); Redirects/Scheduler/Sprachpakete/SSL; Verifikation und Rueckweg. Die Beispiele stammen aus einem realen Staging-Account: ~26 MB Dumps und Ticket-Sicherungen im Home, eine .bak-Config im Projektbaum, Basic-Auth in public/.htaccess, displayErrors=1 und ein auf die Staging-Domain gepinntes trustedHostsPattern. Die konsoleH-Deploy-Skill (jetzt 1.1) verweist am Ende darauf und benennt die beiden Artefakte, die sie selbst erzeugt und die nicht mitwandern duerfen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@ name: typo3-konsoleh-staging-deploy
|
||||
description: "Deployt ein lokal mit DDEV gebautes TYPO3-Projekt (v13/v14, Composer) als Staging-Seite auf einen Hetzner-Managed-Webhosting-Server (konsoleH). Der Composer-Build läuft AUF dem Server (kein vorgefertigtes vendor/ wird hochgeladen). Verwenden, wenn eine TYPO3-Staging- oder Vorschau-Umgebung auf Hetzner Managed Hosting (konsoleH), einem *.your-server.de-Host oder dedi*-Server eingerichtet werden soll, oder wenn eine lokale DDEV-TYPO3-Seite per SSH auf ein Managed-/Shared-Hosting übertragen werden soll. Umfasst: SSH-Inventar, per-User-composer.phar, Deploy-Keys für private Git-Repos (gitea) + Registry-Auth, Datenbank + Dokumentstamm über konsoleH, rsync von Quellcode + fileadmin, DB-Import, Staging-additional.php, .htaccess, Sprachpakete, HTTP-Basic-Auth und Let's Encrypt. NICHT für Root-VPS-/Docker-/DDEV-auf-dem-Server-Deployments."
|
||||
metadata:
|
||||
author: Wappler
|
||||
version: "1.0"
|
||||
version: "1.1"
|
||||
---
|
||||
|
||||
# TYPO3 → Hetzner konsoleH staging deployment
|
||||
@@ -224,3 +224,11 @@ On subsequent rsyncs, **exclude** the files that hold staging-specific state:
|
||||
9. `.htpasswd` must be `chmod 644` (Apache auth uid ≠ PHP uid) and live outside the web root.
|
||||
10. SSL = admin sets Let's Encrypt in the konsoleH SSL-Manager.
|
||||
11. Always run composer/typo3 with `php -d memory_limit=-1` (128M host limit).
|
||||
|
||||
## Danach live gehen
|
||||
Diese Skill baut und pflegt eine **Staging**-Umgebung. Sie in Produktion zu überführen ist eine eigene
|
||||
Aufgabe mit anderem Risikoprofil — siehe die Skill **`typo3-staging-to-live-cutover`**. Zwei Dinge, die
|
||||
diese Skill bewusst erzeugt und die **nicht** auf live gehören: der **Basic-Auth-Block samt
|
||||
`.htpasswd`** und die **DB-Dumps / Ticket-Sicherungen**, die sich im Home des Accounts ansammeln.
|
||||
Dumps von Anfang an außerhalb des Docroots ablegen, mit Datum benennen und löschen, sobald die
|
||||
Änderung abgenommen ist, die sie absichern.
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
---
|
||||
name: typo3-staging-to-live-cutover
|
||||
description: "Promote an approved TYPO3 staging site to production — the go-live step AFTER a staging environment exists. Use when a TYPO3 site is about to go live, when a staging/preview site must become the public site, when asked to clean up a staging server before launch, or when preparing a launch checklist for a shared/managed host. Covers: what must NOT travel to live (DB dumps, one-off SQL/PHP scripts, .bak files, error logs), the environment-specific config that must change (trustedHostsPattern, displayErrors, site base, DB credentials, mail), removing basic-auth/staging locks, indexing and redirects, scheduler and SSL, plus verification and rollback. Assumes the build already runs on staging (see the staging-deploy skill for that)."
|
||||
metadata:
|
||||
author: Wappler
|
||||
version: "1.0"
|
||||
---
|
||||
|
||||
# TYPO3 — staging → live cutover
|
||||
|
||||
Turning an approved staging site into the public site. Different risk profile from building staging:
|
||||
**public, hard to reverse, and observed by the customer**. Work through the phases in order; do not
|
||||
start Phase 4 before Phase 1–3 are verified.
|
||||
|
||||
Placeholders: `<SSH_USER>@<HOST>`, `<PROJECT_DIR>` (e.g. `~/public_html/<project>`), `<SITE_ID>`,
|
||||
`<STAGING_DOMAIN>`, `<LIVE_DOMAIN>`, `<LIVE_DB>`.
|
||||
|
||||
---
|
||||
|
||||
## Phase 0 — Decide the cutover model FIRST
|
||||
It determines everything else. Three common shapes:
|
||||
- **Domain switch in place** — the staging webspace becomes the live one (point `<LIVE_DOMAIN>`'s
|
||||
document root at the same project). Cheapest; but staging then no longer exists as a separate
|
||||
environment, so agree with the user where future work is previewed.
|
||||
- **Copy into the live webspace** — rsync the project + DB into a separate account/space. Keeps
|
||||
staging alive. Everything in Phase 1 matters twice: you must not copy the junk over.
|
||||
- **Rebuild from the repo** — `composer install` on the live space, DB imported from staging. Cleanest;
|
||||
the artefacts in Phase 1 never exist there. **Prefer this when the host allows it.**
|
||||
|
||||
Also settle **who owns the DNS/TTL change** and **when** (lower the TTL a day ahead), and confirm the
|
||||
content freeze: the customer's editors are usually working in staging until the last minute.
|
||||
|
||||
---
|
||||
|
||||
## Phase 1 — What must NOT travel to live
|
||||
Staging accumulates working material. Inventory it, then decide per item: delete, or keep outside
|
||||
the project tree. **Never just leave it.**
|
||||
|
||||
```bash
|
||||
# Dumps, backups, one-off scripts in the account home
|
||||
ls -lah ~/ | grep -viE '^d|\.bashrc|\.profile|\.ssh'
|
||||
# Leftovers inside the project (exclude vendor)
|
||||
find <PROJECT_DIR> -path '*/vendor' -prune -o \
|
||||
\( -name '*.bak' -o -name '*.bak-*' -o -name '*.orig' -o -name '*.sql' \
|
||||
-o -name '*.sql.gz' -o -name '*.zip' -o -name '*.tar.gz' \) -print
|
||||
# Anything executable in the docroot besides the entry point
|
||||
find <PROJECT_DIR>/public -maxdepth 1 -name '*.php'
|
||||
```
|
||||
|
||||
Typical finds, and why each matters:
|
||||
- **Database dumps** (`*-db*.sql.gz`, `backup-*.sql`) — often tens of MB and a **full copy of the
|
||||
production dataset**, including `be_users` hashes and any personal data in content records.
|
||||
Usually they sit in the account home, i.e. *outside* the docroot and not web-reachable — verify
|
||||
that rather than assume it (`ls -la ~/public_html` and compare with the domain's document root).
|
||||
Even when unreachable they must not be copied to live and should not linger indefinitely.
|
||||
- **Per-ticket safety backups** (`backup-<ticket>-<date>.sql`) and permission exports
|
||||
(`be_group*.bak`) — the same, in miniature. Delete once the change they protected is accepted.
|
||||
- **One-off migration/build scripts** (`build-*.php`, `*-debug.php`, `fix-*.php`) — the real hazard:
|
||||
a script written to run once, left in a web-reachable path, is a remote code path nobody reviews.
|
||||
**Nothing but the framework's entry point belongs in the docroot.**
|
||||
- **`*.bak` config files** (e.g. `config/sites/<SITE_ID>/config.yaml.bak-<ticket>`) — these DO sit
|
||||
inside the project and will be rsynced to live. Remove them; they are noise at best and a
|
||||
stale-config trap at worst.
|
||||
- **Empty/failed artefacts** (`dumperr.log`, `importerr.log`, 20-byte `.sql.gz` files from a dump
|
||||
that failed) — evidence a step went wrong; read them once, then delete.
|
||||
- **The staging `.htpasswd`** — see Phase 3.
|
||||
|
||||
Before deleting a dump, confirm its content is either reproducible or genuinely obsolete. If the user
|
||||
wants an archive, move it **off the server** (they download it), don't relocate it within the account.
|
||||
|
||||
---
|
||||
|
||||
## Phase 2 — Environment-specific configuration
|
||||
Every one of these is pinned to staging and silently wrong on live.
|
||||
|
||||
- **`config/system/additional.php`** (or the live equivalent):
|
||||
- `SYS/trustedHostsPattern` — pinned to `<STAGING_DOMAIN>`; a wrong value gives a hard failure on
|
||||
the live host. Set it to `<LIVE_DOMAIN>` (escape the dots), or `.*` only if the host terminates
|
||||
the Host header itself.
|
||||
- `SYS/displayErrors` — staging typically runs `1`. **Must be `0` (or removed) on live**, otherwise
|
||||
stack traces with paths and query fragments are public.
|
||||
- `SYS/devIPmask`, `exceptionalErrors`, `systemLogLevel`, debug/preview flags — reset to production.
|
||||
- **Application context** — `Production` on live (`TYPO3_CONTEXT`, often via `.htaccess`/vhost).
|
||||
- **DB credentials** — the live database is a different one. Keep the pattern of reading the password
|
||||
from a `chmod 600` file outside the docroot rather than inlining it; **generate fresh credentials
|
||||
for live, do not reuse staging's.**
|
||||
- **Site configuration** `config/sites/<SITE_ID>/config.yaml` — `base` is usually `/` or the staging
|
||||
host. Set the live base (or base variants keyed on the application context, which lets one config
|
||||
serve both). Check `baseVariants` blocks left over from earlier environments.
|
||||
- **Mail** — sender address/domain, SMTP credentials, and any staging-wide redirect of outgoing mail
|
||||
(a "catch all recipients" setting is common on staging and **must** be off on live).
|
||||
- **File permissions** — `settings.php` holds the `encryptionKey` and is often world-readable (644) on
|
||||
shared hosting. Tighten what the host allows, and rotate the encryption key if staging was widely
|
||||
shared.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3 — Remove the staging locks
|
||||
- **HTTP basic-auth**: staging is usually protected in `public/.htaccess`
|
||||
(`AuthType Basic` / `AuthUserFile …/.htpasswd` / `Require valid-user`). Remove that block for live —
|
||||
and delete the `.htpasswd` file. Verify with `curl -sk -o /dev/null -w '%{http_code}' <LIVE_URL>`:
|
||||
**200, not 401**.
|
||||
- **Indexing**: whatever was decided for staging is usually the opposite for live. Check `robots.txt`,
|
||||
any `X-Robots-Tag` header, and the site's SEO settings for a global `noindex`.
|
||||
- **Test accounts**: remove backend users created for the launch, reset the install-tool password, and
|
||||
confirm no `_cli_`/demo account carries an interactive password.
|
||||
- **Placeholder files** left in the webspace root from before the project (`index.htm`, "coming soon"
|
||||
pages) — they can shadow the real entry point depending on the host's `DirectoryIndex`.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4 — Content, SEO, operations
|
||||
- **Redirects** — a relaunch usually changes slugs. Export the old URL set, map it to the new one, and
|
||||
load it into `sys_redirect` **before** DNS switches. Check the old site's top URLs from its access
|
||||
logs or analytics, not from the sitemap alone.
|
||||
- **Scheduler** — set up the cron entry on the live host (`vendor/bin/typo3 scheduler:run`, typically
|
||||
every minute); staging often has none.
|
||||
- **Language packs** — `vendor/bin/typo3 language:update` on the live host; in Composer mode they are
|
||||
not shipped, and labels silently fall back to English.
|
||||
- **SSL** — issue/activate the certificate for `<LIVE_DOMAIN>` (on managed panels this is a UI step and
|
||||
may need a retry before it takes). Verify the chain from outside, not just `curl -k`.
|
||||
- **Caches and index** — `cache:flush`, clear compiled CSS/JS artefacts, `referenceindex:update`.
|
||||
- **Search/indexed search** — re-index after the content freeze lifts.
|
||||
|
||||
---
|
||||
|
||||
## Phase 5 — Verify, then keep a way back
|
||||
- **Rollback plan before the switch**: a final DB dump plus the previous DNS values, written down.
|
||||
Store the dump outside the docroot and **delete it once the launch is accepted** — otherwise it
|
||||
becomes exactly the Phase 1 problem on the live server.
|
||||
- **Smoke test the live host** over the real domain (loop the slug list, assert 200), including the
|
||||
backend, a form submission, and one page per template type.
|
||||
- **Confirm from outside your network** — DNS, SSL and caching behave differently from a machine that
|
||||
has been talking to the staging IP all week.
|
||||
- **Re-run the Phase 1 inventory on the live server** after the cutover. If you copied rather than
|
||||
rebuilt, the junk came along.
|
||||
|
||||
---
|
||||
|
||||
## Recurring traps
|
||||
- **Remote DB writes and schema commands are frequently blocked by tooling guards.** Expect it: stage
|
||||
a reviewed `.sql` file on the server, keep a row-level backup beside it, and hand the user the
|
||||
one-line command to execute rather than fighting the guard.
|
||||
- **Editors keep working during the cutover.** A dump taken at 13:00 does not contain the 13:40 edit.
|
||||
Agree a content freeze, or take the final dump immediately before the switch and re-verify counts.
|
||||
- **`composer install` ships the locked reference.** If the sitepackage is tracked from a branch, the
|
||||
lock may point at an older commit — `composer update <TEMPLATE_PACKAGE>` explicitly, else live runs
|
||||
a template older than staging's.
|
||||
- **Do not promote by copying the staging DB onto an existing live DB** without checking which side is
|
||||
the content master. Once real editors touch the live site, the direction reverses permanently.
|
||||
Reference in New Issue
Block a user